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