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 4     4   2226 use strict;
  4         15  
  4         129  
4 4     4   26 use warnings;
  4         10  
  4         188  
5              
6             our $VERSION = '0.47';
7              
8 4     4   21 use parent 'Specio::Exporter';
  4         10  
  4         32  
9              
10 4     4   370 use Carp qw( confess );
  4         10  
  4         240  
11 4     4   25 use List::Util ();
  4         10  
  4         139  
12 4     4   25 use Scalar::Util qw( blessed );
  4         8  
  4         256  
13 4     4   1882 use Specio::Constraint::Structurable;
  4         11  
  4         143  
14 4     4   28 use Specio::Declare;
  4         8  
  4         31  
15 4     4   28 use Specio::Library::Builtins;
  4         14  
  4         25  
16 4     4   2062 use Specio::Library::Structured::Dict;
  4         12  
  4         130  
17 4     4   2009 use Specio::Library::Structured::Map;
  4         13  
  4         133  
18 4     4   2080 use Specio::Library::Structured::Tuple;
  4         13  
  4         147  
19 4     4   28 use Specio::TypeChecks qw( does_role );
  4         9  
  4         1005  
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 27 return { optional => shift };
61             }
62              
63             sub slurpy {
64 1     1 0 9 return { slurpy => shift };
65             }
66              
67             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
68 4     4   19 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.47
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 key.
132              
133             The argument passed to C<of> should be a single hashref. That hashref must
134             contain a C<kv> key defining the expected keys and the types for their values.
135             This C<kv> value is itself a hashref. If a key/value pair is optional, use
136             C<optional> around the I<type> for that key:
137              
138             my $person = t(
139             'Dict',
140             of => {
141             kv => {
142             first => t('NonEmptyStr'),
143             middle => optional( t('NonEmptyStr') ),
144             last => t('NonEmptyStr'),
145             },
146             },
147             );
148              
149             If a key is optional, then it can be omitted entirely, but if it passed then
150             it's type will be checked, so it cannot just be set to C<undef>.
151              
152             You can also pass a C<slurpy> key. If this is passed, then the C<Dict> will
153             allow other, unknown keys, as long as they match the specified type:
154              
155             my $person = t(
156             'Dict',
157             of => {
158             kv => {
159             first => t('NonEmptyStr'),
160             middle => optional( t('NonEmptyStr') ),
161             last => t('NonEmptyStr'),
162             },
163             slurpy => t('Int'),
164             },
165             );
166              
167             =head2 Map
168              
169             A C<Map> is a hashref with specified types for its keys and values, but no
170             well-defined key names.
171              
172             The argument passed to C<of> should be a single hashref with two keys, C<key>
173             and C<value>. The type for the C<key> will typically be some sort of key, but
174             if you're using a tied hash or an object with hash overloading it could
175             conceivably be any sort of value.
176              
177             =head2 Tuple
178              
179             A C<Tuple> is an arrayref with a fixed set of members in a specific order.
180              
181             The argument passed to C<of> should be a single arrayref consisting of types.
182             You can mark a slot in the C<Tuple> as optional by wrapping the type in a call
183             to C<optional>:
184              
185             my $record = t(
186             'Tuple',
187             of => [
188             t('PositiveInt'),
189             t('Str'),
190             optional( t('Num') ),
191             optional( t('Num') ),
192             ],
193             );
194              
195             You can have as many C<optional> elements as you want, but they must always
196             come in sequence at the end of the tuple definition. You cannot interleave
197             required and optional elements.
198              
199             You can also make the Tuple accept an arbitrary number of values by wrapping
200             the last type in a call to C<slurpy>:
201              
202             my $record = t(
203             'Tuple',
204             of => [
205             t('PositiveInt'),
206             t('Str'),
207             slurpy( t('Num') ),
208             ],
209             );
210              
211             In this case, the C<Tuple> will require the first two elements and then allow
212             any number (including zero) of C<Num> elements.
213              
214             You cannot mix C<optional> and C<slurpy> in a C<Tuple> definition.
215              
216             =for Pod::Coverage optional slurpy
217              
218             =head1 LIMITATIONS
219              
220             Currently all structured types require that the types they are structured with
221             can be inlined. This may change in the future, but inlining all your types is a
222             really good idea, so you should do that anyway.
223              
224             =head1 SUPPORT
225              
226             Bugs may be submitted at L<https://github.com/houseabsolute/Specio/issues>.
227              
228             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
229              
230             =head1 SOURCE
231              
232             The source code repository for Specio can be found at L<https://github.com/houseabsolute/Specio>.
233              
234             =head1 AUTHOR
235              
236             Dave Rolsky <autarch@urth.org>
237              
238             =head1 COPYRIGHT AND LICENSE
239              
240             This software is Copyright (c) 2012 - 2021 by Dave Rolsky.
241              
242             This is free software, licensed under:
243              
244             The Artistic License 2.0 (GPL Compatible)
245              
246             The full text of the license can be found in the
247             F<LICENSE> file included with this distribution.
248              
249             =cut