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 32     32   182 use strict;
  32         72  
  32         1182  
4 32     32   147 use warnings;
  32         50  
  32         5661  
5              
6             our $VERSION = '0.53';
7              
8 32     32   198 use Carp qw( confess );
  32         60  
  32         1692  
9 32     32   7632 use Role::Tiny::With;
  32         117496  
  32         3735  
10 32     32   14345 use Specio::Constraint::Parameterized;
  32         109  
  32         1423  
11 32     32   8761 use Specio::DeclaredAt;
  32         82  
  32         984  
12 32     32   166 use Specio::OO;
  32         51  
  32         1865  
13 32     32   268 use Specio::TypeChecks qw( does_role isa_class );
  32         65  
  32         1445  
14              
15 32     32   210 use Specio::Constraint::Role::Interface;
  32         58  
  32         14550  
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 529     529   1192 return $attrs;
40             }
41             }
42              
43             sub BUILD {
44 128     128 0 3163 my $self = shift;
45              
46 128 50       589 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 128 50       830 if ( $self->_has_inline_generator ) {
53 128 50       993 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 128         1028 return;
59             }
60              
61             sub parameterize {
62 15     15 1 224 my $self = shift;
63 15         62 my %args = @_;
64              
65 15         47 my ( $parameter, $declared_at ) = @args{qw( of declared_at )};
66 15 50       91 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 15 100       312 if ($declared_at) {
71 14 50       45 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 15 100       54 $declared_at = Specio::DeclaredAt->new_from_caller(1)
77             unless defined $declared_at;
78              
79 15         89 my %p = (
80             parent => $self,
81             parameter => $parameter,
82             declared_at => $declared_at,
83             );
84              
85 15 50       81 if ( $self->_has_parameterized_constraint_generator ) {
86             $p{constraint}
87 0         0 = $self->_parameterized_constraint_generator->($parameter);
88             }
89             else {
90 15 100       195 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 14         154 my $ig = $self->_parameterized_inline_generator;
95 14     13   165 $p{inline_generator} = sub { $ig->( shift, $parameter, @_ ) };
  13         99  
96             }
97              
98 14         118 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.53
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 argument,
151             the type object for the type parameter.
152              
153             This parameter is mutually exclusive with the C<parameterized_inline_generator>
154             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 receive
163             the type parameter as the first argument and the variable name as a string as
164             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 new
180             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             =head1 SOURCE
189              
190             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
191              
192             =head1 AUTHOR
193              
194             Dave Rolsky <autarch@urth.org>
195              
196             =head1 COPYRIGHT AND LICENSE
197              
198             This software is Copyright (c) 2012 - 2025 by Dave Rolsky.
199              
200             This is free software, licensed under:
201              
202             The Artistic License 2.0 (GPL Compatible)
203              
204             The full text of the license can be found in the
205             F<LICENSE> file included with this distribution.
206              
207             =cut