File Coverage

blib/lib/Specio/Constraint/Parameterizable.pm
Criterion Covered Total %
statement 47 49 95.9
branch 12 20 60.0
condition n/a
subroutine 13 13 100.0
pod 1 2 50.0
total 73 84 86.9


line stmt bran cond sub pod time code
1             package Specio::Constraint::Parameterizable;
2              
3 28     28   164 use strict;
  28         52  
  28         713  
4 28     28   130 use warnings;
  28         43  
  28         1076  
5              
6             our $VERSION = '0.46';
7              
8 28     28   142 use Carp qw( confess );
  28         52  
  28         1176  
9 28     28   6324 use Role::Tiny::With;
  28         72387  
  28         1228  
10 28     28   11042 use Specio::Constraint::Parameterized;
  28         75  
  28         949  
11 28     28   6051 use Specio::DeclaredAt;
  28         62  
  28         757  
12 28     28   147 use Specio::OO;
  28         54  
  28         1316  
13 28     28   147 use Specio::TypeChecks qw( does_role isa_class );
  28         55  
  28         1104  
14              
15 28     28   145 use Specio::Constraint::Role::Interface;
  28         52  
  28         10424  
16             with 'Specio::Constraint::Role::Interface';
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             _parameterized_constraint_generator => {
26             isa => 'CodeRef',
27             init_arg => 'parameterized_constraint_generator',
28             predicate => '_has_parameterized_constraint_generator',
29             },
30             _parameterized_inline_generator => {
31             isa => 'CodeRef',
32             init_arg => 'parameterized_inline_generator',
33             predicate => '_has_parameterized_inline_generator',
34             },
35             };
36              
37             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
38             sub _attrs {
39 442     442   767 return $attrs;
40             }
41             }
42              
43             sub BUILD {
44 112     112 0 1931 my $self = shift;
45              
46 112 50       339 if ( $self->_has_constraint ) {
47 0 0       0 die
48             'A parameterizable constraint with a constraint parameter must also have a parameterized_constraint_generator'
49             unless $self->_has_parameterized_constraint_generator;
50             }
51              
52 112 50       676 if ( $self->_has_inline_generator ) {
53 112 50       640 die
54             'A parameterizable constraint with an inline_generator parameter must also have a parameterized_inline_generator'
55             unless $self->_has_parameterized_inline_generator;
56             }
57              
58 112         563 return;
59             }
60              
61             sub parameterize {
62 11     11 1 125 my $self = shift;
63 11         38 my %args = @_;
64              
65 11         35 my ( $parameter, $declared_at ) = @args{qw( of declared_at )};
66 11 50       40 does_role( $parameter, 'Specio::Constraint::Role::Interface' )
67             or confess
68             'The "of" parameter passed to ->parameterize must be an object which does the Specio::Constraint::Role::Interface role';
69              
70 11 100       233 if ($declared_at) {
71 10 50       39 isa_class( $declared_at, 'Specio::DeclaredAt' )
72             or confess
73             'The "declared_at" parameter passed to ->parameterize must be a Specio::DeclaredAt object';
74             }
75              
76 11 100       43 $declared_at = Specio::DeclaredAt->new_from_caller(1)
77             unless defined $declared_at;
78              
79 11         60 my %p = (
80             parent => $self,
81             parameter => $parameter,
82             declared_at => $declared_at,
83             );
84              
85 11 50       53 if ( $self->_has_parameterized_constraint_generator ) {
86             $p{constraint}
87 0         0 = $self->_parameterized_constraint_generator->($parameter);
88             }
89             else {
90 11 100       115 confess
91             'The "of" parameter passed to ->parameterize must be an inlinable constraint if the parameterizable type has an inline_generator'
92             unless $parameter->can_be_inlined;
93              
94 10         95 my $ig = $self->_parameterized_inline_generator;
95 10     13   94 $p{inline_generator} = sub { $ig->( shift, $parameter, @_ ) };
  13         84  
96             }
97              
98 10         81 return Specio::Constraint::Parameterized->new(%p);
99             }
100              
101             __PACKAGE__->_ooify;
102              
103             1;
104              
105             # ABSTRACT: A class which represents parameterizable constraints
106              
107             __END__
108              
109             =pod
110              
111             =encoding UTF-8
112              
113             =head1 NAME
114              
115             Specio::Constraint::Parameterizable - A class which represents parameterizable constraints
116              
117             =head1 VERSION
118              
119             version 0.46
120              
121             =head1 SYNOPSIS
122              
123             my $arrayref = t('ArrayRef');
124              
125             my $arrayref_of_int = $arrayref->parameterize( of => t('Int') );
126              
127             =head1 DESCRIPTION
128              
129             This class implements the API for parameterizable types like C<ArrayRef> and
130             C<Maybe>.
131              
132             =for Pod::Coverage BUILD
133              
134             =head1 API
135              
136             This class implements the same API as L<Specio::Constraint::Simple>, with a few
137             additions.
138              
139             =head2 Specio::Constraint::Parameterizable->new(...)
140              
141             This class's constructor accepts two additional parameters:
142              
143             =over 4
144              
145             =item * parameterized_constraint_generator
146              
147             This is a subroutine that generates a new constraint subroutine when the type
148             is parameterized.
149              
150             It will be called as a method on the type and will be passed a single
151             argument, the type object for the type parameter.
152              
153             This parameter is mutually exclusive with the
154             C<parameterized_inline_generator> parameter.
155              
156             =item * parameterized_inline_generator
157              
158             This is a subroutine that generates a new inline generator subroutine when the
159             type is parameterized.
160              
161             It will be called as a method on the L<Specio::Constraint::Parameterized>
162             object when that object needs to generate an inline constraint. It will
163             receive the type parameter as the first argument and the variable name as a
164             string as the second.
165              
166             This probably seems fairly confusing, so looking at the examples in the
167             L<Specio::Library::Builtins> code may be helpful.
168              
169             This parameter is mutually exclusive with the
170             C<parameterized_constraint_generator> parameter.
171              
172             =back
173              
174             =head2 $type->parameterize(...)
175              
176             This method takes two arguments. The C<of> argument should be an object which
177             does the L<Specio::Constraint::Role::Interface> role, and is required.
178              
179             The other argument, C<declared_at>, is optional. If it is not given, then a
180             new L<Specio::DeclaredAt> object is creating using a call stack depth of 1.
181              
182             This method returns a new L<Specio::Constraint::Parameterized> object.
183              
184             =head1 SUPPORT
185              
186             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
187              
188             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
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 - 2020 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