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 103     103   2850 use 5.010_000;
  103         581  
  103         6964  
6 103     103   771 use strict;
  103         327  
  103         6797  
7 103     103   882 use warnings;
  103         219  
  103         15881  
8 103     103   1075 no if $] >= 5.018000, warnings => 'experimental::smartmatch';
  103         296  
  103         1089  
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 103     103   13771 use perl5i::2::autobox;
  103         263  
  103         1073  
16              
17 103     103   77891 use parent qw(perl5i::2::Meta);
  103         244  
  103         1189  
18              
19             sub id {
20 40     40 0 2543 require Object::ID;
21              
22             # Hash::FieldHash cannot handle non-references
23 40 100       125 return Object::ID::object_id(ref ${${$_[0]}} ? ${${$_[0]}} : ${$_[0]});
  40         42  
  40         141  
  30         35  
  30         208  
  10         38  
24             }
25              
26             sub class {
27 33     33 0 40 return ref ${${$_[0]}};
  33         46  
  33         131  
28             }
29              
30             sub reftype {
31 6     6 0 10 return Scalar::Util::reftype(${${$_[0]}});
  6         10  
  6         48  
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 28     28 0 147 my $code;
44              
45 28         1194 require Taint::Util;
46              
47 28 100       1179 if( !ref ${${$_[0]}} ) {
  28 100       37  
  28 100       127  
  19         96  
48             # Its a plain scalar
49 9         17 return Taint::Util::tainted(${${$_[0]}});
  9         11  
  9         66  
50             }
51 19         36 elsif( ref ${${$_[0]}} eq 'SCALAR' ) {
52             # Unblessed scalar
53 3         6 return Taint::Util::tainted(${${$_[0]}});
  3         4  
  3         22  
54             }
55             elsif( $code = $_[0]->$has_string_overload ) {
56 7         364 return Taint::Util::tainted( $code->(${${$_[0]}}) );
  7         11  
  7         43  
57             }
58             else {
59 9         291 return 0;
60             }
61              
62 0         0 die "Never should be reached";
63             }
64              
65              
66             sub taint {
67 9     9 0 52 require Taint::Util;
68              
69 9 100       15 if( !ref ${${$_[0]}} ) {
  9 100       11  
  9         47  
70             # Its a plain scalar
71 3         5 return Taint::Util::taint(${${$_[0]}});
  3         6  
  3         14  
72             }
73             elsif( $_[0]->$has_string_overload ) {
74 2 100       98 Carp::Fix::1_25::croak("Untainted overloaded objects cannot normally be made tainted") if
75             !$_[0]->is_tainted;
76 1         53 return 1;
77             }
78             else {
79 4         953 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 55 require Taint::Util;
88              
89 9 100 100     15 if( !ref ${${$_[0]}} ) {
  9 100       15  
  9         51  
90             # Its a plain scalar
91 3         5 return Taint::Util::untaint(${${$_[0]}});
  3         4  
  3         15  
92             }
93             elsif( $_[0]->$has_string_overload && $_[0]->is_tainted ) {
94 1         239 Carp::Fix::1_25::croak("Tainted overloaded objects cannot normally be untainted");
95             }
96             else {
97 5         162 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 97 my( $thing, %args ) = @_;
106              
107 33         41 state $algorithms = [qw(sha1 md5)];
108 33   100     123 $args{algorithm} //= 'sha1';
109 33 100       123 $args{algorithm} ~~ $algorithms or
110 1         26 Carp::Fix::1_25::croak("algorithm must be @{[ $algorithms->join(' or ' ) ]}");
111              
112 32         39 state $algorithm2module = { sha1 => "Digest::SHA", md5 => "Digest::MD5" };
113              
114 32         36 state $format = [qw(hex base64 binary)];
115 32   100     94 $args{format} //= 'hex';
116 32 100       92 $args{format} ~~ $format or
117 1         9 Carp::Fix::1_25::croak("format must be @{[ $format->join(' or ') ]}");
118              
119 31         37 state $prefix = { hex => 'hex', base64 => 'b64', binary => undef };
120              
121 31         57 my $module = $algorithm2module->{ $args{algorithm} };
122 31 100       137 my $digest = defined $prefix->{ $args{format} } ? $prefix->{ $args{format} } . 'digest' : 'digest';
123              
124 31         173 $module->require;
125 31         4965 my $digestor = $module->new;
126              
127 31         1696 require Data::Dumper;
128              
129 31         9919 my $d = Data::Dumper->new( [ ${$thing} ] );
  31         167  
130 31         830 $d->Deparse(1)->Terse(1)->Sortkeys(1)->Indent(0);
131              
132 31         624 $digestor->add( $d->Dump );
133 31         5607 return $digestor->$digest;
134             }
135              
136              
137             sub is_equal {
138 43     43 0 70 my ($self, $other) = @_;
139 43         938 require perl5i::2::equal;
140              
141 43         136 return perl5i::2::equal::are_equal($$$self, $other);
142             }
143              
144             *perl = \&as_perl;
145             sub as_perl {
146 33     33 0 15979 require Data::Dumper;
147              
148 33         160596 state $options = [qw(Terse Sortkeys Deparse)];
149              
150 33         69 my $self = shift;
151 33         306 my $dumper = Data::Dumper->new([$$$self]);
152 33         1028 for my $option (@$options) {
153 99         693 $dumper->$option(1);
154             }
155              
156 33         286 $dumper->Indent(1);
157              
158 33         376 return $dumper->Dump;
159             }
160              
161              
162             sub dump {
163 8     8 0 19 my $self = shift;
164 8         30 my %args = @_;
165              
166 8   100     45 my $format = $args{format} // "perl";
167 8         41 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       30 Carp::Fix::1_25::croak("Unknown format '$format' for dump()") unless $dumper;
175              
176 8         42 return $self->$dumper(%args);
177             }
178              
179             sub as_json {
180 4     4 0 28 require JSON;
181 4         148 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   6 require B;
193 1         10 my $b_obj = B::svref_2object( $_[0] );
194 1         38 return $b_obj->isa('B::HV') ? { %{ $_[0] } }
  0         0  
195 1 0       23 : $b_obj->isa('B::AV') ? [ @{ $_[0] } ]
    50          
196             : undef
197             ;
198 4 50       39 } unless defined &UNIVERSAL::TO_JSON;
199              
200 4         9 return $json->encode(${${$_[0]}});
  4         7  
  4         150  
201             }
202              
203             sub as_yaml {
204 4     4 0 1094 require YAML::Any;
205 4         1298 return YAML::Any::Dump(${${$_[0]}});
  4         12  
  4         32  
206             }
207              
208             1;