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