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