File Coverage

blib/lib/Specio/Library/Structured.pm
Criterion Covered Total %
statement 42 42 100.0
branch n/a
condition n/a
subroutine 16 16 100.0
pod 0 2 0.0
total 58 60 96.6


line stmt bran cond sub pod time code
1             package Specio::Library::Structured;
2              
3 3     3   1467 use strict;
  3         7  
  3         84  
4 3     3   14 use warnings;
  3         9  
  3         179  
5              
6             our $VERSION = '0.46';
7              
8 3     3   18 use parent 'Specio::Exporter';
  3         5  
  3         18  
9              
10 3     3   189 use Carp qw( confess );
  3         5  
  3         175  
11 3     3   21 use List::Util ();
  3         6  
  3         56  
12 3     3   14 use Scalar::Util qw( blessed );
  3         13  
  3         138  
13 3     3   1229 use Specio::Constraint::Structurable;
  3         8  
  3         94  
14 3     3   19 use Specio::Declare;
  3         22  
  3         19  
15 3     3   16 use Specio::Library::Builtins;
  3         6  
  3         17  
16 3     3   1329 use Specio::Library::Structured::Dict;
  3         9  
  3         78  
17 3     3   1212 use Specio::Library::Structured::Map;
  3         10  
  3         79  
18 3     3   1243 use Specio::Library::Structured::Tuple;
  3         9  
  3         87  
19 3     3   17 use Specio::TypeChecks qw( does_role );
  3         6  
  3         572  
