File Coverage

blib/lib/List/Objects/Types.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 32 32 100.0


line stmt bran cond sub pod time code
1             package List::Objects::Types;
2             $List::Objects::Types::VERSION = '2.001001';
3 3     3   247492 use strict; use warnings;
  3     3   6  
  3         69  
  3         9  
  3         3  
  3         67  
4              
5 3     3   10 use List::Util ();
  3         3  
  3         40  
6              
7 3     3   9 use Type::Library -base;
  3         3  
  3         15  
8 3     3   1756 use Type::Utils -all;
  3         9248  
  3         24  
9 3     3   5224 use Types::Standard -types;
  3         4  
  3         11  
10 3     3   7051 use Types::TypeTiny ();
  3         5  
  3         37  
11              
12 3     3   1226 use List::Objects::WithUtils;
  3         6131  
  3         15  
13              
14             # FIXME reorg wrt Immutable types;
15             # ::WithUtils needs v3 role reorg wrt moving common methods
16             # -> declare ArrayObj as ImmutableArray & HashObj as ImmutableHash
17              
18             declare ArrayObj =>
19             as ConsumerOf[ 'List::Objects::WithUtils::Role::Array' ];
20              
21             coerce ArrayObj =>
22             from ArrayRef() => via { array(@$_) };
23              
24              
25             declare ImmutableArray =>
26             as ArrayObj(),
27             where { $_->does('List::Objects::WithUtils::Role::Array::Immutable') },
28             inline_as {
29             (undef, qq[$_->does('List::Objects::WithUtils::Role::Array::Immutable')])
30             };
31              
32             coerce ImmutableArray =>
33             from ArrayRef() => via { immarray(@$_) },
34             from ArrayObj() => via { immarray($_->all) };
35              
36              
37             declare TypedArray =>
38             as ConsumerOf[ 'List::Objects::WithUtils::Role::Array::Typed' ],
39             constraint_generator => sub {
40             my $param = Types::TypeTiny::to_TypeTiny(shift);
41             sub { $_->type->equals($param) }
42             },
43             coercion_generator => sub {
44             my ($parent, $child, $param) = @_;
45             my $c = Type::Coercion->new(type_constraint => $child);
46             if ($param->has_coercion) {
47             my $inner = $param->coercion;
48             $c->add_type_coercions(
49             ArrayRef() => sub { array_of($param, map {; $inner->coerce($_) } @$_) },
50             ArrayObj() => sub { array_of($param, map {; $inner->coerce($_) } $_->all) },
51             );
52             } else {
53             $c->add_type_coercions(
54             ArrayRef() => sub { array_of($param, @$_) },
55             ArrayObj() => sub { array_of($param, $_->all) },
56             );
57             }
58              
59             $c->freeze
60             };
61              
62             declare ImmutableTypedArray =>
63             as InstanceOf[ 'List::Objects::WithUtils::Array::Immutable::Typed' ],
64             constraint_generator => sub {
65             my $param = Types::TypeTiny::to_TypeTiny(shift);
66             sub { $_->type->is_a_type_of($param) }
67             },
68             coercion_generator => sub {
69             my ($parent, $child, $param) = @_;
70             my $c = Type::Coercion->new( type_constraint => $child );
71             if ($param->has_coercion) {
72             my $inner = $param->coercion;
73             $c->add_type_coercions(
74             ArrayRef() => sub {
75             immarray_of($param, map {; $inner->coerce($_) } @$_)
76             },
77             ArrayObj() => sub {
78             immarray_of($param, map {; $inner->coerce($_) } $_->all)
79             },
80             );
81             } else {
82             $c->add_type_coercions(
83             ArrayRef() => sub { immarray_of($param, @$_) },
84             ArrayObj() => sub { immarray_of($param, $_->all) },
85             );
86             }
87             };
88              
89             declare HashObj =>
90             as ConsumerOf[ 'List::Objects::WithUtils::Role::Hash' ];
91              
92             coerce HashObj =>
93             from HashRef() => via { hash(%$_) };
94              
95              
96             declare ImmutableHash =>
97             as HashObj(),
98             where { $_->does('List::Objects::WithUtils::Role::Hash::Immutable') },
99             inline_as {
100             (undef, qq[$_->does('List::Objects::WithUtils::Role::Hash::Immutable')])
101             };
102              
103             coerce ImmutableHash =>
104             from HashRef() => via { immhash(%$_) },
105             from HashObj() => via { immhash($_->export) };
106              
107              
108             declare InflatedHash =>
109             as InstanceOf['List::Objects::WithUtils::Hash::Inflated'],
110             constraint_generator => sub {
111             my @params = @_;
112             sub {
113             Scalar::Util::blessed $_
114             and not List::Util::first { !$_[0]->can($_) } @params
115             }
116             };
117              
118             coerce InflatedHash =>
119             from HashRef() => via { hash(%$_)->inflate },
120             from HashObj() => via { $_->inflate };
121              
122              
123             declare TypedHash =>
124             as ConsumerOf[ 'List::Objects::WithUtils::Role::Hash::Typed' ],
125             constraint_generator => sub {
126             my $param = Types::TypeTiny::to_TypeTiny(shift);
127             sub { $_->type->equals($param) }
128             },
129             coercion_generator => sub {
130             my ($parent, $child, $param) = @_;
131             my $c = Type::Coercion->new(type_constraint => $child);
132             if ($param->has_coercion) {
133             my $inner = $param->coercion;
134             $c->add_type_coercions(
135             HashRef() => sub {
136             my %old = %$_; my %new;
137             @new{keys %old} = map {; $inner->coerce($_) } values %old;
138             hash_of($param, %new)
139             },
140             HashObj() => sub {
141             my %old = $_->export; my %new;
142             @new{keys %old} = map {; $inner->coerce($_) } values %old;
143             hash_of($param, %new)
144             },
145             );
146             } else {
147             $c->add_type_coercions(
148             HashRef() => sub { hash_of($param, %$_) },
149             HashObj() => sub { hash_of($param, $_->export) },
150             );
151             }
152              
153            
154             $c->freeze
155             };
156              
157              
158             declare ImmutableTypedHash =>
159             as InstanceOf[ 'List::Objects::WithUtils::Hash::Immutable::Typed' ],
160             constraint_generator => sub {
161             my $param = Types::TypeTiny::to_TypeTiny(shift);
162             sub { $_->type->is_a_type_of($param) }
163             },
164             coercion_generator => sub {
165             my ($parent, $child, $param) = @_;
166             my $c = Type::Coercion->new(type_constraint => $child);
167             if ($param->has_coercion) {
168             my $inner = $param->coercion;
169             $c->add_type_coercions(
170             HashRef() => sub {
171             my %old = %$_; my %new;
172             @new{keys %old} = map {; $inner->coerce($_) } values %old;
173             immhash_of($param, %new)
174             },
175             HashObj() => sub {
176             my %old = $_->export; my %new;
177             @new{keys %old} = map {; $inner->coerce($_) } values %old;
178             immhash_of($param, %new)
179             },
180             );
181             } else {
182             $c->add_type_coercions(
183             HashRef() => sub { immhash_of($param, %$_) },
184             HashObj() => sub { immhash_of($param, $_->export) },
185             );
186             }
187              
188            
189             $c->freeze
190             };
191              
192             1;
193              
194              
195             =pod
196              
197             =head1 NAME
198              
199             List::Objects::Types - Type::Tiny-based types for List::Objects::WithUtils
200              
201             =head1 SYNOPSIS
202              
203             package Foo;
204              
205             use List::Objects::Types -all;
206             use List::Objects::WithUtils;
207             use Moo 2; # version 2+ for better Type::Tiny support
208              
209             has my_array => (
210             is => 'ro',
211             isa => ArrayObj,
212             default => sub { array }
213             );
214              
215             has static_array => (
216             is => 'ro',
217             isa => ImmutableArray,
218             coerce => 1,
219             default => sub { [qw/ foo bar /] }
220             );
221              
222             has my_hash => (
223             is => 'ro',
224             isa => HashObj,
225             coerce => 1,
226             # Coercible from a plain HASH:
227             default => sub { +{} }
228             );
229              
230             use Types::Standard 'Int', 'Num';
231             has my_ints => (
232             is => 'ro',
233             # Nums added to this array_of(Int) are coerced to Ints:
234             isa => TypedArray[ Int->plus_coercions(Num, 'int($_)') ],
235             coerce => 1,
236             default => sub { [1, 2, 3.14] }
237             );
238              
239             =head1 DESCRIPTION
240              
241             A set of L-based types & coercions matching the list objects found
242             in L.
243              
244             =head3 ArrayObj
245              
246             An object that consumes L.
247              
248             Can be coerced from a plain ARRAY; a shallow copy is performed.
249              
250             =head3 HashObj
251              
252             An object that consumes L.
253              
254             Can be coerced from a plain HASH; a shallow copy is performed.
255              
256             =head3 ImmutableArray
257              
258             An object that consumes L.
259              
260             Can be coerced from a plain ARRAY or an L; a shallow copy is performed.
261              
262             =head3 TypedArray
263              
264             An object that consumes L.
265              
266             Not coercible.
267              
268             =head3 TypedArray[`a]
269              
270             TypedArray can be parameterized with another type constraint specifying the
271             type of its values.
272              
273             Can be coerced from a plain ARRAY or an L; a shallow copy is
274             performed. If the parameter also has a coercion, this will be applied
275             to each item in the new array.
276              
277             In versions prior to C, subtypes were permitted; C<< TypedArray[Num] >>
278             would accept C<< array_of(Num, 1, 2, 3.14) >> as expected, but also C<<
279             array_of(Int, 1, 2, 3) >> as C is a subtype C. This could lead to
280             unexpected behavior. As of C, this has been corrected; the latter
281             would be rejected without an appropriate coercion (for example, specifying C<<
282             coerce => 1 >> in a Moo(se) attribute along these lines will coerce the
283             C-typed array object to C)
284              
285             (The C directory that comes with this distribution contains some
286             examples of parameterized & coercible TypedArrays.)
287              
288             =head3 ImmutableTypedArray
289              
290             An object that isa L.
291              
292             Not coercible.
293              
294             =head3 ImmutableTypedArray[`a]
295              
296             ImmutableTypedArray can be parameterized with another type constraint, like
297             L (however unlike its mutable counterpart, subtypes are
298             accepted).
299              
300             Can be coerced from a plain ARRAY or an L.
301              
302             =head3 TypedHash
303              
304             An object that consumes L.
305              
306             Not coercible.
307              
308             =head3 TypedHash[`a]
309              
310             TypedHash can be parameterized with another type constraint, like
311             L.
312              
313             Can be coerced from a plain HASH or a L. If the parameter also has a
314             coercion, this will be applied to each value in the new hash.
315              
316             =head3 ImmutableTypedHash
317              
318             An object that isa L.
319              
320             Not coercible.
321              
322             =head3 ImmutableTypedHash[`a]
323              
324             ImmutableTypedHash can be parameterized with another type constraint, like
325             L.
326              
327             Can be coerced from a plain HASH or an L.
328              
329             =head3 InflatedHash
330              
331             An object that isa L.
332              
333             Can be coerced from a plain HASH or an L.
334              
335             (Available from v1.2.1)
336              
337             =head3 InflatedHash[`a]
338              
339             InflatedHash can be parameterized with a list of methods expected to be
340             available.
341              
342             (Available from v1.3.1)
343              
344             =head2 SEE ALSO
345              
346             L for integration with L class-building sugar.
347              
348             L for more on the relevant list objects.
349              
350             L for more on type methods & overloads.
351              
352             L for a set of useful base types.
353              
354             L for details on importing types.
355              
356             =head1 AUTHOR
357              
358             Jon Portnoy with significant contributions from Toby
359             Inkster (CPAN: TOBYINK)
360              
361             =cut