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