| 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; |