File Coverage

blib/lib/Scalar/Util/Reftype.pm
Criterion Covered Total %
statement 107 122 87.7
branch 21 24 87.5
condition 15 18 83.3
subroutine 25 27 92.5
pod n/a
total 168 191 87.9


line stmt bran cond sub pod time code
1             package Scalar::Util::Reftype;
2             $Scalar::Util::Reftype::VERSION = '0.46';
3 1     1   53122 use 5.010;
  1         9  
4 1     1   4 use strict;
  1         1  
  1         17  
5 1     1   3 use warnings;
  1         2  
  1         38  
6              
7 1     1   5 use constant RESET_COUNTER => -1;
  1         1  
  1         78  
8             # being kept for backwards compatibility, 5.10 and later have it
9 1     1   5 use constant HAS_FORMAT_REF => 1;
  1         2  
  1         61  
10 1         70 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         1  
22 1         4 use subs qw(
23             blessed
24             class
25             container
26             object
27             reftype
28             type
29 1     1   422 );
  1         19  
30 1         5 use overload bool => '_bool',
31             fallback => 1,
32 1     1   982 ;
  1         830  
33 1     1   70 use re ();
  1         1  
  1         12  
34 1     1   3 use Scalar::Util ();
  1         2  
  1         14  
35 1     1   3 use base qw( Exporter );
  1         2  
  1         188  
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         2 foreach my $type ( PRIMITIVES ) {
44 10         176 constant->import( 'TYPE_' . $type, ++$OID );
45 10         205 constant->import( 'TYPE_' . $type . '_OBJECT', ++$OID );
46             }
47             }
48              
49 1     1   16 use constant CONTAINER => ++$OID;
  1         2  
  1         50  
50 1     1   5 use constant BLESSED => ++$OID;
  1         2  
  1         49  
51 1     1   5 use constant OVERRIDE => ++$OID;
  1         2  
  1         54  
52 1     1   6 use constant MAXID => $OID;
  1         1  
  1         65  
53              
54             BEGIN {
55 1     1   5 *class = \*container;
56 1         2 *type = \*reftype;
57 1         3 *object = \*blessed;
58 1         1 my(@types, @obj_idx);
59 1     1   6 no strict 'refs';
  1         1  
  1         296  
60 1         2 foreach my $sym ( keys %{ __PACKAGE__ . q{::} } ) {
  1         7  
61 46 100       96 if ( $sym =~ m{ \A TYPE_ (.+?) \z }xms ) {
62 20         40 push @types, $1;
63 20         31 push @obj_idx, $sym;
64             }
65             }
66              
67 1         3 foreach my $meth ( @types ) {
68 20         63 *{ lc $meth } = sub {
69 30     30   40 my $self = shift;
70 30         61 my $id = 'TYPE_' . $meth;
71 30         133 return $self->[ $self->$id() ];
72             }
73 20         51 }
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         454 };
87             }
88              
89             sub reftype {
90 34     34   988 my @args = @_;
91 34         76 my $o = __PACKAGE__->_new;
92 34         64 return $o->_analyze( @args )
93             }
94              
95             sub _new {
96 34     34   49 my $class = shift;
97 34         61 my $self = [ map { 0 } 0..MAXID ];
  782         1013  
98 34         65 $self->[CONTAINER] = q{};
99 34         47 bless $self, $class;
100 34         53 return $self;
101             }
102              
103             sub _analyze {
104 34     34   45 my $self = shift;
105 34   100     90 my $thing = shift || return $self;
106 31   100     64 my $ref = CORE::ref($thing) || return $self;
107              
108 29         60 foreach my $type ( PRIMITIVES ) {
109 142 100       284 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       266 if ( $id ) {
114 29 100       132 $self->[ $self->$id() ] = 1 if ! $self->[OVERRIDE];
115             # IO refs are always objects
116 29 50       56 $self->[TYPE_IO] = 1 if $id eq 'TYPE_IO_OBJECT';
117 29 100       45 $self->[CONTAINER] = $ref if $self->[BLESSED];
118 29         54 last;
119             }
120             }
121              
122 29         93 return $self;
123             }
124              
125 3     3   11 sub container { return shift->[CONTAINER] }
126 0     0   0 sub blessed { return shift->[BLESSED] }
127              
128             sub _object {
129 128     128   182 my($self, $object, $type)= @_;
130 128   100     264 my $blessed = Scalar::Util::blessed( $object ) || return;
131 73         112 my $rt = Scalar::Util::reftype( $object );
132              
133             # new perl (5.24+ ?) messes the detection
134 73 100 33     322 if ( $rt
      100        
      66        
      100        
135             && $blessed
136             # new 5.10
137             && ( $rt eq 'REGEXP' || $rt eq 'SCALAR')
138             && $blessed eq 'Regexp'
139             ) {
140 8         14 return;
141             }
142              
143 65         73 $self->[BLESSED] = 1;
144              
145 65 100       83 if ( $rt eq 'IO' ) { # special case: IO
146 4         7 $self->[TYPE_IO_OBJECT] = 1;
147 4         4 $self->[TYPE_IO] = 1;
148 4         5 $self->[OVERRIDE] = 1;
149 4         16 return 1;
150             }
151              
152 61 100       99 if ( re::is_regexp( $object ) ) { # special case: Regexp
153 1         2 $self->[TYPE_Regexp_OBJECT] = 1;
154 1         2 $self->[OVERRIDE] = 1;
155 1         4 return 1;
156             }
157              
158 60 100       113 return if $rt ne $type; # || ! ( $blessed eq 'IO' && $blessed eq $type );
159 10         36 return 1;
160             }
161              
162             sub _bool {
163 1     1   13 require Carp;
164 1         197 Carp::croak(
165             'reftype() objects can not be used in boolean contexts. '
166             .'Please call one of the test methods on the return value instead. '
167             .'Example: `print 42 if reftype( \$thing )->array;`'
168             );
169             }
170              
171             1;
172              
173             __END__