File Coverage

blib/lib/Specio/Library/Structured/Tuple.pm
Criterion Covered Total %
statement 84 88 95.4
branch 28 36 77.7
condition 7 9 77.7
subroutine 12 12 100.0
pod 0 1 0.0
total 131 146 89.7


line stmt bran cond sub pod time code
1              
2             use strict;
3 4     4   24 use warnings;
  4         7  
  4         95  
4 4     4   16  
  4         7  
  4         133  
5             our $VERSION = '0.48';
6              
7             use Carp qw( confess );
8 4     4   19 use List::Util ();
  4         10  
  4         174  
9 4     4   29 use Scalar::Util qw( blessed );
  4         7  
  4         68  
10 4     4   23 use Specio::Library::Builtins;
  4         7  
  4         176  
11 4     4   24 use Specio::TypeChecks qw( does_role );
  4         7  
  4         18  
12 4     4   20  
  4         10  
  4         2686  
13             my $arrayref = t('ArrayRef');
14              
15              
16 4     4 0 15 ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
17             $arrayref->inline_check( $_[1] );
18             }
19              
20 1     1   17 shift;
21             my $args = shift;
22              
23             my $saw_slurpy;
24 5     5   62 my $saw_optional;
25 5         8 for my $p ( @{$args} ) {
26             if ($saw_slurpy) {
27 5         9 confess
28             'A Tuple cannot have any parameters after a slurpy parameter';
29 5         7 }
  5         9  
30 15 50       62 if ( $saw_optional && blessed($p) ) {
31 0         0 confess
32             'A Tuple cannot have a non-optional parameter after an optional parameter';
33             }
34 15 50 66     28  
35 0         0 my $type;
36             if ( blessed($p) ) {
37             $type = $p;
38             }
39 15         18 else {
40 15 100       32 if ( ref $p eq 'HASH' ) {
41 11         14 if ( $p->{optional} ) {
42             $saw_optional = 1;
43             $type = $p->{optional};
44 4 50       14 }
45 4 100       11 if ( $p->{slurpy} ) {
46 3         4 $saw_slurpy = 1;
47 3         3 $type = $p->{slurpy};
48             }
49 4 100       9 }
50 1         2 else {
51 1         2 confess
52             'Can only pass types, optional types, and slurpy types when defining a Tuple';
53             }
54             }
55 0         0  
56             if ( $saw_optional && $saw_slurpy ) {
57             confess
58             'Cannot defined a slurpy Tuple with optional slots as well';
59             }
60 15 50 66     37  
61 0         0 does_role( $type, 'Specio::Constraint::Role::Interface' )
62             or confess
63             'All parameters passed to ->parameterize must be objects which do the Specio::Constraint::Role::Interface role';
64              
65 15 50       108 confess
66             'All parameters passed to ->parameterize must be inlinable constraints'
67             unless $type->can_be_inlined;
68             }
69 15 50       179  
70             return ( of => $args );
71             }
72              
73             my $self = shift;
74 5         35 my $p = shift;
75              
76             my @names;
77             for my $m ( @{ $p->{of} } ) {
78 5     5   16 ## no critic (Subroutines::ProtectPrivateSubs)
79 5         8 if ( blessed($m) ) {
80             push @names, $self->_name_or_anon($m);
81 5         6 }
82 5         8 elsif ( $m->{optional} ) {
  5         10  
83             push @names, $self->_name_or_anon( $m->{optional} ) . '?';
84 15 100       82 }
    100          
    50          
85 11         22 elsif ( $m->{slurpy} ) {
86             push @names, $self->_name_or_anon( $m->{slurpy} ) . '...';
87             }
88 3         6 }
89              
90             return 'Tuple[ ' . ( join ', ', @names ) . ' ]';
91 1         3 }
92              
93             shift;
94             my $val = shift;
95 5         94 my %args = @_;
96              
97             my @of = @{ $args{of} };
98              
99 12     12   16 my $slurpy;
100 12         20 $slurpy = ( pop @of )->{slurpy}
101 12         27 if !blessed( $of[-1] ) && $of[-1]->{slurpy};
102              
103 12         29 my @code = sprintf( '( %s )', $arrayref->_inline_check($val) );
  12         29  
104              
105 12         18 unless ($slurpy) {
106             my $min = 0;
107 12 100 100     57 my $max = 0;
108             for my $p (@of) {
109 12         36  
110             # Unblessed values are optional.
111 12 100       29 if ( blessed($p) ) {
112 9         14 $min++;
113 9         13 $max++;
114 9         17 }
115             else {
116             $max++;
117 30 100       61 }
118 21         29 }
119 21         27  
120             if ($min) {
121             push @code,
122 9         13 sprintf(
123             '( @{ %s } >= %d && @{ %s } <= %d )',
124             $val, $min, $val, $max
125             );
126 9 50       17 }
127 9         40 }
128              
129             for my $i ( 0 .. $#of ) {
130             my $p = $of[$i];
131             my $access = sprintf( '%s->[%d]', $val, $i );
132              
133             if ( !blessed($p) ) {
134             my $type = $p->{optional};
135 12         33  
136 36         59 push @code,
137 36         71 sprintf(
138             '( @{%s} >= %d ? ( %s ) : 1 )', $val, $i + 1,
139 36 100       88 $type->_inline_check($access)
140 9         17 );
141             }
142 9         17 else {
143             push @code,
144             sprintf( '( %s )', $p->_inline_check($access) );
145             }
146             }
147              
148             if ($slurpy) {
149 27         56 my $non_slurpy = scalar @of;
150             my $check
151             = '( @{%s} > %d ? ( List::Util::all { %s } @{%s}[%d .. $#{%s}] ) : 1 )';
152             push @code,
153             sprintf(
154 12 100       31 $check,
155 3         5 $val, $non_slurpy, $slurpy->_inline_check('$_'),
156 3         6 $val, $non_slurpy, $val,
157             );
158 3         7 }
159              
160             return '( ' . ( join ' && ', @code ) . ' )';
161             }
162              
163             1;
164              
165             # ABSTRACT: Guts of Tuple structured type
166 12         262  
167              
168             =pod
169              
170             =encoding UTF-8
171              
172             =head1 NAME
173              
174             Specio::Library::Structured::Tuple - Guts of Tuple structured type
175              
176             =head1 VERSION
177              
178             version 0.48
179              
180             =head1 DESCRIPTION
181              
182             There are no user facing parts here.
183              
184             =for Pod::Coverage .*
185              
186             =head1 SUPPORT
187              
188             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
189              
190             =head1 SOURCE
191              
192             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
193              
194             =head1 AUTHOR
195              
196             Dave Rolsky <autarch@urth.org>
197              
198             =head1 COPYRIGHT AND LICENSE
199              
200             This software is Copyright (c) 2012 - 2022 by Dave Rolsky.
201              
202             This is free software, licensed under:
203              
204             The Artistic License 2.0 (GPL Compatible)
205              
206             The full text of the license can be found in the
207             F<LICENSE> file included with this distribution.
208              
209             =cut