File Coverage

blib/lib/Specio/Library/Builtins.pm
Criterion Covered Total %
statement 36 37 97.3
branch n/a
condition n/a
subroutine 12 12 100.0
pod n/a
total 48 49 97.9


line stmt bran cond sub pod time code
1              
2             use strict;
3 30     30   240816 use warnings;
  30         83  
  30         735  
4 30     30   124  
  30         51  
  30         1048  
5             our $VERSION = '0.48';
6              
7             use parent 'Specio::Exporter';
8 30     30   5663  
  30         4153  
  30         211  
9             use List::Util 1.33 ();
10 30     30   1282 use overload ();
  30         600  
  30         516  
11 30     30   125 use re ();
  30         67  
  30         880  
12 30     30   144 use Scalar::Util ();
  30         46  
  30         364  
13 30     30   112 use Specio::Constraint::Parameterizable;
  30         47  
  30         401  
14 30     30   10821 use Specio::Declare;
  30         73  
  30         1602  
15 30     30   7227 use Specio::Helpers ();
  30         66  
  30         154  
16 30     30   138  
  30         45  
  30         1839  
17             BEGIN {
18 0         0 local $@ = undef;
19 30     30   92 my $has_ref_util
20             = eval { require Ref::Util; Ref::Util->VERSION('0.112'); 1 };
21 30         52 }
  30         12946  
  30         39959  
  30         35860  
