• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

dev-bin/H29-Jan-2021-2013

git/H29-Jan-2021-4429

lib/H29-Jan-2021-10,5914,883

t/H29-Jan-2021-5,7795,068

xt/H29-Jan-2021-581493

CODE_OF_CONDUCT.mdH A D29-Jan-20213.2 KiB7656

CONTRIBUTING.mdH A D29-Jan-20214.1 KiB11176

ChangesH A D29-Jan-202111.9 KiB407232

INSTALLH A D29-Jan-20212.2 KiB7346

LICENSEH A D29-Jan-20218.8 KiB208154

MANIFESTH A D29-Jan-20212.6 KiB117116

META.jsonH A D29-Jan-202144.9 KiB1,3501,348

META.ymlH A D29-Jan-202129.1 KiB1,0111,010

Makefile.PLH A D29-Jan-20213.4 KiB133115

README.mdH A D29-Jan-202115.6 KiB456315

TODO.mdH A D29-Jan-20212.8 KiB8353

azure-pipelines.ymlH A D29-Jan-2021725 3226

cpanfileH A D29-Jan-20212.4 KiB8276

dist.iniH A D29-Jan-2021815 4135

perlcriticrcH A D29-Jan-20211.9 KiB7149

perltidyrcH A D29-Jan-2021301 2322

precious.tomlH A D29-Jan-20211.5 KiB6457

README.md

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