File Coverage

blib/lib/Specio/Constraint/Structurable.pm
Criterion Covered Total %
statement 52 55 94.5
branch 10 22 45.4
condition n/a
subroutine 15 15 100.0
pod 1 2 50.0
total 78 94 82.9


line stmt bran cond sub pod time code
1              
2             use strict;
3 4     4   23 use warnings;
  4         6  
  4         90  
4 4     4   17  
  4         6  
  4         129  
5             our $VERSION = '0.48';
6              
7             use Carp qw( confess );
8 4     4   19 use Role::Tiny::With;
  4         13  
  4         136  
9 4     4   22 use Scalar::Util qw( blessed );
  4         13  
  4         149  
10 4     4   19 use Specio::DeclaredAt;
  4         7  
  4         150  
11 4     4   22 use Specio::OO;
  4         8  
  4         70  
12 4     4   15 use Specio::Constraint::Structured;
  4         31  
  4         200  
13 4     4   1321 use Specio::TypeChecks qw( does_role isa_class );
  4         10  
  4         115  
14 4     4   20  
  4         8  
  4         156  
15             use Specio::Constraint::Role::Interface;
16 4     4   21 with 'Specio::Constraint::Role::Interface';
  4         6  
  4         1560  
17              
18             {
19             ## no critic (Subroutines::ProtectPrivateSubs)
20             my $role_attrs = Specio::Constraint::Role::Interface::_attrs();
21             ## use critic
22              
23             my $attrs = {
24             %{$role_attrs},
25             _parameterization_args_builder => {
26             isa => 'CodeRef',
27             init_arg => 'parameterization_args_builder',
28             required => 1,
29             },
30             _name_builder => {
31             isa => 'CodeRef',
32             init_arg => 'name_builder',
33             required => 1,
34             },
35             _structured_constraint_generator => {
36             isa => 'CodeRef',
37             init_arg => 'structured_constraint_generator',
38             predicate => '_has_structured_constraint_generator',
39             },
40             _structured_inline_generator => {
41             isa => 'CodeRef',
42             init_arg => 'structured_inline_generator',
43             predicate => '_has_structured_inline_generator',
44             },
45             };
46              
47             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
48             return $attrs;
49             }
50 20     20   47 }
51              
52             my $self = shift;
53              
54             if ( $self->_has_constraint ) {
55 12     12 0 216 die
56             'A structurable constraint with a constraint parameter must also have a structured_constraint_generator'
57 12 50       30 unless $self->_has_structured_constraint_generator;
58 0 0       0 }
59              
60             if ( $self->_has_inline_generator ) {
61             die
62             'A structurable constraint with an inline_generator parameter must also have a structured_inline_generator'
63 12 50       65 unless $self->_has_structured_inline_generator;
64 12 50       53 }
65              
66             return;
67             }
68              
69 12         48 my $self = shift;
70             my %args = @_;
71              
72             my $declared_at = $args{declared_at};
73 11     11 1 103  
74 11         24 if ($declared_at) {
75             isa_class( $declared_at, 'Specio::DeclaredAt' )
76 11         20 or confess
77             q{The "declared_at" parameter passed to ->parameterize must be a Specio::DeclaredAt object};
78 11 50       28 }
79 11 50       27  
80             my %parameters
81             = $self->_parameterization_args_builder->( $self, $args{of} );
82              
83             $declared_at = Specio::DeclaredAt->new_from_caller(1)
84             unless defined $declared_at;
85 11         44  
86             my %new_p = (
87 11 50       27 parent => $self,
88             parameters => \%parameters,
89             declared_at => $declared_at,
90 11         40 name => $self->_name_builder->( $self, \%parameters ),
91             );
92              
93             if ( $self->_has_structured_constraint_generator ) {
94             $new_p{constraint}
95             = $self->_structured_constraint_generator->(%parameters);
96             }
97 11 50       53 else {
98             for my $p (
99 0         0 grep {
100             blessed($_)
101             && does_role('Specio::Constraint::Role::Interface')
102 11         79 } values %parameters
103             ) {
104 14 100       54  
105             confess
106             q{Any type objects passed to ->parameterize must be inlinable constraints if the structurable type has an inline_generator}
107             unless $p->can_be_inlined;
108             }
109 0 0       0  
110             my $ig = $self->_structured_inline_generator;
111             $new_p{inline_generator}
112             = sub { $ig->( shift, shift, %parameters, @_ ) };
113             }
114 11         28  
115             return Specio::Constraint::Structured->new(%new_p);
116 11     24   66 }
  24         160  
