File Coverage

blib/lib/perl5i/2/Meta/Instance.pm
Criterion Covered Total %
statement 120 124 96.7
branch 27 32 84.3
condition 9 9 100.0
subroutine 19 19 100.0
pod 0 12 0.0
total 175 196 89.2


line stmt bran cond sub pod time code
1             package perl5i::2::Meta::Instance;
2              
3             # Methods here are for $thing->mo->method.
4              
5 101     101   1915 use 5.010_000;
  101         359  
  101         3878  
6 101     101   527 use strict;
  101         418  
  101         3485  
7 101     101   421 use warnings;
  101         208  
  101         3669  
8 101     101   441 no if $] >= 5.018000, warnings => 'experimental::smartmatch';
  101         310  
  101         845  
9              
10             # Don't import anything that might be misinterpreted as a method
11             require Scalar::Util;
12             require overload;
13             require Carp::Fix::1_25;
14              
15 101     101   8575 use perl5i::2::autobox;
  101         302  
  101         807  
16              
17 101     101   52314 use parent qw(perl5i::2::Meta);
  101         250  
  101         819  
18              
19             sub id {
20 40     40 0 1325 require Object::ID;
21              
22             # Hash::FieldHash cannot handle non-references
23 40 100       67 return Object::ID::object_id(ref ${${$_[0]}} ? ${${$_[0]}} : ${$_[0]});
  40         33  
  40         92  
  30         26  
  30         76  
  10         23  
24             }
25              
26             sub class {
27 29     29 0 25 return ref ${${$_[0]}};
  29         20  
  29         73  
28             }
29              
30             sub reftype {
31 6     6 0 7 return Scalar::Util::reftype(${${$_[0]}});
  6         3  
  6         39  
32             }
33              
34              
35             # Only instances can be tainted
36              
37             # Returns the code which will run when the object is used as a string
38             my $has_string_overload = sub {
39             return overload::Method(${${$_[0]}}, q[""]) || overload::Method(${${$_[0]}}, q[0+])
40             };
41              
42             sub is_tainted {
43 27     27 0 100 my $code;
44              
45 27         673 require Taint::Util;
46              
47 27 100       527 if( !ref ${${$_[0]}} ) {
  27 100       22  
  27 100       80  
  18         54  
48             # Its a plain scalar
49 9         9 return Taint::Util::tainted(${${$_[0]}});
  9         9  
  9         47  
50             }
51 18         24 elsif( ref ${${$_[0]}} eq 'SCALAR' ) {
52             # Unblessed scalar
53 3         3 return Taint::Util::tainted(${${$_[0]}});
  3         3  
  3         17  
54             }
55             elsif( $code = $_[0]->$has_string_overload ) {
56 6         182 return Taint::Util::tainted( $code->(${${$_[0]}}) );
  6         5  
  6         15  
57             }
58             else {
59 9         188 return 0;
60             }
61              
62 0         0 die "Never should be reached";
63             }
64              
65              
66             sub taint {
67 9     9 0 41 require Taint::Util;
68              
69 9 100       11 if( !ref ${${$_[0]}} ) {
  9 100       9  
  9         31  
70             # Its a plain scalar
71 3         3 return Taint::Util::taint(${${$_[0]}});
  3         4  
  3         9  
72             }
73             elsif( $_[0]->$has_string_overload ) {
74 2 100       73 Carp::Fix::1_25::croak("Untainted overloaded objects cannot normally be made tainted") if
75             !$_[0]->is_tainted;
76 1         36 return 1;
77             }
78             else {
79 4         635 Carp::Fix::1_25::croak("Only scalars can normally be made tainted");
80             }
81              
82 0         0 Carp::Fix::1_25::confess("Should not be reached");
83             }
84              
85              
86             sub untaint {
87 9     9 0 42 require Taint::Util;
88              
89 9 100 100     10 if( !ref ${${$_[0]}} ) {
  9 100       9  
  9         35  
90             # Its a plain scalar
91 3         6 return Taint::Util::untaint(${${$_[0]}});
  3         4  
  3         10  
92             }
93             elsif( $_[0]->$has_string_overload && $_[0]->is_tainted ) {
94 1         158 Carp::Fix::1_25::croak("Tainted overloaded objects cannot normally be untainted");
95             }
96             else {
97 5         118 return 1;
98             }
99              
100 0         0 Carp::Fix::1_25::confess("Should never be reached");
101             }
102              
103              
104             sub checksum {
105 33     33 0 63 my( $thing, %args ) = @_;
106              
107 33         36 state $algorithms = [qw(sha1 md5)];
108 33   100     101 $args{algorithm} //= 'sha1';
109 33 100       107 $args{algorithm} ~~ $algorithms or
110 1         20 Carp::Fix::1_25::croak("algorithm must be @{[ $algorithms->join(' or ' ) ]}");
111              
112 32         32 state $algorithm2module = { sha1 => "Digest::SHA", md5 => "Digest::MD5" };
113              
114 32         25 state $format = [qw(hex base64 binary)];
115 32   100     69 $args{format} //= 'hex';
116 32 100       57 $args{format} ~~ $format or
117 1         6 Carp::Fix::1_25::croak("format must be @{[ $format->join(' or ') ]}");
118              
119 31         32 state $prefix = { hex => 'hex', base64 => 'b64', binary => undef };
120              
121 31         39 my $module = $algorithm2module->{ $args{algorithm} };
122 31 100       73 my $digest = defined $prefix->{ $args{format} } ? $prefix->{ $args{format} } . 'digest' : 'digest';
123              
124 31         141 $module->require;
125 31         2771 my $digestor = $module->new;
126              
127 31         937 require Data::Dumper;
128              
129 31         5540 my $d = Data::Dumper->new( [ ${$thing} ] );
  31         119  
130 31         596 $d->Deparse(1)->Terse(1)->Sortkeys(1)->Indent(0);
131              
132 31         433 $digestor->add( $d->Dump );
133 31         4564 return $digestor->$digest;
134             }
135              
136              
137             sub is_equal {
138 43     43 0 51 my ($self, $other) = @_;
139 43         566 require perl5i::2::equal;
140              
141 43         102 return perl5i::2::equal::are_equal($$$self, $other);
142             }
143              
144             *perl = \&as_perl;
145             sub as_perl {
146 33     33 0 5153 require Data::Dumper;
147              
148 33         43310 state $options = [qw(Terse Sortkeys Deparse)];
149              
150 33         51 my $self = shift;
151 33         216 my $dumper = Data::Dumper->new([$$$self]);
152 33         760 for my $option (@$options) {
153 99         452 $dumper->$option(1);
154             }
155              
156 33         201 $dumper->Indent(1);
157              
158 33         265 return $dumper->Dump;
159             }
160              
161              
162             sub dump {
163 8     8 0 14 my $self = shift;
164 8         26 my %args = @_;
165              
166 8   100     38 my $format = $args{format} // "perl";
167 8         24 state $dumpers = {
168             json => "as_json",
169             yaml => "as_yaml",
170             perl => "as_perl",
171             };
172              
173 8         17 my $dumper = $dumpers->{$format};
174 8 50       22 Carp::Fix::1_25::croak("Unknown format '$format' for dump()") unless $dumper;
175              
176 8         36 return $self->$dumper(%args);
177             }
178              
179             sub as_json {
180 4     4 0 25 require JSON;
181 4         117 my $json = JSON->new
182             ->utf8
183             ->pretty
184             ->allow_unknown
185             ->allow_blessed
186             ->convert_blessed;
187              
188             # JSON doesn't seem to have an easy way to say
189             # "just dump objects as references please". This is their
190             # recommended way to do it (yarf).
191             local *UNIVERSAL::TO_JSON = sub {
192 1     1   8 require B;
193 1         10 my $b_obj = B::svref_2object( $_[0] );
194 1         103 return $b_obj->isa('B::HV') ? { %{ $_[0] } }
  0         0  
195 1 0       25 : $b_obj->isa('B::AV') ? [ @{ $_[0] } ]
    50          
196             : undef
197             ;
198 4 50       37 } unless defined &UNIVERSAL::TO_JSON;
199              
200 4         8 return $json->encode(${${$_[0]}});
  4         6  
  4         163  
201             }
202              
203             sub as_yaml {
204 4     4 0 490 require YAML::Any;
205 4         965 return YAML::Any::Dump(${${$_[0]}});
  4         7  
  4         28  
206             }
207              
208             1;