File Coverage

blib/lib/Scalar/Util/Reftype.pm
Criterion Covered Total %
statement 106 121 87.6
branch 21 24 87.5
condition 12 15 80.0
subroutine 25 27 92.5
pod n/a
total 164 187 87.7


line stmt bran cond sub pod time code
1             package Scalar::Util::Reftype;
2             $Scalar::Util::Reftype::VERSION = '0.45';
3 1     1   65722 use 5.010;
  1         11  
4 1     1   6 use strict;
  1         1  
  1         21  
5 1     1   4 use warnings;
  1         2  
  1         49  
6              
7 1     1   6 use constant RESET_COUNTER => -1;
  1         2  
  1         94  
8             # being kept for backwards compatibility, 5.10 and later have it
9 1     1   6 use constant HAS_FORMAT_REF => 1;
  1         2  
  1         63  
10 1         57 use constant PRIMITIVES => qw(
11             ARRAY
12             CODE
13             FORMAT
14             GLOB
15             HASH
16             IO
17             LVALUE
18             REF
19             Regexp
20             SCALAR
21 1     1   6 );
  1         2  
22 1         5 use subs qw(
23             blessed
24             class
25             container
26             object
27             reftype
28             type
29 1     1   526 );
  1         23  
30 1         6 use overload bool => '_bool',
31             fallback => 1,
32 1     1   1551 ;
  1         983  
33 1     1   86 use re ();
  1         2  
  1         16  
34 1     1   5 use Scalar::Util ();
  1         2  
  1         17  
35 1     1   5 use base qw( Exporter );
  1         1  
  1         213  
36              
37             our @EXPORT = qw( reftype );
38             our @EXPORT_OK = qw( type HAS_FORMAT_REF );
39              
40             my $OID;
41             BEGIN {
42 1     1   4 $OID = RESET_COUNTER;
43 1         3 foreach my $type ( PRIMITIVES ) {
44 10         194 constant->import( 'TYPE_' . $type, ++$OID );
45 10         235 constant->import( 'TYPE_' . $type . '_OBJECT', ++$OID );
46             }
47             }
48              
49 1     1   7 use constant CONTAINER => ++$OID;
  1         2  
  1         62  
50 1     1   7 use constant BLESSED => ++$OID;
  1         1  
  1         62  
51 1     1   6 use constant OVERRIDE => ++$OID;
  1         2  
  1         49  
52 1     1   7 use constant MAXID => $OID;
  1         2  
  1         78  
53              
54             BEGIN {
55 1     1   7 *class = \*container;
56 1         2 *type = \*reftype;
57 1         3 *object = \*blessed;
58 1         3 my(@types, @obj_idx);
59 1     1   6 no strict 'refs';
  1         2  
  1         355  
60 1         1 foreach my $sym ( keys %{ __PACKAGE__ . q{::} } ) {
  1         9  
61 46 100       122 if ( $sym =~ m{ \A TYPE_ (.+?) \z }xms ) {
62 20         43 push @types, $1;
63 20         49 push @obj_idx, $sym;
64             }
65             }
66              
67 1         4 foreach my $meth ( @types ) {
68 20         122 *{ lc $meth } = sub {
69 30     30   47 my $self = shift;
70 30         88 my $id = 'TYPE_' . $meth;
71 30         153 return $self->[ $self->$id() ];
72             }
73 20         60 }
74              
75             *_dump = sub {
76 0     0   0 my $self = shift;
77 0         0 my %type = map { $self->$_() => $_ } @obj_idx;
  0         0  
78 0         0 my %val = map { $type{$_} => $self->[$_] } 0..$#obj_idx;
  0         0  
79 0         0 my $max = ( sort { $b <=> $a } map { length $_ } keys %val)[0];
  0         0  
  0         0  
80 0         0 my $rm = 'TYPE_';
81 0         0 $max -= length $rm;
82 0         0 for my $name ( sort { lc $a cmp lc $b } keys %val) {
  0         0  
83 0         0 (my $display = $name) =~ s{ \A $rm }{}xms;
84 0 0       0 printf "% ${max}s: %s\n", $display, $val{ $name } ? 'true' : '';
85             }
86 1         539 };
87             }
88              
89             sub reftype {
90 34     34   1095 my @args = @_;
91 34         84 my $o = __PACKAGE__->_new;
92 34         76 return $o->_analyze( @args )
93             }
94              
95             sub _new {
96 34     34   59 my $class = shift;
97 34         75 my $self = [ map { 0 } 0..MAXID ];
  782         1128  
98 34         75 $self->[CONTAINER] = q{};
99 34         58 bless $self, $class;
100 34         58 return $self;
101             }
102              
103             sub _analyze {
104 34     34   51 my $self = shift;
105 34   100     97 my $thing = shift || return $self;
106 31   100     78 my $ref = CORE::ref($thing) || return $self;
107              
108 29         69 foreach my $type ( PRIMITIVES ) {
109 142 100       377 my $id = $ref eq $type ? sprintf( 'TYPE_%s', $type )
    100          
110             : $self->_object($thing, $type) ? sprintf( 'TYPE_%s_OBJECT', $type )
111             : undef
112             ;
113 142 100       315 if ( $id ) {
114 29 100       156 $self->[ $self->$id() ] = 1 if ! $self->[OVERRIDE];
115             # IO refs are always objects
116 29 50       64 $self->[TYPE_IO] = 1 if $id eq 'TYPE_IO_OBJECT';
117 29 100       58 $self->[CONTAINER] = $ref if $self->[BLESSED];
118 29         61 last;
119             }
120             }
121              
122 29         108 return $self;
123             }
124              
125 3     3   13 sub container { return shift->[CONTAINER] }
126 0     0   0 sub blessed { return shift->[BLESSED] }
127              
128             sub _object {
129 128     128   219 my($self, $object, $type)= @_;
130 128   100     322 my $blessed = Scalar::Util::blessed( $object ) || return;
131 73         143 my $rt = Scalar::Util::reftype( $object );
132             # new perl (5.24+ ?) messes the detection
133 73 100 33     300 return if $rt && $blessed && $rt eq 'REGEXP' && $blessed eq 'Regexp';
      66        
      100        
134 65         89 $self->[BLESSED] = 1;
135              
136 65 100       118 if ( $rt eq 'IO' ) { # special case: IO
137 4         6 $self->[TYPE_IO_OBJECT] = 1;
138 4         7 $self->[TYPE_IO] = 1;
139 4         6 $self->[OVERRIDE] = 1;
140 4         19 return 1;
141             }
142              
143 61 100       123 if ( re::is_regexp( $object ) ) { # special case: Regexp
144 1         2 $self->[TYPE_Regexp_OBJECT] = 1;
145 1         3 $self->[OVERRIDE] = 1;
146 1         5 return 1;
147             }
148              
149 60 100       130 return if $rt ne $type; # || ! ( $blessed eq 'IO' && $blessed eq $type );
150 10         42 return 1;
151             }
152              
153             sub _bool {
154 1     1   10 require Carp;
155 1         214 Carp::croak(
156             'reftype() objects can not be used in boolean contexts. '
157             .'Please call one of the test methods on the return value instead. '
158             .'Example: `print 42 if reftype( \$thing )->array;`'
159             );
160             }
161              
162             1;
163              
164             __END__