File Coverage

blib/lib/Scalar/Util/Reftype.pm
Criterion Covered Total %
statement 108 112 96.4
branch 20 22 90.9
condition 6 6 100.0
subroutine 25 26 96.1
pod n/a
total 159 166 95.7


line stmt bran cond sub pod time code
1             package Scalar::Util::Reftype;
2 1     1   14065 use strict;
  1         1  
  1         27  
3 1     1   3 use warnings;
  1         0  
  1         29  
4 1     1   3 use vars qw( $VERSION @ISA $OID @EXPORT @EXPORT_OK );
  1         5  
  1         67  
5 1     1   3 use constant RESET_COUNTER => -1;
  1         1  
  1         80  
6 1     1   4 use constant HAS_FORMAT_REF => $] >= 5.008; # old ones don't have it
  1         0  
  1         53  
7 1         54 use constant PRIMITIVES => qw(
8             Regexp IO SCALAR ARRAY HASH CODE GLOB REF LVALUE
9             ),
10             ( HAS_FORMAT_REF ? qw(FORMAT) : () )
11 1     1   4 ;
  1         0  
12 1     1   464 use subs qw( container class reftype type blessed object );
  1         17  
  1         3  
13 1         4 use overload bool => '_bool',
14             fallback => 1,
15 1     1   1104 ;
  1         737  
16 1     1   56 use re ();
  1         1  
  1         10  
17 1     1   3 use Scalar::Util ();
  1         1  
  1         19  
18 1     1   2 use base qw( Exporter );
  1         1  
  1         137  
19              
20             BEGIN {
21 1     1   2 $VERSION = '0.44';
22 1         2 @EXPORT = qw( reftype );
23 1         1 @EXPORT_OK = qw( type HAS_FORMAT_REF );
24              
25 1         1 $OID = RESET_COUNTER;
26 1         2 foreach my $type ( PRIMITIVES ) {
27 10         214 constant->import( 'TYPE_' . $type, ++$OID );
28 10         242 constant->import( 'TYPE_' . $type . '_OBJECT', ++$OID );
29             }
30             }
31              
32 1     1   5 use constant CONTAINER => ++$OID;
  1         1  
  1         42  
33 1     1   3 use constant BLESSED => ++$OID;
  1         1  
  1         40  
34 1     1   4 use constant OVERRIDE => ++$OID;
  1         1  
  1         33  
35 1     1   3 use constant MAXID => $OID;
  1         1  
  1         57  
36              
37             BEGIN {
38 1     1   4 *class = \*container;
39 1         1 *type = \*reftype;
40 1         1 *object = \*blessed;
41 1         1 my @types;
42 1     1   4 no strict 'refs';
  1         1  
  1         157  
43 1         1 foreach my $sym ( keys %{ __PACKAGE__ . q{::} } ) {
  1         6  
44 44 100       75 if ( $sym =~ m{ \A TYPE_ (.+?) \z }xms ) {
45 20         31 push @types, $1;
46             }
47             }
48              
49 1         2 foreach my $meth ( @types ) {
50 20         53 *{ lc $meth } = sub {
51 30     30   27 my $self = shift;
52 30         53 my $id = 'TYPE_' . $meth;
53 30         137 return $self->[ $self->$id() ];
54             }
55 20         34 }
56              
57             # http://perlmonks.org/?node_id=665339
58 1 50       444 if ( ! defined &re::is_regexp ) {
59             *re::is_regexp = sub($) {
60 0         0 require Data::Dump::Streamer;
61 0         0 return Data::Dump::Streamer::regex( shift );
62             }
63 0         0 }
64             }
65              
66             sub reftype {
67 34     34   571 my @args = @_;
68 34         82 my $o = __PACKAGE__->_new;
69 34         64 return $o->_analyze( @args )
70             }
71              
72             sub _new {
73 34     34   56 my $class = shift;
74 34         57 my $self = [ map { 0 } 0..MAXID ];
  782         644  
75 34         57 $self->[CONTAINER] = q{};
76 34         40 bless $self, $class;
77 34         41 return $self;
78             }
79              
80             sub _analyze {
81 34     34   27 my $self = shift;
82 34   100     89 my $thing = shift || return $self;
83 31   100     65 my $ref = CORE::ref($thing) || return $self;
84              
85 29         63 foreach my $type ( PRIMITIVES ) {
86 137 100       272 my $id = $ref eq $type ? sprintf( 'TYPE_%s', $type )
    100          
87             : $self->_object($thing, $type) ? sprintf( 'TYPE_%s_OBJECT', $type )
88             : undef
89             ;
90 137 100       239 if ( $id ) {
91 29 100       165 $self->[ $self->$id() ] = 1 if ! $self->[OVERRIDE];
92             # IO refs are always objects
93 29 50       59 $self->[TYPE_IO] = 1 if $id eq 'TYPE_IO_OBJECT';
94 29 100       48 $self->[CONTAINER] = $ref if $self->[BLESSED];
95 29         39 last;
96             }
97             }
98 29         121 return $self;
99             }
100              
101 3     3   8 sub container { return shift->[CONTAINER] }
102 0     0   0 sub blessed { return shift->[BLESSED] }
103              
104             sub _object {
105 123     123   118 my($self, $object, $type)= @_;
106 123   100     317 my $blessed = Scalar::Util::blessed( $object ) || return;
107 63         87 my $rt = Scalar::Util::reftype( $object );
108 63         48 $self->[BLESSED] = 1;
109              
110 63 100       87 if ( $rt eq 'IO' ) { # special case: IO
111 4         4 $self->[TYPE_IO_OBJECT] = 1;
112 4         4 $self->[TYPE_IO] = 1;
113 4         4 $self->[OVERRIDE] = 1;
114 4         17 return 1;
115             }
116              
117 59 100       87 if ( re::is_regexp( $object ) ) { # special case: Regexp
118 1         3 $self->[TYPE_Regexp_OBJECT] = 1;
119 1         1 $self->[OVERRIDE] = 1;
120 1         3 return 1;
121             }
122              
123 58 100       110 return if $rt ne $type; # || ! ( $blessed eq 'IO' && $blessed eq $type );
124 10         37 return 1;
125             }
126              
127             sub _bool {
128 1     1   11 require Carp;
129 1         154 Carp::croak(
130             'reftype() objects can not be used in boolean contexts. '
131             .'Please call one of the test methods on the return value instead. '
132             .'Example: `print 42 if reftype( \$thing )->array;`'
133             );
134             }
135              
136             1;
137              
138             __END__