File Coverage

blib/lib/Specio/Constraint/Simple.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1              
2             use strict;
3 30     30   57204 use warnings;
  30         56  
  30         777  
4 30     30   129  
  30         55  
  30         1062  
5             our $VERSION = '0.48';
6              
7             use Role::Tiny::With;
8 30     30   483 use Specio::OO;
  30         4143  
  30         1178  
9 30     30   480  
  30         47  
  30         1683  
10             with 'Specio::Constraint::Role::Interface';
11              
12             __PACKAGE__->_ooify;
13              
14             1;
15              
16             # ABSTRACT: Class for simple (non-parameterized or specialized) types
17              
18              
19             =pod
20              
21             =encoding UTF-8
22              
23             =head1 NAME
24              
25             Specio::Constraint::Simple - Class for simple (non-parameterized or specialized) types
26              
27             =head1 VERSION
28              
29             version 0.48
30              
31             =head1 SYNOPSIS
32              
33             my $str = t('Str');
34              
35             print $str->name; # Str
36              
37             my $parent = $str->parent;
38              
39             if ( $str->value_is_valid($value) ) { ... }
40              
41             $str->validate_or_die($value);
42              
43             my $code = $str->inline_coercion_and_check('$_[0]');
44              
45             =head1 DESCRIPTION
46              
47             This class implements simple type constraints, constraints without special
48             properties or parameterization.
49              
50             It does not actually contain any real code of its own. The entire
51             implementation is provided by the L<Specio::Constraint::Role::Interface> role,
52             but the primary API for type constraints is documented here.
53              
54             All other type constraint classes in this distribution implement this API,
55             except where otherwise noted.
56              
57             =head1 API
58              
59             This class provides the following methods.
60              
61             =head2 Specio::Constraint::Simple->new(...)
62              
63             This creates a new constraint. It accepts the following named parameters:
64              
65             =over 4
66              
67             =item * name => $name
68              
69             This is the type's name. The name is optional, but if provided it must be a
70             string.
71              
72             =item * parent => $type
73              
74             The type's parent type. This must be an object which does the
75             L<Specio::Constraint::Role::Interface> role.
76              
77             This parameter is optional.
78              
79             =item * constraint => sub { ... }
80              
81             A subroutine reference implementing the constraint. It will be called as a
82             method on the object and passed a single argument, the value to check.
83              
84             It should return true or false to indicate whether the value matches the
85             constraint.
86              
87             This parameter is mutually exclusive with C<inline_generator>.
88              
89             You can also pass this option with the key C<where> in the parameter list.
90              
91             =item * inline_generator => sub { ... }
92              
93             This should be a subroutine reference which returns a string containing a
94             single term. This code should I<not> end in a semicolon. This code should
95             implement the constraint.
96              
97             The generator will be called as a method on the constraint with a single
98             argument. That argument is the name of the variable being coerced, something
99             like C<'$_[0]'> or C<'$var'>.
100              
101             The inline generator is expected to include code to implement both the current
102             type and all its parents. Typically, the easiest way to do this is to write a
103             subroutine something like this:
104              
105             sub {
106             my $self = shift;
107             my $var = shift;
108              
109             return $_[0]->parent->inline_check( $_[1] )
110             . ' and more checking code goes here';
111             }
112              
113             This parameter is mutually exclusive with C<constraint>.
114              
115             You can also pass this option with the key C<inline> in the parameter list.
116              
117             =item * inline_environment => {}
118              
119             This should be a hash reference of variable names (with sigils) and values for
120             that variable. The values should be I<references> to the values of the
121             variables.
122              
123             This environment will be used when compiling the constraint as part of a
124             subroutine. The named variables will be captured as closures in the generated
125             subroutine, using L<Eval::Closure>.
126              
127             It should be very rare to need to set this in the constructor. It's more likely
128             that a special type subclass would need to provide values that it generates
129             internally.
130              
131             If you do set this, you are responsible for generating variable names that
132             won't clash with anything else in the inlined code.
133              
134             This parameter defaults to an empty hash reference.
135              
136             =item * message_generator => sub { ... }
137              
138             A subroutine to generate an error message when the type check fails. The
139             default message says something like "Validation failed for type named Int
140             declared in package Specio::Library::Builtins
141             (.../Specio/blib/lib/Specio/Library/Builtins.pm) at line 147 in sub named
142             (eval) with value 1.1".
143              
144             You can override this to provide something more specific about the way the type
145             failed.
146              
147             The subroutine you provide will be called as a subroutine, I<not as a method>,
148             with two arguments. The first is the description of the type (the bit in the
149             message above that starts with "type named Int ..." and ends with "... in sub
150             named (eval)". This description says what the thing is and where it was
151             defined.
152              
153             The second argument is the value that failed the type check, after any
154             coercions that might have been applied.
155              
156             You can also pass this option with the key C<message> in the parameter list.
157              
158             =item * declared_at => $declared_at
159              
160             This parameter must be a L<Specio::DeclaredAt> object.
161              
162             This parameter is required.
163              
164             =back
165              
166             It is possible to create a type without a constraint of its own.
167              
168             =head2 $type->name
169              
170             Returns the name of the type as it was passed the constructor.
171              
172             =head2 $type->parent
173              
174             Returns the parent type passed to the constructor. If the type has no parent
175             this returns C<undef>.
176              
177             =head2 $type->is_anon
178              
179             Returns false for named types, true otherwise.
180              
181             =head2 $type->is_a_type_of($other_type)
182              
183             Given a type object, this returns true if the type this method is called on is
184             a descendant of that type or is that type.
185              
186             =head2 $type->is_same_type_as($other_type)
187              
188             Given a type object, this returns true if the type this method is called on is
189             the same as that type.
190              
191             =head2 $type->coercions
192              
193             Returns a list of L<Specio::Coercion> objects which belong to this constraint.
194              
195             =head2 $type->coercion_from_type($name)
196              
197             Given a type name, this method returns a L<Specio::Coercion> object which
198             coerces from that type, if such a coercion exists.
199              
200             =head2 $type->validate_or_die($value)
201              
202             This method does nothing if the value is valid. If it is not, it throws a
203             L<Specio::Exception>.
204              
205             =head2 $type->value_is_valid($value)
206              
207             Returns true or false depending on whether the C<$value> passes the type
208             constraint.
209              
210             =head2 $type->has_real_constraint
211              
212             This returns true if the type was created with a C<constraint> or
213             C<inline_generator> parameter. This is used internally to skip type checks for
214             types that don't actually implement a constraint.
215              
216             =head2 $type->description
217              
218             This returns a string describing the type. This includes the type's name and
219             where it was declared, so you end up with something like C<'type named Foo
220             declared in package My::Lib (lib/My/Lib.pm) at line 42'>. If the type is
221             anonymous the name will be "anonymous type".
222              
223             =head2 $type->id
224              
225             This is a unique id for the type as a string. This is useful if you need to
226             make a hash key based on a type, for example. This should be treated as an
227             essentially arbitrary and opaque string, and could change at any time in the
228             future. If you want something human-readable, use the C<< $type->description >>
229             method.
230              
231             =head2 $type->add_coercion($coercion)
232              
233             This adds a new L<Specio::Coercion> to the type. If the type already has a
234             coercion from the same type as the new coercion, it will throw an error.
235              
236             =head2 $type->has_coercion_from_type($other_type)
237              
238             This method returns true if the type can coerce from the other type.
239              
240             =head2 $type->coerce_value($value)
241              
242             This attempts to coerce a value into a new value that matches the type. It
243             checks all of the type's coercions. If it finds one which has a "from" type
244             that accepts the value, it runs the coercion and returns the new value.
245              
246             If it cannot find a matching coercion it returns the original value.
247              
248             =head2 $type->inline_coercion_and_check($var)
249              
250             Given a variable name, this returns a string of code and an environment hash
251             that implements all of the type's coercions as well as the type check itself.
252              
253             This will throw an exception unless both the type and all of its coercions are
254             inlinable.
255              
256             The generated code will throw a L<Specio::Exception> if the type constraint
257             fails. If the constraint passes, then the generated code returns the (possibly
258             coerced) value.
259              
260             The return value is a two-element list. The first element is the code. The
261             second is a hash reference containing variables which need to be in scope for
262             the code to work. This is intended to be passed to L<Eval::Closure>'s
263             C<eval_closure> subroutine.
264              
265             The returned code is a single C<do { }> block without a terminating semicolon.
266              
267             =head2 $type->inline_assert($var)
268              
269             Given a variable name, this generates code that implements the constraint and
270             throws an exception if the variable does not pass the constraint.
271              
272             The return value is a two-element list. The first element is the code. The
273             second is a hash reference containing variables which need to be in scope for
274             the code to work. This is intended to be passed to L<Eval::Closure>'s
275             C<eval_closure> subroutine.
276              
277             =head2 $type->inline_check($var)
278              
279             Given a variable name, this returns a string of code that implements the
280             constraint. If the type is not inlinable, this method throws an error.
281              
282             =head2 $type->inline_coercion($var)
283              
284             Given a variable name, this returns a string of code and an environment hash
285             that implements all of the type's coercions. I<It does not check that the
286             resulting value is valid.>
287              
288             This will throw an exception unless all of the type's coercions are inlinable.
289              
290             The return value is a two-element list. The first element is the code. The
291             second is a hash reference containing variables which need to be in scope for
292             the code to work. This is intended to be passed to L<Eval::Closure>'s
293             C<eval_closure> subroutine.
294              
295             The returned code is a single C<do { }> block without a terminating semicolon.
296              
297             =head2 $type->inline_environment()
298              
299             This returns a hash defining the variables that need to be closed over when
300             inlining the type. The keys are full variable names like C<'$foo'> or
301             C<'@bar'>. The values are I<references> to a variable of the matching type.
302              
303             =head2 $type->coercion_sub
304              
305             This method returns a sub ref that takes a single argument and applied all
306             relevant coercions to it. This sub ref will use L<Sub::Quote> if all the type's
307             coercions are inlinable.
308              
309             This method exists primarily for the benefit of L<Moo>.
310              
311             =head1 OVERLOADING
312              
313             All constraints implement the following overloads:
314              
315             =head2 Subroutine De-referencing
316              
317             This is done for the benefit of L<Moo>. The returned subroutine uses
318             L<Sub::Quote> if the type constraint is inlinable.
319              
320             =head2 Stringification
321              
322             For non-anonymous types, this will be the type's name. For anonymous types, a
323             string like "__ANON__(Str)" is generated. However, this string should not be
324             expected to be stable across releases, so don't use it for things like equality
325             checks!
326              
327             =head2 Boolification
328              
329             This always returns true.
330              
331             =head2 String Equality (eq)
332              
333             This calls C<< $type->is_same_type_as($other) >> to compare the two types.
334              
335             =head1 ROLES
336              
337             This role does the L<Specio::Constraint::Role::Interface> and
338             L<Specio::Role::Inlinable> roles.
339              
340             =head1 SUPPORT
341              
342             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
343              
344             =head1 SOURCE
345              
346             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
347              
348             =head1 AUTHOR
349              
350             Dave Rolsky <autarch@urth.org>
351              
352             =head1 COPYRIGHT AND LICENSE
353              
354             This software is Copyright (c) 2012 - 2022 by Dave Rolsky.
355              
356             This is free software, licensed under:
357              
358             The Artistic License 2.0 (GPL Compatible)
359              
360             The full text of the license can be found in the
361             F<LICENSE> file included with this distribution.
362              
363             =cut