File Coverage

blib/lib/Scalar/Does.pm
Criterion Covered Total %
statement 88 95 92.6
branch 24 32 75.0
condition 10 11 90.9
subroutine 25 26 96.1
pod 4 4 100.0
total 151 168 89.8


line stmt bran cond sub pod time code
1             package Scalar::Does;
2              
3 7     7   203929 use 5.008;
  7         28  
  7         302  
4 7     7   45 use strict;
  7         12  
  7         253  
5 7     7   57 use warnings;
  7         19  
  7         301  
6 7     7   17239 use if $] < 5.010, 'UNIVERSAL::DOES';
  7         74  
  7         47  
7              
8             METADATA:
9             {
10             $Scalar::Does::AUTHORITY = 'cpan:TOBYINK';
11             $Scalar::Does::VERSION = '0.202';
12             }
13              
14             UTILITY_CLASS:
15             {
16             package Scalar::Does::RoleChecker;
17             $Scalar::Does::RoleChecker::AUTHORITY = 'cpan:TOBYINK';
18             $Scalar::Does::RoleChecker::VERSION = '0.202';
19 7     7   822 use base "Type::Tiny";
  7         12  
  7         22167  
20             sub new {
21 3     3   5 my $class = shift;
22 3         3 my ($name, $coderef);
23 3         7 for my $p (@_)
24             {
25 3 50       6 if (Scalar::Does::does($p, 'CODE')) { $coderef = $p }
  0         0  
26 3 100       2332 if (Scalar::Does::does($p, 'HASH')) { $coderef = $p->{where} }
  1         8  
27 3 100   2   533 if (Scalar::Does::does($p, 'Regexp')){ $coderef = sub { $_[0] =~ $p } }
  1         18  
  2         76  
28 3 100       536 if (not ref $p) { $name = $p }
  1         3  
29             }
30 3 100       295 Carp::confess("Cannot make role without checker coderef or regexp") unless $coderef;
31 2         18 $class->SUPER::new(display_name => $name, constraint => $coderef);
32             }
33 1     1   997 sub code { shift->constraint };
34             }
35              
36             PRIVATE_STUFF:
37             {
38             sub _lu {
39             require lexical::underscore;
40             goto \&lexical::underscore;
41             }
42            
43 7         1192 use constant MISSING_ROLE_MESSAGE => (
44             "Please supply a '-role' argument when exporting custom functions, died"
45 7     7   1774383 );
  7         21  
46            
47 7     7   41 use Carp 0 qw( confess );
  7         291  
  7         1596  
48 7     7   18411 use Types::Standard 0.004 qw( -types );
  7         10381383  
  7         97  
49             }
50              
51 7     7   93287 use namespace::clean 0.19;
  7         152199  
  7         55  