20              
21             ## no critic (Variables::ProtectPrivateVars)
22             declare(
23             'Dict',
24             type_class => 'Specio::Constraint::Structurable',
25             parent => Specio::Library::Structured::Dict->parent,
26             inline => \&Specio::Library::Structured::Dict::_inline,
27             parameterization_args_builder =>
28             \&Specio::Library::Structured::Dict::_parameterization_args_builder,
29             name_builder => \&Specio::Library::Structured::Dict::_name_builder,
30             structured_inline_generator =>
31             \&Specio::Library::Structured::Dict::_structured_inline_generator,
32             );
33              
34             declare(
35             'Map',
36             type_class => 'Specio::Constraint::Structurable',
37             parent => Specio::Library::Structured::Map->parent,
38             inline => \&Specio::Library::Structured::Map::_inline,
39             parameterization_args_builder =>
40             \&Specio::Library::Structured::Map::_parameterization_args_builder,
41             name_builder => \&Specio::Library::Structured::Map::_name_builder,
42             structured_inline_generator =>
43             \&Specio::Library::Structured::Map::_structured_inline_generator,
44             );
45              
46             declare(
47             'Tuple',
48             type_class => 'Specio::Constraint::Structurable',
49             parent => Specio::Library::Structured::Tuple->parent,
50             inline => \&Specio::Library::Structured::Tuple::_inline,
51             parameterization_args_builder =>
52             \&Specio::Library::Structured::Tuple::_parameterization_args_builder,
53             name_builder => \&Specio::Library::Structured::Tuple::_name_builder,
54             structured_inline_generator =>
55             \&Specio::Library::Structured::Tuple::_structured_inline_generator,
56             );
57             ## use critic
58              
59             sub optional {
60 5     5 0 23 return { optional => shift };
61             }
62              
63             sub slurpy {
64 1     1 0 5 return { slurpy => shift };
65             }
66              
67             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
68 3     3   12 sub _also_export {qw( optional slurpy )}
69             ## use critic
70              
71             1;
72              
73             # ABSTRACT: Structured types for Specio (Dict, Map, Tuple)
74              
75             __END__
76              
77             =pod
78              
79             =encoding UTF-8
80              
81             =head1 NAME
82              
83             Specio::Library::Structured - Structured types for Specio (Dict, Map, Tuple)
84              
85             =head1 VERSION
86              
87             version 0.46
88              
89             =head1 SYNOPSIS
90              
91             use Specio::Library::Builtins;
92             use Specio::Library::String;
93             use Specio::Library::Structured;
94              
95             my $map = t(
96             'Map',
97             of => {
98             key => t('NonEmptyStr'),
99             value => t('Int'),
100             },
101             );
102             my $tuple = t(
103             'Tuple',
104             of => [ t('Str'), t('Num') ],
105             );
106             my $dict = t(
107             'Dict',
108             of => {
109             kv => {
110             name => t('Str'),
111             age => t('Int'),
112             },
113             },
114             );
115              
116             =head1 DESCRIPTION
117              
118             B<This particular library should be considered in an alpha state. The syntax
119             for defining structured types may change, as well as some of the internals of
120             its implementation.>
121              
122             This library provides a set of structured types for Specio, C<Dict>, C<Map>,
123             and C<Tuple>. This library also exports two helper subs used for some types,
124             C<optional> and C<slurpy>.
125              
126             All structured types are parameterized by calling C<< t( 'Type Name', of =>
127             ... ) >>. The arguments passed after C<of> vary for each type.
128              
129             =head2 Dict
130              
131             A C<Dict> is a hashref with a well-defined set of keys and types for those
132             key.
133              
134             The argument passed to C<of> should be a single hashref. That hashref must
135             contain a C<kv> key defining the expected keys and the types for their
136             values. This C<kv> value is itself a hashref. If a key/value pair is optional,
137             use C<optional> around the I<type> for that key:
138              
139             my $person = t(
140             'Dict',
141             of => {
142             kv => {
143             first => t('NonEmptyStr'),
144             middle => optional( t('NonEmptyStr') ),
145             last => t('NonEmptyStr'),
146             },
147             },
148             );
149              
150             If a key is optional, then it can be omitted entirely, but if it passed then
151             it's type will be checked, so it cannot just be set to C<undef>.
152              
153             You can also pass a C<slurpy> key. If this is passed, then the C<Dict> will
154             allow other, unknown keys, as long as they match the specified type:
155              
156             my $person = t(
157             'Dict',
158             of => {
159             kv => {
160             first => t('NonEmptyStr'),
161             middle => optional( t('NonEmptyStr') ),
162             last => t('NonEmptyStr'),
163             },
164             slurpy => t('Int'),
165             },
166             );
167              
168             =head2 Map
169              
170             A C<Map> is a hashref with specified types for its keys and values, but no
171             well-defined key names.
172              
173             The argument passed to C<of> should be a single hashref with two keys, C<key>
174             and C<value>. The type for the C<key> will typically be some sort of key, but
175             if you're using a tied hash or an object with hash overloading it could
176             conceivably be any sort of value.
177              
178             =head2 Tuple
179              
180             A C<Tuple> is an arrayref with a fixed set of members in a specific order.
181              
182             The argument passed to C<of> should be a single arrayref consisting of
183             types. You can mark a slot in the C<Tuple> as optional by wrapping the type in
184             a call to C<optional>:
185              
186             my $record = t(
187             'Tuple',
188             of => [
189             t('PositiveInt'),
190             t('Str'),
191             optional( t('Num') ),
192             optional( t('Num') ),
193             ],
194             );
195              
196             You can have as many C<optional> elements as you want, but they must always
197             come in sequence at the end of the tuple definition. You cannot interleave
198             required and optional elements.
199              
200             You can also make the Tuple accept an arbitrary number of values by wrapping
201             the last type in a call to C<slurpy>:
202              
203             my $record = t(
204             'Tuple',
205             of => [
206             t('PositiveInt'),
207             t('Str'),
208             slurpy( t('Num') ),
209             ],
210             );
211              
212             In this case, the C<Tuple> will require the first two elements and then allow
213             any number (including zero) of C<Num> elements.
214              
215             You cannot mix C<optional> and C<slurpy> in a C<Tuple> definition.
216              
217             =for Pod::Coverage optional slurpy
218              
219             =head1 LIMITATIONS
220              
221             Currently all structured types require that the types they are structured with
222             can be inlined. This may change in the future, but inlining all your types is
223             a really good idea, so you should do that anyway.
224              
225             =head1 SUPPORT
226              
227             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
228              
229             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
230              
231             =head1 SOURCE
232              
233             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
234              
235             =head1 AUTHOR
236              
237             Dave Rolsky <autarch@urth.org>
238              
239             =head1 COPYRIGHT AND LICENSE
240              
241             This software is Copyright (c) 2012 - 2020 by Dave Rolsky.
242              
243             This is free software, licensed under:
244              
245             The Artistic License 2.0 (GPL Compatible)
246              
247             The full text of the license can be found in the
248             F<LICENSE> file included with this distribution.
249              
250             =cut