22 240     240   645  
23             declare(
24             'Item',
25             inline => sub {'1'}
26             );
27              
28             declare(
29             'Undef',
30             parent => t('Item'),
31             inline => sub {
32             '!defined(' . $_[1] . ')';
33             }
34             );
35              
36             declare(
37             'Defined',
38             parent => t('Item'),
39             inline => sub {
40             'defined(' . $_[1] . ')';
41             }
42             );
43              
44             declare(
45             'Bool',
46             parent => t('Item'),
47             inline => sub {
48             return sprintf( <<'EOF', ( $_[1] ) x 7 );
49             (
50             (
51             !ref( %s )
52             && (
53             !defined( %s )
54             || %s eq q{}
55             || %s eq '1'
56             || %s eq '0'
57             )
58             )
59             ||
60             (
61             Scalar::Util::blessed( %s )
62             && defined overload::Method( %s, 'bool' )
63             )
64             )
65             EOF
66             }
67             );
68              
69             declare(
70             'Value',
71             parent => t('Defined'),
72             inline => sub {
73             $_[0]->parent->inline_check( $_[1] ) . ' && !ref(' . $_[1] . ')';
74             }
75             );
76              
77             declare(
78             'Ref',
79             parent => t('Defined'),
80              
81             # no need to call parent - ref also checks for definedness
82             inline => sub { 'ref(' . $_[1] . ')' }
83             );
84              
85             declare(
86             'Str',
87             parent => t('Value'),
88             inline => sub {
89             return sprintf( <<'EOF', ( $_[1] ) x 6 );
90             (
91             (
92             defined( %s )
93             && !ref( %s )
94             && (
95             ( ref( \%s ) eq 'SCALAR' )
96             || do { ( ref( \( my $val = %s ) ) eq 'SCALAR' ) }
97             )
98             )
99             ||
100             (
101             Scalar::Util::blessed( %s )
102             && defined overload::Method( %s, q{""} )
103             )
104             )
105             EOF
106             }
107             );
108              
109             declare(
110             'Num',
111             parent => t('Str'),
112             inline => sub {
113             return sprintf( <<'EOF', ( $_[1] ) x 5 );
114             (
115             (
116             defined( %s )
117             && !ref( %s )
118             && (
119             do {
120             ( my $val = %s ) =~
121             /\A
122             -?[0-9]+(?:\.[0-9]+)?
123             (?:[Ee][\-+]?[0-9]+)?
124             \z/x
125             }
126             )
127             )
128             ||
129             (
130             Scalar::Util::blessed( %s )
131             && defined overload::Method( %s, '0+' )
132             )
133             )
134             EOF
135             }
136             );
137              
138             declare(
139             'Int',
140             parent => t('Num'),
141             inline => sub {
142             return sprintf( <<'EOF', ( $_[1] ) x 6 );
143             (
144             (
145             defined( %s )
146             && !ref( %s )
147             && (
148             do { ( my $val1 = %s ) =~ /\A-?[0-9]+(?:[Ee]\+?[0-9]+)?\z/ }
149             )
150             )
151             ||
152             (
153             Scalar::Util::blessed( %s )
154             && defined overload::Method( %s, '0+' )
155             && do { ( my $val2 = %s + 0 ) =~ /\A-?[0-9]+(?:[Ee]\+?[0-9]+)?\z/ }
156             )
157             )
158             EOF
159             }
160             );
161              
162             {
163             my $ref_check
164             = _HAS_REF_UTIL
165             ? 'Ref::Util::is_plain_coderef(%s)'
166             : q{ref(%s) eq 'CODE'};
167              
168             declare(
169             'CodeRef',
170             parent => t('Ref'),
171             inline => sub {
172             return sprintf( <<"EOF", ( $_[1] ) x 3 );
173             (
174             $ref_check
175             ||
176             (
177             Scalar::Util::blessed( %s )
178             && defined overload::Method( %s, '&{}' )
179             )
180             )
181             EOF
182             }
183             );
184             }
185              
186             {
187             # This is a 5.8 back-compat shim stolen from Type::Tiny's Devel::Perl58Compat
188             # module.
189             unless ( exists &re::is_regexp || _HAS_REF_UTIL ) {
190             require B;
191             *re::is_regexp = sub {
192             ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval)
193             eval { B::svref_2object( $_[0] )->MAGIC->TYPE eq 'r' };
194             };
195             }
196              
197             my $ref_check
198             = _HAS_REF_UTIL
199             ? 'Ref::Util::is_regexpref(%s)'
200             : 're::is_regexp(%s)';
201              
202             declare(
203             'RegexpRef',
204             parent => t('Ref'),
205             inline => sub {
206             return sprintf( <<"EOF", ( $_[1] ) x 3 );
207             (
208             $ref_check
209             ||
210             (
211             Scalar::Util::blessed( %s )
212             && defined overload::Method( %s, 'qr' )
213             )
214             )
215             EOF
216             },
217             );
218             }
219              
220             {
221             my $ref_check
222             = _HAS_REF_UTIL
223             ? 'Ref::Util::is_plain_globref(%s)'
224             : q{ref( %s ) eq 'GLOB'};
225              
226             declare(
227             'GlobRef',
228             parent => t('Ref'),
229             inline => sub {
230             return sprintf( <<"EOF", ( $_[1] ) x 3 );
231             (
232             $ref_check
233             ||
234             (
235             Scalar::Util::blessed( %s )
236             && defined overload::Method( %s, '*{}' )
237             )
238             )
239             EOF
240             }
241             );
242             }
243              
244             {
245             my $ref_check
246             = _HAS_REF_UTIL
247             ? 'Ref::Util::is_plain_globref(%s)'
248             : q{ref( %s ) eq 'GLOB'};
249              
250             # NOTE: scalar filehandles are GLOB refs, but a GLOB ref is not always a
251             # filehandle
252             declare(
253             'FileHandle',
254             parent => t('Ref'),
255             inline => sub {
256             return sprintf( <<"EOF", ( $_[1] ) x 6 );
257             (
258             (
259             $ref_check
260             && Scalar::Util::openhandle( %s )
261             )
262             ||
263             (
264             Scalar::Util::blessed( %s )
265             &&
266             (
267             %s->isa('IO::Handle')
268             ||
269             (
270             defined overload::Method( %s, '*{}' )
271             && Scalar::Util::openhandle( *{ %s } )
272             )
273             )
274             )
275             )
276             EOF
277             }
278             );
279             }
280              
281             {
282             my $ref_check
283             = _HAS_REF_UTIL
284             ? 'Ref::Util::is_blessed_ref(%s)'
285             : 'Scalar::Util::blessed(%s)';
286              
287             declare(
288             'Object',
289             parent => t('Ref'),
290             inline => sub { sprintf( $ref_check, $_[1] ) },
291             );
292             }
293              
294             declare(
295             'ClassName',
296             parent => t('Str'),
297             inline => sub {
298             return
299             sprintf(
300             <<'EOF', $_[0]->parent->inline_check( $_[1] ), ( $_[1] ) x 2 );
301             (
302             ( %s )
303             && length "%s"
304             && Specio::Helpers::is_class_loaded( "%s" )
305             )
306             EOF
307             },
308             );
309              
310             {
311             my $ref_check
312             = _HAS_REF_UTIL
313             ? 'Ref::Util::is_plain_scalarref(%s) || Ref::Util::is_plain_refref(%s)'
314             : q{ref( %s ) eq 'SCALAR' || ref( %s ) eq 'REF'};
315              
316             my $base_scalarref_check = sub {
317             return sprintf( <<"EOF", ( $_[0] ) x 4 );
318             (
319             (
320             $ref_check
321             )
322             ||
323             (
324             Scalar::Util::blessed( %s )
325             && defined overload::Method( %s, '\${}' )
326             )
327             )
328             EOF
329             };
330              
331             declare(
332             'ScalarRef',
333             type_class => 'Specio::Constraint::Parameterizable',
334             parent => t('Ref'),
335             inline => sub { $base_scalarref_check->( $_[1] ) },
336             parameterized_inline_generator => sub {
337             shift;
338             my $parameter = shift;
339             my $val = shift;
340              
341             return sprintf(
342             '( ( %s ) && ( %s ) )',
343             $base_scalarref_check->($val),
344             $parameter->inline_check( '${' . $val . '}' ),
345             );
346             }
347             );
348             }
349              
350             {
351             my $ref_check
352             = _HAS_REF_UTIL
353             ? 'Ref::Util::is_plain_arrayref(%s)'
354             : q{ref( %s ) eq 'ARRAY'};
355              
356             my $base_arrayref_check = sub {
357             return sprintf( <<"EOF", ( $_[0] ) x 3 );
358             (
359             $ref_check
360             ||
361             (
362             Scalar::Util::blessed( %s )
363             && defined overload::Method( %s, '\@{}' )
364             )
365             )
366             EOF
367             };
368              
369             declare(
370             'ArrayRef',
371             type_class => 'Specio::Constraint::Parameterizable',
372             parent => t('Ref'),
373             inline => sub { $base_arrayref_check->( $_[1] ) },
374             parameterized_inline_generator => sub {
375             shift;
376             my $parameter = shift;
377             my $val = shift;
378              
379             return sprintf(
380             '( ( %s ) && ( List::Util::all { %s } @{ %s } ) )',
381             $base_arrayref_check->($val),
382             $parameter->inline_check('$_'),
383             $val,
384             );
385             }
386             );
387             }
388              
389             {
390             my $ref_check
391             = _HAS_REF_UTIL
392             ? 'Ref::Util::is_plain_hashref(%s)'
393             : q{ref( %s ) eq 'HASH'};
394              
395             my $base_hashref_check = sub {
396             return sprintf( <<"EOF", ( $_[0] ) x 3 );
397             (
398             $ref_check
399             ||
400             (
401             Scalar::Util::blessed( %s )
402             && defined overload::Method( %s, '%%{}' )
403             )
404             )
405             EOF
406             };
407              
408             declare(
409             'HashRef',
410             type_class => 'Specio::Constraint::Parameterizable',
411             parent => t('Ref'),
412             inline => sub { $base_hashref_check->( $_[1] ) },
413             parameterized_inline_generator => sub {
414             shift;
415             my $parameter = shift;
416             my $val = shift;
417              
418             return sprintf(
419             '( ( %s ) && ( List::Util::all { %s } values %%{ %s } ) )',
420             $base_hashref_check->($val),
421             $parameter->inline_check('$_'),
422             $val,
423             );
424             }
425             );
426             }
427              
428             declare(
429             'Maybe',
430             type_class => 'Specio::Constraint::Parameterizable',
431             parent => t('Item'),
432             inline => sub {'1'},
433             parameterized_inline_generator => sub {
434             shift;
435             my $parameter = shift;
436             my $val = shift;
437              
438             return sprintf( <<'EOF', $val, $parameter->inline_check($val) );
439             ( !defined( %s ) || ( %s ) )
440             EOF
441             },
442             );
443              
444             1;
445              
446             # ABSTRACT: Implements type constraint objects for Perl's built-in types
447              
448              
449             =pod
450              
451             =encoding UTF-8
452              
453             =head1 NAME
454              
455             Specio::Library::Builtins - Implements type constraint objects for Perl's built-in types
456              
457             =head1 VERSION
458              
459             version 0.48
460              
461             =head1 DESCRIPTION
462              
463             This library provides a set of types parallel to those provided by Moose.
464              
465             The types are in the following hierarchy
466              
467             Item
468             Bool
469             Maybe (of `a)
470             Undef
471             Defined
472             Value
473             Str
474             Num
475             Int
476             ClassName
477             Ref
478             ScalarRef (of `a)
479             ArrayRef (of `a)
480             HashRef (of `a)
481             CodeRef
482             RegexpRef
483             GlobRef
484             FileHandle
485             Object
486              
487             =head2 Item
488              
489             Accepts any value
490              
491             =head2 Bool
492              
493             Accepts a non-reference that is C<undef>, an empty string, C<0>, or C<1>. It
494             also accepts any object which overloads boolification.
495              
496             =head2 Maybe (of `a)
497              
498             A parameterizable type which accepts C<undef> or the type C<`a>. If not
499             parameterized this type will accept any value.
500              
501             =head2 Undef
502              
503             Only accepts C<undef>.
504              
505             =head2 Value
506              
507             Accepts any non-reference value.
508              
509             =head2 Str
510              
511             Accepts any non-reference value or an object which overloads stringification.
512              
513             =head2 Num
514              
515             Accepts nearly the same values as C<Scalar::Util::looks_like_number>, but does
516             not accept numbers with leading or trailing spaces, infinities, or NaN. Also
517             accepts an object which overloads numification.
518              
519             =head2 Int
520              
521             Accepts any integer value, or an object which overloads numification and
522             numifies to an integer.
523              
524             =head2 ClassName
525              
526             Accepts any value which passes C<Str> where the string is a loaded package.
527              
528             =head2 Ref
529              
530             Accepts any reference.
531              
532             =head2 ScalarRef (of `a)
533              
534             Accepts a scalar reference or an object which overloads scalar dereferencing.
535             If parameterized, the dereferenced value must be of type C<`a>.
536              
537             =head2 ArrayRef (of `a)
538              
539             Accepts a array reference or an object which overloads array dereferencing. If
540             parameterized, the values in the arrayref must be of type C<`a>.
541              
542             =head2 HashRef (of `a)
543              
544             Accepts a hash reference or an object which overloads hash dereferencing. If
545             parameterized, the values in the hashref must be of type C<`a>.
546              
547             =head2 CodeRef
548              
549             Accepts a code (sub) reference or an object which overloads code dereferencing.
550              
551             =head2 RegexpRef
552              
553             Accepts a regex object created by C<qr//> or an object which overloads regex
554             interpolation.
555              
556             =head2 GlobRef
557              
558             Accepts a glob reference or an object which overloads glob dereferencing.
559              
560             =head2 FileHandle
561              
562             Accepts a glob reference which is an open file handle, any C<IO::Handle> Object
563             or subclass, or an object which overloads glob dereferencing and returns a glob
564             reference which is an open file handle.
565              
566             =head2 Object
567              
568             Accepts any blessed object.
569              
570             =head1 SUPPORT
571              
572             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
573              
574             =head1 SOURCE
575              
576             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
577              
578             =head1 AUTHOR
579              
580             Dave Rolsky <autarch@urth.org>
581              
582             =head1 COPYRIGHT AND LICENSE
583              
584             This software is Copyright (c) 2012 - 2022 by Dave Rolsky.
585              
586             This is free software, licensed under:
587              
588             The Artistic License 2.0 (GPL Compatible)
589              
590             The full text of the license can be found in the
591             F<LICENSE> file included with this distribution.
592              
593             =cut