52              
53             DEFINE_CONSTANTS:
54             {
55             our %_CONSTANTS = (
56             BOOLEAN => q[bool],
57             STRING => q[""],
58             NUMBER => q[0+],
59             REGEXP => q[qr],
60             SMARTMATCH => q[~~],
61             map {; $_ => $_ } qw(
62             SCALAR ARRAY HASH CODE REF GLOB
63             LVALUE FORMAT IO VSTRING
64             )
65             );
66             require constant;
67             constant->import(\%_CONSTANTS);
68             }
69              
70             EXPORTER:
71             {
72 7     7   4862 use base "Exporter::Tiny";
  7         20  
  7         2467  
73            
74             our %_CONSTANTS;
75             our @EXPORT = ( "does" );
76             our @EXPORT_OK = (
77             qw( does overloads blessed reftype looks_like_number make_role where custom ),
78             keys(%_CONSTANTS),
79             );
80             our %EXPORT_TAGS = (
81             constants => [ "does", keys(%_CONSTANTS) ],
82             only_constants => [ keys(%_CONSTANTS) ],
83             make => [ qw( make_role where ) ],
84             );
85            
86             sub _exporter_validate_opts
87             {
88 7     7   1517 require B;
89 7         17 my $class = shift;
90             $_[0]{exporter} ||= sub {
91 24     24   2839 my $into = $_[0]{into};
92 24         33 my ($name, $sym) = @{ $_[1] };
  24         47  
93 24         218 for (grep ref, $into->can($name))
94             {
95 0 0       0 B::svref_2object($_)->STASH->NAME eq $into
96             and _croak("Refusing to overwrite local sub '$name' with export from $class");
97             }
98 24         158 "namespace::clean"->import(-cleanee => $_[0]{into}, $name);
99 7     7   43 no strict qw(refs);
  7         14  
  7         261  
100 7     7   43 no warnings qw(redefine prototype);
  7         19  
  7         830  
101 24         785 *{"$into\::$name"} = $sym;
  24         148  
102             }
103 7   50     96 }
104             }
105              
106             ROLES:
107             {
108 7     7   37 no warnings;
  7         10  
  7         3906  
109            
110             my $io = "Type::Tiny"->new(
111             display_name => "IO",
112             constraint => sub { require IO::Detect; IO::Detect::is_filehandle($_) },
113             );
114            
115             our %_ROLES = (
116             SCALAR => ( ScalarRef() | Ref->parameterize('SCALAR') | Overload->parameterize('${}') ),
117             ARRAY => ( ArrayRef() | Ref->parameterize('ARRAY') | Overload->parameterize('@{}') ),
118             HASH => ( HashRef() | Ref->parameterize('HASH') | Overload->parameterize('%{}') ),
119             CODE => ( CodeRef() | Ref->parameterize('CODE') | Overload->parameterize('&{}') ),
120             REF => ( Ref->parameterize('REF') ),
121             GLOB => ( GlobRef() | Ref->parameterize('GLOB') | Overload->parameterize('*{}') ),
122             LVALUE => ( Ref->parameterize('LVALUE') ),
123             FORMAT => ( Ref->parameterize('FORMAT') ),
124             IO => $io,
125             VSTRING => ( Ref->parameterize('VSTRING') ),
126             Regexp => ( RegexpRef() | Ref->parameterize('Regexp') | Overload->parameterize('qr') ),
127             bool => ( Value() | Overload->complementary_type | Overload->parameterize('bool') ),
128             q[""] => ( Value() | Overload->complementary_type | Overload->parameterize('""') ),
129             q[0+] => ( Value() | Overload->complementary_type | Overload->parameterize('0+') ),
130             q[<>] => ( Overload->parameterize('<>') | $io ),
131             q[~~] => ( Overload->parameterize('~~') | Object->complementary_type ),
132             q[${}] => 'SCALAR',
133             q[@{}] => 'ARRAY',
134             q[%{}] => 'HASH',
135             q[&{}] => 'CODE',
136             q[*{}] => 'GLOB',
137             q[qr] => 'Regexp',
138             );
139            
140             while (my ($k, $v) = each %_ROLES) { $_ROLES{$k} = $_ROLES{$v} unless ref $v }
141             }
142              
143             PUBLIC_FUNCTIONS:
144             {
145 7     7   56 use Scalar::Util 1.24 qw( blessed reftype looks_like_number );
  7         198  
  7         1427  
146            
147             sub overloads ($;$)
148             {
149 0 0   0 1 0 unshift @_, ${+_lu} if @_ == 1;
  0         0  
150 0 0       0 return unless blessed $_[0];
151 0         0 goto \&overload::Method;
152             }
153            
154             sub does ($;$)
155             {
156 172 50   172 1 55391 unshift @_, ${+_lu} if @_ == 1;
  0         0  
157 172         248 my ($thing, $role) = @_;
158            
159 7     7   37 no warnings;
  7         13  
  7         2907  
160 172         176 our %_ROLES;
161 172 100       1020 if (my $test = $_ROLES{$role})
162             {
163 97         618 return !! $test->check($thing);
164             }
165            
166 75 100 100     407 if (blessed $role and $role->can('check'))
167             {
168 18         112 return !! $role->check($thing);
169             }
170            
171 57 100 100     385 if (blessed $thing && $thing->can('DOES'))
    100 100        
172             {
173 12 100       51 return !! 1 if $thing->DOES($role);
174             }
175             elsif (UNIVERSAL::can($thing, 'can') && $thing->can('DOES'))
176             {
177 12         14 my $class = $thing;
178 12 100       47 return '0E0' if $class->DOES($role);
179             }
180            
181 49         323 return;
182             }
183            
184             sub _generate_custom
185             {
186 3     3   472 my ($class, $name, $arg) = @_;
187 3 100       275 my $role = $arg->{ -role } or confess MISSING_ROLE_MESSAGE;
188            
189             return sub (;$) {
190 4     4   2789 push @_, $role;
191 4         13 goto \&does;
192             }
193 2         14 }
194            
195             sub make_role
196             {
197 3     3 1 307 return "Scalar::Does::RoleChecker"->new(@_);
198             }
199            
200             sub where (&)
201             {
202 1     1 1 16 return +{ where => $_[0] };
203             }
204             }
205              
206             "it does"
207             __END__