File Coverage

lib/MooseX/TypeArray.pm
Criterion Covered Total %
statement 21 52 40.3
branch 4 14 28.5
condition 0 3 0.0
subroutine 6 9 66.6
pod 1 1 100.0
total 32 79 40.5


line stmt bran cond sub pod time code
1 2     2   1841 use strict;
  2         3  
  2         78  
2 2     2   12 use warnings;
  2         4  
  2         114  
3              
4             package MooseX::TypeArray;
5             BEGIN {
6 2     2   153 $MooseX::TypeArray::AUTHORITY = 'cpan:KENTNL';
7             }
8             {
9             $MooseX::TypeArray::VERSION = '0.2.0'; # TRIAL
10             }
11              
12             # ABSTRACT: Create composite types where all subtypes must be satisfied
13              
14              
15 2         22 use Sub::Exporter -setup => {
16             exports => [qw( typearray )],
17             groups => [ default => [qw( typearray )] ],
18 2     2   3891 };
  2         25224  
19              
20             my $sugarmap = {
21              
22             # '' => sub {},
23             'ARRAY' => sub { { name => undef, combining => $_[0], } },
24             'HASH' => sub { { name => undef, %{ $_[0] }, combining => [ @{ $_[0]->{combining} || [] } ], } },
25              
26             # '_string' => sub {},
27             '_string,ARRAY' => sub { { name => $_[0], combining => $_[1], } },
28             '_string,HASH' => sub { { name => $_[0], %{ $_[1] }, combining => [ @{ $_[1]->{combining} || [] } ], } },
29             'ARRAY,HASH' => sub { { name => undef, %{ $_[1] }, combining => [ @{ $_[1]->{combining} || [] }, @{ $_[0] } ], } },
30             '_string,ARRAY,HASH' => sub { { name => $_[0], %{ $_[2] }, combining => [ @{ $_[2]->{combining} || [] }, @{ $_[1] } ], } },
31              
32             };
33              
34             sub _desugar_typearray {
35 10     10   25043 my (@args) = @_;
36 10 100       18 my (@argtypes) = map { ref $_ ? ref $_ : '_string' } @args;
  16         61  
37 10         21 my $signature = join q{,}, @argtypes;
38              
39 10 100       36 if ( exists $sugarmap->{$signature} ) {
40 6         20 return $sugarmap->{$signature}->(@args);
41             }
42 24         68 return __PACKAGE__->_throw_error( 'Unexpected parameters types passed: <'
43             . $signature . '>,' . qq{\n}
44             . 'Expected one from [ '
45 4         12 . ( join q{, }, map { '<' . $_ . '>' } sort keys %{$sugarmap} )
  4         33  
46             . ' ] ' );
47             }
48              
49             sub _check_conflict_names {
50 0     0   0 my ( $name, $package ) = @_;
51 0         0 require Moose::Util::TypeConstraints;
52              
53 0         0 my $type = Moose::Util::TypeConstraints::find_type_constraint($name);
54              
55 0 0 0     0 if ( defined $type and $type->_package_defined_in eq $package ) {
56 0         0 __PACKAGE__->_throw_error( "The type constraint '$name' has already been created in "
57             . $type->_package_defined_in
58             . " and cannot be created again in $package " );
59             }
60 0 0       0 if ( $name !~ /\A[[:word:]:.]+\z/sxm ) {
61 0         0 __PACKAGE__->_throw_error(
62             sprintf q{%s contains invalid characters for a type name. Names can contain alphanumeric character, ":", and "."%s},
63             $name, qq{\n} );
64             }
65 0         0 return 1;
66             }
67              
68             sub _convert_type_names {
69 0     0   0 my ( $name, @types ) = @_;
70 0         0 require Moose::Util::TypeConstraints;
71 0         0 my @out;
72 0         0 for my $type (@types) {
73 0         0 my $translated_type = Moose::Util::TypeConstraints::find_or_parse_type_constraint($type);
74 0 0       0 if ( not $translated_type ) {
75 0         0 __PACKAGE__->_throw_error("Could not locate type constraint ($type) for the TypeArray");
76             }
77 0         0 push @out, $translated_type;
78             }
79 0         0 return @out;
80             }
81              
82             ## no critic ( RequireArgUnpacking )
83              
84              
85             sub typearray {
86 0     0 1 0 my $config = _desugar_typearray(@_);
87              
88 0         0 $config->{package_defined_in} = scalar caller 0;
89              
90 0 0       0 _check_conflict_names( $config->{name}, $config->{package_defined_in} ) if defined $config->{name};
91              
92 0         0 $config->{combining} = [ _convert_type_names( $config->{name}, @{ $config->{combining} } ) ];
  0         0  
93              
94 0         0 require Moose::Meta::TypeConstraint::TypeArray;
95              
96 0         0 my $constraint = Moose::Meta::TypeConstraint::TypeArray->new( %{$config} );
  0         0  
97              
98 0 0       0 if ( defined $config->{name} ) {
99 0         0 require Moose::Util::TypeConstraints;
100 0         0 Moose::Util::TypeConstraints::register_type_constraint($constraint);
101             }
102              
103 0         0 return $constraint;
104              
105             }
106              
107             ## no critic ( RequireArgUnpacking )
108             sub _throw_error {
109 4     4   6 shift;
110 4         1653 require Moose;
111 0           unshift @_, 'Moose';
112 0           goto &Moose::throw_error;
113             }
114              
115             1;
116              
117             __END__
118              
119             =pod
120              
121             =encoding UTF-8
122              
123             =head1 NAME
124              
125             MooseX::TypeArray - Create composite types where all subtypes must be satisfied
126              
127             =head1 VERSION
128              
129             version 0.2.0
130              
131             =head1 SYNOPSIS
132              
133             {
134             package #
135             Foo;
136             use Moose::Util::TypeConstraint;
137             use MooseX::TypeArray;
138             subtype 'Natural',
139             as 'Int',
140             where { $_ > 0 };
141             message { "This number ($_) is not bigger then 0" };
142              
143             subtype 'BiggerThanTen',
144             as 'Int',
145             where { $_ > 10 },
146             message { "This number ($_) is not bigger than ten!" };
147              
148              
149             typearray NaturalAndBiggerThanTen => [ 'Natural', 'BiggerThanTen' ];
150              
151             # or this , which is the same thing.
152              
153             typearray NaturalAndBiggerThanTen => {
154             combining => [qw( Natural BiggerThanTen )],
155             };
156              
157              
158             ...
159              
160             has field => (
161             isa => 'NaturalAndBiggerThanTen',
162             ...
163             );
164              
165             ...
166             }
167             use Try::Tiny;
168             use Data::Dumper qw( Dumper );
169              
170             try {
171             Foo->new( field => 0 );
172             } catch {
173             print Dumper( $_ );
174             #
175             # bless({ errors => {
176             # Natural => "This number (0) is not bigger then 0",
177             # BiggerThanTen => "This number (0) is not bigger than ten!"
178             # }}, 'MooseX::TypeArray::Error' );
179             #
180             print $_;
181              
182             # Validation failed for TypeArray NaturalAndBiggerThanTen with value "0" :
183             # 1. Validation failed for Natural:
184             # This number (0) is not bigger than 0
185             # 2. Validation failed for BiggerThanTen:
186             # This number (0) is not bigger than ten!
187             #
188             }
189              
190             =head1 DESCRIPTION
191              
192             This type constraint is much like the "Union" type constraint, except the union
193             type constraint validates when any of its members are valid. This type
194             constraint requires B<ALL> of its members to be valid.
195              
196             This type constraint also returns an Object with a breakdown of the composite
197             failed constraints on error, which you should be able to use if you work with
198             this type constraint directly.
199              
200             Alas, Moose itself currently doesn't support propagation of objects as
201             validation methods, so you will only get the stringified version of this object
202             until that is solved.
203              
204             Alternatively, you can use L<MooseX::Attribute::ValidateWithException> until
205             Moose natively supports exceptions.
206              
207             =head1 FUNCTIONS
208              
209             =head2 typearray
210              
211             This function has 2 forms, anonymous and named.
212              
213             =head2 typearray $NAME, \@CONSTRAINTS
214              
215             typearray 'foo', [ 'SubTypeA', 'SubTypeB' ];
216             # the same as
217             typearray { name => 'foo', combining => [ 'SubTypeA', 'SubTypeB' ] };
218              
219             =head2 typearray $NAME, \@CONSTRAINTS, \%CONFIG
220              
221             typearray 'foo', [ 'SubTypeA', 'SubTypeB' ], { blah => "blah" };
222             # the same as
223             typearray { name => 'foo', combining => [ 'SubTypeA', 'SubTypeB' ], blah => "blah" };
224              
225             =head2 typearray $NAME, \%CONFIG
226              
227             typearray 'foo', { blah => "blah" };
228             # the same as
229             typearray { name => 'foo', blah => "blah" };
230              
231             =head2 typearray \@CONSTRAINTS
232              
233             typearray [ 'SubTypeA', 'SubTypeB' ];
234             # the same as
235             typearray { combining => [ 'SubTypeA', 'SubTypeB' ] };
236              
237             =head2 typearray \@CONSTRAINTS, \%CONFIG
238              
239             typearray [ 'SubTypeA', 'SubTypeB' ], { blah => "blah};
240             # the same as
241             typearray { combining => [ 'SubTypeA', 'SubTypeB' ] , blah => "blah" };
242              
243             =head2 typearray \%CONFIG
244              
245             typearray {
246             name => $name # the name of the type ( ie: 'MyType' or 'NaturalBigInt' )
247             combining => $arrayref # the subtypes which must be satisfied for this constraint
248             };
249              
250             No other keys are recognised at this time.
251              
252             =head1 AUTHOR
253              
254             Kent Fredric <kentnl@cpan.org>
255              
256             =head1 COPYRIGHT AND LICENSE
257              
258             This software is copyright (c) 2013 by Kent Fredric <kentnl@cpan.org>.
259              
260             This is free software; you can redistribute it and/or modify it under
261             the same terms as the Perl 5 programming language system itself.
262              
263             =cut