File Coverage

blib/lib/isa.pm
Criterion Covered Total %
statement 46 61 75.4
branch 11 34 32.3
condition 2 7 28.5
subroutine 10 11 90.9
pod 0 4 0.0
total 69 117 58.9


line stmt bran cond sub pod time code
1 1     1   71541 use 5.006;
  1         4  
2 1     1   6 use strict;
  1         1  
  1         20  
3 1     1   4 use warnings;
  1         2  
  1         439  
4              
5             package isa;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '2.001';
9              
10             BEGIN {
11 1         491 *HAS_XS = eval { require Type::Tiny::XS; 1 }
  1         2590  
12             ? sub(){!!1}
13 1 50   1   3 : sub(){!!0};
14            
15 1 50       5 eval { require Mouse::Util; } unless HAS_XS();
  0         0  
16 1 0       16 *HAS_MOUSE = eval { Mouse::Util::MOUSE_XS() and 'Mouse::Util'->can('generate_isa_predicate_for') }
17             ? sub(){!!1}
18 1 50       2 : sub(){!!0};
19            
20             *HAS_NATIVE = ( $] ge '5.032' )
21             ? sub(){!!1}
22 1 50       5 : sub(){!!0};
23            
24             *perlstring = eval { require B; 'B'->can('perlstring') }
25 1   50     2 || sub { sprintf '"%s"', quotemeta($_[0]) };
26            
27             *is_CodeRef = HAS_XS()
28             ? Type::Tiny::XS::get_coderef_for('CodeRef')
29 1 50       8 : sub { 'CODE' eq ref $_[0] };
  0         0  
30            
31             *is_HashRef = HAS_XS()
32             ? Type::Tiny::XS::get_coderef_for('HashRef')
33 1 50       13 : sub { 'HASH' eq ref $_[0] };
  0         0  
34            
35             *is_NonEmptyStr = HAS_XS()
36             ? Type::Tiny::XS::get_coderef_for('NonEmptyStr')
37 1 0 0     10 : sub { defined $_[0] and !length ref $_[0] and length $_[0] };
  0 50       0  
38             };
39              
40             sub import {
41 1     1   9 my ( $caller, $me ) = ( scalar(caller), shift );
42            
43 1         2 my %imports;
44 1         2 for my $arg ( @_ ) {
45 2 50       8 if ( is_HashRef $arg ) {
46 0         0 %imports = ( %imports, %$arg );
47             }
48             else {
49 2         3 $imports{ $me->subname_for( $arg ) } = $arg;
50             }
51             }
52            
53 1         3 $me->setup_for( $caller, \%imports );
54             }
55              
56             sub subname_for {
57 2     2 0 4 my ( $me, $class ) = ( shift, @_ );
58 2         10 $class =~ s/\W+/_/g;
59 2         7 'isa_' . $class;
60             }
61              
62             sub failed_expectation {
63 0     0 0 0 my ( $me, $bad_value, $role, $expectation ) = ( shift, @_ );
64 0 0       0 my $printable_value =
    0          
    0          
65             ref($bad_value) ? sprintf( '%s reference', ref($bad_value) ) :
66             !defined($bad_value) ? 'undef' :
67             !length($bad_value) ? 'empty string' : 'something weird';
68            
69 0         0 require Carp;
70 0         0 Carp::croak( sprintf(
71             'Expected %s to be %s, but got %s; failed',
72             $role,
73             $expectation,
74             $printable_value,
75             ) );
76             }
77              
78             my %cache;
79             sub setup_for {
80 1     1 0 3 my ( $me, $caller, $imports ) = ( shift, @_ );
81            
82 1         5 while ( my ( $subname, $class ) = each %$imports ) {
83 2 50       8 is_NonEmptyStr $subname or $me->failed_expectation( $subname, 'function name', 'non-empty string' );
84 2 50       5 is_NonEmptyStr $class or $me->failed_expectation( $class, 'class name', 'non-empty string' );
85            
86 1     1   386 no strict 'refs';
  1         2  
  1         29  
87 1     1   5 no warnings 'redefine';
  1         1  
  1         280  
88 2         126 *{"$caller\::$subname"} = (
89 2   50     7 $cache{ $class } ||= $me->generate_coderef( $class )
90             or die( "Problem generating coderef for $class" )
91             );
92             }
93             }
94              
95             sub generate_coderef {
96 2     2 0 4 my ( $me, $class ) = ( shift, @_ );
97 2         2 my $code;
98            
99 2         3 if ( HAS_XS ) {
100 2         8 my $typename = sprintf( 'InstanceOf[%s]', $class );
101 2         5 $code = Type::Tiny::XS::get_coderef_for( $typename );
102 2 50       91 return $code if is_CodeRef $code;
103             }
104            
105 0           if ( HAS_MOUSE ) {
106             $code = Mouse::Util::generate_isa_predicate_for( $class );
107             return $code if is_CodeRef $code;
108             }
109            
110 0           if ( HAS_NATIVE ) {
111             $code = eval sprintf(
112             q{ package isa::__NATIVE__; use feature q[isa]; no warnings q[experimental::isa]; sub { $_[0] isa %s } },
113             perlstring($class),
114             );
115             return $code if is_CodeRef $code;
116             }
117              
118 0           require Scalar::Util;
119 0           $code = eval sprintf(
120             q{ package isa::__LEGACY__; sub { Scalar::Util::blessed($_[0]) and $_[0]->isa(%s) } },
121             perlstring($class),
122             );
123 0 0         return $code if is_CodeRef $code;
124            
125 0           return;
126             }
127              
128             1;
129              
130             __END__