File Coverage

blib/lib/Specio.pm
Criterion Covered Total %
statement 17 18 94.4
branch 1 2 50.0
condition n/a
subroutine 6 6 100.0
pod n/a
total 24 26 92.3


line stmt bran cond sub pod time code
1             package Specio;
2              
3 32     32   208 use strict;
  32         86  
  32         1199  
4 32     32   177 use warnings;
  32         1617  
  32         1507  
5              
6 32     32   631 use 5.008;
  32         107  
7              
8             our $VERSION = '0.53';
9              
10 32     32   15444 use Module::Implementation;
  32         146300  
  32         1293  
11              
12 32     32   205 use Exporter qw( import );
  32         52  
  32         2675  
13              
14             BEGIN {
15             # This env var exists for the benefit of the PurePerlTests dzil plugin, which only knows how to
16             # set an env var to a true value.
17 32 50   32   218 if ( $ENV{SPECIO_TEST_PP} ) {
18             ## no critic (Variables::RequireLocalizedPunctuationVars)
19 0         0 $ENV{SPECIO_IMPLEMENTATION} = 'PP';
20             }
21              
22 32         176 my $loader = Module::Implementation::build_loader_sub(
23             implementations => [ 'XS', 'PP' ],
24             symbols => ['_clone'],
25             );
26 32         1011 $loader->();
27             }
28              
29             # It's a bit weird to put this in the root module, but this way the env var that
30             # Module::Implementation::build_loader_sub uses will be named "SPECIO_IMPLEMENTATION". That way, if
31             # in the future there are other optional XS components besides the Clone implementation, we don't
32             # end up with a bunch of different env vars.
33             #
34             ## no critic (Modules::ProhibitAutomaticExportation)
35             our @EXPORT = qw( _clone );
36              
37             1;
38              
39             # ABSTRACT: Type constraints and coercions for Perl
40              
41             __END__
42              
43             =pod
44              
45             =encoding UTF-8
46              
47             =head1 NAME
48              
49             Specio - Type constraints and coercions for Perl
50              
51             =head1 VERSION
52              
53             version 0.53
54              
55             =head1 SYNOPSIS
56              
57             package MyApp::Type::Library;
58              
59             use Specio::Declare;
60             use Specio::Library::Builtins;
61              
62             declare(
63             'PositiveInt',
64             parent => t('Int'),
65             inline => sub {
66             $_[0]->parent->inline_check( $_[1] )
67             . ' && ( '
68             . $_[1]
69             . ' > 0 )';
70             },
71             );
72              
73             # or ...
74              
75             declare(
76             'PositiveInt',
77             parent => t('Int'),
78             where => sub { $_[0] > 0 },
79             );
80              
81             declare(
82             'ArrayRefOfPositiveInt',
83             parent => t(
84             'ArrayRef',
85             of => t('PositiveInt'),
86             ),
87             );
88              
89             coerce(
90             'ArrayRefOfPositiveInt',
91             from => t('PositiveInt'),
92             using => sub { [ $_[0] ] },
93             );
94              
95             any_can_type(
96             'Duck',
97             methods => [ 'duck_walk', 'quack' ],
98             );
99              
100             object_isa_type('MyApp::Person');
101              
102             =head1 DESCRIPTION
103              
104             The C<Specio> distribution provides classes for representing type constraints
105             and coercion, along with syntax sugar for declaring them.
106              
107             Note that this is not a proper type system for Perl. Nothing in this
108             distribution will magically make the Perl interpreter start checking a value's
109             type on assignment to a variable. In fact, there's no built-in way to apply a
110             type to a variable at all.
111              
112             Instead, you can explicitly check a value against a type, and optionally coerce
113             values to that type.
114              
115             =head1 WHAT IS A TYPE?
116              
117             At it's core, a type is simply a constraint. A constraint is code that checks a
118             value and returns true or false. Most constraints are represented by
119             L<Specio::Constraint::Simple> objects. However, there are other type constraint
120             classes for specialized kinds of constraints.
121              
122             Types can be named or anonymous, and each type can have a parent type. A type's
123             constraint is optional because sometimes you may want to create a named subtype
124             of some existing type without adding additional constraints.
125              
126             Constraints can be expressed either in terms of a simple subroutine reference
127             or in terms of an inline generator subroutine reference. The former is easier
128             to write but the latter is preferred because it allow for better optimization.
129              
130             A type can also have an optional message generator subroutine reference. You
131             can use this to provide a more intelligent error message when a value does not
132             pass the constraint, though the default message should suffice for most cases.
133              
134             Finally, you can associate a set of coercions with a type. A coercion is a
135             subroutine reference (or inline generator, like constraints), that takes a
136             value of one type and turns it into a value that matches the type the coercion
137             belongs to.
138              
139             =head1 BUILTIN TYPES
140              
141             This distribution ships with a set of builtin types representing the types
142             provided by the Perl interpreter itself. They are arranged in a hierarchy as
143             follows:
144              
145             Item
146             Bool
147             Maybe (of `a)
148             Undef
149             Defined
150             Value
151             Str
152             Num
153             Int
154             ClassName
155             Ref
156             ScalarRef (of `a)
157             ArrayRef (of `a)
158             HashRef (of `a)
159             CodeRef
160             RegexpRef
161             GlobRef
162             FileHandle
163             Object
164              
165             The C<Item> type accepts anything and everything.
166              
167             The C<Bool> type only accepts C<undef>, C<0>, or C<1>.
168              
169             The C<Undef> type only accepts C<undef>.
170              
171             The C<Defined> type accepts anything I<except> C<undef>.
172              
173             The C<Num> and C<Int> types are stricter about numbers than Perl is.
174             Specifically, they do not allow any sort of space in the number, nor do they
175             accept "Nan", "Inf", or "Infinity".
176              
177             The C<ClassName> type constraint checks that the name is valid I<and> that the
178             class is loaded.
179              
180             The C<FileHandle> type accepts either a glob, a scalar filehandle, or anything
181             that isa L<IO::Handle>.
182              
183             All types accept overloaded objects that support the required operation. See
184             below for details.
185              
186             =head2 Overloading
187              
188             Perl's overloading is horribly broken and doesn't make much sense at all.
189              
190             However, unlike Moose, all type constraints allow overloaded objects where they
191             make sense.
192              
193             For types where overloading makes sense, we explicitly check that the object
194             provides the type overloading we expect. We I<do not> simply try to use the
195             object as the type in question and hope it works. This means that these checks
196             effectively ignore the C<fallback> setting for the overloaded object. In other
197             words, an object that overloads stringification will not pass the C<Bool> type
198             check unless it I<also> overloads boolification.
199              
200             Most types do not check that the overloaded method actually returns something
201             that matches the constraint. This may change in the future.
202              
203             The C<Bool> type accepts an object that implements C<bool> overloading.
204              
205             The C<Str> type accepts an object that implements string (C<q{""}>)
206             overloading.
207              
208             The C<Num> type accepts an object that implements numeric (C<'0+'}>)
209             overloading. The C<Int> type does as well, but it will check that the
210             overloading returns an actual integer.
211              
212             The C<ClassName> type will accept an object with string overloading that
213             returns a class name.
214              
215             To make this all more confusing, the C<Value> type will I<never> accept an
216             object, even though some of its subtypes will.
217              
218             The various reference types all accept objects which provide the appropriate
219             overloading. The C<FileHandle> type accepts an object which overloads
220             globification as long as the returned glob is an open filehandle.
221              
222             =head1 PARAMETERIZABLE TYPES
223              
224             Any type followed by a type parameter C<of `a> in the hierarchy above can be
225             parameterized. The parameter is itself a type, so you can say you want an
226             "ArrayRef of Int", or even an "ArrayRef of HashRef of ScalarRef of ClassName".
227              
228             When they are parameterized, the C<ScalarRef> and C<ArrayRef> types check that
229             the value(s) they refer to match the type parameter. For the C<HashRef> type,
230             the parameter applies to the values (keys are never checked).
231              
232             =head2 Maybe
233              
234             The C<Maybe> type is a special parameterized type. It allows for either
235             C<undef> or a value. All by itself, it is meaningless, since it is equivalent
236             to "Maybe of Item", which is equivalent to Item. When parameterized, it accepts
237             either an C<undef> or the type of its parameter.
238              
239             This is useful for optional attributes or parameters. However, you're probably
240             better off making your code simply not pass the parameter at all This usually
241             makes for a simpler API.
242              
243             =head1 REGISTRIES AND IMPORTING
244              
245             Types are local to each package where they are used. When you "import" types
246             from some other library, you are actually making a copy of that type.
247              
248             This means that a type named "Foo" in one package may not be the same as "Foo"
249             in another package. This has potential for confusion, but it also avoids the
250             magic action at a distance pollution that comes with a global type naming
251             system.
252              
253             The registry is managed internally by the Specio distribution's modules, and is
254             not exposed to your code. To access a type, you always call C<t('TypeName')>.
255              
256             This returns the named type or dies if no such type exists.
257              
258             Because types are always copied on import, it's safe to create coercions on any
259             type. Your coercion from C<Str> to C<Int> will not be seen by any other
260             package, unless that package explicitly imports your C<Int> type.
261              
262             When you import types, you import every type defined in the package you import
263             from. However, you I<can> overwrite an imported type with your own type
264             definition. You I<cannot> define the same type twice internally.
265              
266             =head1 CREATING A TYPE LIBRARY
267              
268             By default, all types created inside a package are invisible to other packages.
269             If you want to create a type library, you need to inherit from
270             L<Specio::Exporter> package:
271              
272             package MyApp::Type::Library;
273              
274             use parent 'Specio::Exporter';
275              
276             use Specio::Declare;
277             use Specio::Library::Builtins;
278              
279             declare(
280             'Foo',
281             parent => t('Str'),
282             where => sub { $_[0] =~ /foo/i },
283             );
284              
285             Now the MyApp::Type::Library package will export a single type named C<Foo>. It
286             I<does not> re-export the types provided by L<Specio::Library::Builtins>.
287              
288             If you want to make your library re-export some other libraries types, you can
289             ask for this explicitly:
290              
291             package MyApp::Type::Library;
292              
293             use parent 'Specio::Exporter';
294              
295             use Specio::Declare;
296             use Specio::Library::Builtins -reexport;
297              
298             declare( 'Foo, ... );
299              
300             Now MyApp::Types::Library exports any types it defines, as well as all the
301             types defined in L<Specio::Library::Builtins>.
302              
303             =head1 DECLARING TYPES
304              
305             Use the L<Specio::Declare> module to declare types. It exports a set of helpers
306             for declaring types. See that module's documentation for more details on these
307             helpers.
308              
309             =head1 USING SPECIO WITH L<Moose>
310              
311             This should just work. Use a Specio type anywhere you'd specify a type.
312              
313             =head1 USING SPECIO WITH L<Moo>
314              
315             Using Specio with Moo is easy. You can pass Specio constraint objects as C<isa>
316             parameters for attributes. For coercions, simply call C<< $type->coercion_sub
317             >>.
318              
319             package Foo;
320              
321             use Specio::Declare;
322             use Specio::Library::Builtins;
323             use Moo;
324              
325             my $str_type = t('Str');
326             has string => (
327             is => 'ro',
328             isa => $str_type,
329             );
330              
331             my $ucstr = declare(
332             'UCStr',
333             parent => t('Str'),
334             where => sub { $_[0] =~ /^[A-Z]+$/ },
335             );
336              
337             coerce(
338             $ucstr,
339             from => t('Str'),
340             using => sub { return uc $_[0] },
341             );
342              
343             has ucstr => (
344             is => 'ro',
345             isa => $ucstr,
346             coerce => $ucstr->coercion_sub,
347             );
348              
349             The subs returned by Specio use L<Sub::Quote> internally and are suitable for
350             inlining.
351              
352             =head1 USING SPECIO WITH OTHER THINGS
353              
354             See L<Specio::Constraint::Simple> for the API that all constraint objects
355             share.
356              
357             =head1 L<Moose>, L<MooseX::Types>, and Specio
358              
359             This module aims to supplant both L<Moose>'s built-in type system (see
360             L<Moose::Util::TypeConstraints> aka MUTC) and L<MooseX::Types>, which attempts
361             to patch some of the holes in the Moose built-in type design.
362              
363             Here are some of the salient differences:
364              
365             =over 4
366              
367             =item * Types names are strings, but they're not global
368              
369             Unlike Moose and MooseX::Types, type names are always local to the current
370             package. There is no possibility of name collision between different modules,
371             so you can safely use short type names.
372              
373             Unlike MooseX::Types, types are strings, so there is no possibility of
374             colliding with existing class or subroutine names.
375              
376             =item * No type auto-creation
377              
378             Types are always retrieved using the C<t()> subroutine. If you pass an unknown
379             name to this subroutine it dies. This is different from Moose and
380             MooseX::Types, which assume that unknown names are class names.
381              
382             =item * Anon types are explicit
383              
384             With L<Moose> and L<MooseX::Types>, you use the same subroutine, C<subtype()>,
385             to declare both named and anonymous types. With Specio, you use C<declare()>
386             for named types and C<anon()> for anonymous types.
387              
388             =item * Class and object types are separate
389              
390             Moose and MooseX::Types have C<class_type> and C<duck_type>. The former type
391             requires an object, while the latter accepts a class name or object.
392              
393             With Specio, the distinction between accepting an object versus object or class
394             is explicit. There are six declaration helpers, C<object_can_type>,
395             C<object_does_type>, C<object_isa_type>, C<any_can_type>, C<any_does_type>, and
396             C<any_isa_type>.
397              
398             =item * Overloading support is baked in
399              
400             Perl's overloading is quite broken but ignoring it makes Moose's type system
401             frustrating to use in many cases.
402              
403             =item * Types can either have a constraint or inline generator, not both
404              
405             Moose and MooseX::Types types can be defined with a subroutine reference as the
406             constraint, an inline generator subroutine, or both. This is purely for
407             backwards compatibility, and it makes the internals more complicated than they
408             need to be.
409              
410             With Specio, a constraint can have I<either> a subroutine reference or an
411             inline generator, not both.
412              
413             =item * Coercions can be inlined
414              
415             I simply never got around to implementing this in Moose.
416              
417             =item * No crazy coercion features
418              
419             Moose has some bizarre (and mostly) undocumented features relating to coercions
420             and parameterizable types. This is a misfeature.
421              
422             =back
423              
424             =head1 OPTIONAL PREREQS
425              
426             There are several optional prereqs that if installed will make this
427             distribution better in some way.
428              
429             =over 4
430              
431             =item * L<Ref::Util>
432              
433             Installing this will speed up a number of type checks for built-in types.
434              
435             =item * L<XString>
436              
437             If this is installed it will be loaded instead of the L<B> module if you have
438             Perl 5.10 or greater. This module is much more memory efficient than loading
439             all of L<B>.
440              
441             =item * L<Sub::Util> or L<Sub::Name>
442              
443             If one of these is installed then stack traces that end up in Specio code will
444             have much better subroutine names for any frames.
445              
446             =back
447              
448             =head1 FORCING PURE PERL MODE
449              
450             For some use cases (notably fatpacking a program), you may want to force Specio
451             to use pure Perl code instead of XS code. This can be done by setting the
452             environment variable C<SPECIO_IMPLEMENTATION> to C<PP>.
453              
454             =head1 WHY THE NAME?
455              
456             This distro was originally called "Type", but that's an awfully generic top
457             level namespace. Specio is Latin for for "look at" and "spec" is the root for
458             the word "species". It's short, relatively easy to type, and not used by any
459             other distro.
460              
461             =head1 SUPPORT
462              
463             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
464              
465             =head1 SOURCE
466              
467             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
468              
469             =head1 DONATIONS
470              
471             If you'd like to thank me for the work I've done on this module, please
472             consider making a "donation" to me via PayPal. I spend a lot of free time
473             creating free software, and would appreciate any support you'd care to offer.
474              
475             Please note that B<I am not suggesting that you must do this> in order for me
476             to continue working on this particular software. I will continue to do so,
477             inasmuch as I have in the past, for as long as it interests me.
478              
479             Similarly, a donation made in this way will probably not make me work on this
480             software much more, unless I get so many donations that I can consider working
481             on free software full time (let's all have a chuckle at that together).
482              
483             To donate, log into PayPal and send money to autarch@urth.org, or use the
484             button at L<https://houseabsolute.com/foss-donations/>.
485              
486             =head1 AUTHOR
487              
488             Dave Rolsky <autarch@urth.org>
489              
490             =head1 CONTRIBUTORS
491              
492             =for stopwords Andrew Rodland Chris White cpansprout Graham Knop Karen Etheridge Vitaly Lipatov
493              
494             =over 4
495              
496             =item *
497              
498             Andrew Rodland <andrewr@vimeo.com>
499              
500             =item *
501              
502             Chris White <chrisw@leehayes.com>
503              
504             =item *
505              
506             cpansprout <cpansprout@gmail.com>
507              
508             =item *
509              
510             Graham Knop <haarg@haarg.org>
511              
512             =item *
513              
514             Karen Etheridge <ether@cpan.org>
515              
516             =item *
517              
518             Vitaly Lipatov <lav@altlinux.ru>
519              
520             =back
521              
522             =head1 COPYRIGHT AND LICENSE
523              
524             This software is Copyright (c) 2012 - 2025 by Dave Rolsky.
525              
526             This is free software, licensed under:
527              
528             The Artistic License 2.0 (GPL Compatible)
529              
530             The full text of the license can be found in the
531             F<LICENSE> file included with this distribution.
532              
533             =cut