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