117              
118             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
119 11         56 return $_[1]->_has_name ? $_[1]->name : 'ANON';
120             }
121             ## use critic
122              
123             __PACKAGE__->_ooify;
124 30 50   30   75  
125             1;
126              
127             # ABSTRACT: A class which represents structurable constraints
128              
129              
130             =pod
131              
132             =encoding UTF-8
133              
134             =head1 NAME
135              
136             Specio::Constraint::Structurable - A class which represents structurable constraints
137              
138             =head1 VERSION
139              
140             version 0.48
141              
142             =head1 SYNOPSIS
143              
144             my $tuple = t('Tuple');
145              
146             my $tuple_of_str_int = $tuple->parameterize( of => [ t('Str'), t('Int') ] );
147              
148             =head1 DESCRIPTION
149              
150             This class implements the API for structurable types like C<Dict>, C<Map>< and
151             C<Tuple>.
152              
153             =for Pod::Coverage BUILD
154              
155             =head1 API
156              
157             This class implements the same API as L<Specio::Constraint::Simple>, with a few
158             additions.
159              
160             =head2 Specio::Constraint::Structurable->new(...)
161              
162             This class's constructor accepts two additional parameters:
163              
164             =over 4
165              
166             =item * parameterization_args_builder
167              
168             This is a subroutine that takes the values passed to C<of> and returns a hash
169             of named arguments. These arguments will then be passed into the
170             C<structured_constraint_generator> or C<structured_inline_generator>.
171              
172             This should also do argument checking to make sure that the argument passed are
173             valid. For example, the C<Tuple> type turns the arrayref passed to C<of> into a
174             hash, along the way checking that the caller did not do things like interleave
175             optional and required elements or mix optional and slurpy together in the
176             definition.
177              
178             This parameter is required.
179              
180             =item * name_builder
181              
182             This is a subroutine that is called to generate a name for the structured type
183             when it is created. This will be called as a method on the
184             C<Specio::Constraint::Structurable> object. It will be passed the hash of
185             arguments returned by the C<parameterization_args_builder>.
186              
187             This parameter is required.
188              
189             =item * structured_constraint_generator
190              
191             This is a subroutine that generates a new constraint subroutine when the type
192             is structured.
193              
194             It will be called as a method on the type and will be passed the hash of
195             arguments returned by the C<parameterization_args_builder>.
196              
197             This parameter is mutually exclusive with the C<structured_inline_generator>
198             parameter.
199              
200             This parameter or the C<structured_inline_generator> parameter is required.
201              
202             =item * structured_inline_generator
203              
204             This is a subroutine that generates a new inline generator subroutine when the
205             type is structured.
206              
207             It will be called as a method on the L<Specio::Constraint::Structured> object
208             when that object needs to generate an inline constraint. It will receive the
209             type parameter as the first argument and the variable name as a string as the
210             second.
211              
212             The remaining arguments will be the parameter hash returned by the
213             C<parameterization_args_builder>.
214              
215             This probably seems fairly confusing, so looking at the examples in the
216             L<Specio::Library::Structured::*> code may be helpful.
217              
218             This parameter is mutually exclusive with the
219             C<structured_constraint_generator> parameter.
220              
221             This parameter or the C<structured_constraint_generator> parameter is required.
222              
223             =back
224              
225             =head2 $type->parameterize(...)
226              
227             This method takes two arguments. The C<of> argument should be an object which
228             does the L<Specio::Constraint::Role::Interface> role, and is required.
229              
230             The other argument, C<declared_at>, is optional. If it is not given, then a new
231             L<Specio::DeclaredAt> object is creating using a call stack depth of 1.
232              
233             This method returns a new L<Specio::Constraint::Structured> object.
234              
235             =head1 SUPPORT
236              
237             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
238              
239             =head1 SOURCE
240              
241             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
242              
243             =head1 AUTHOR
244              
245             Dave Rolsky <autarch@urth.org>
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             This software is Copyright (c) 2012 - 2022 by Dave Rolsky.
250              
251             This is free software, licensed under:
252              
253             The Artistic License 2.0 (GPL Compatible)
254              
255             The full text of the license can be found in the
256             F<LICENSE> file included with this distribution.
257              
258             =cut