1 package MooseX::Types::Structured;
4 use Moose::Util::TypeConstraints;
5 use MooseX::Meta::TypeConstraint::Structured::Positional;
6 use MooseX::Meta::TypeConstraint::Structured::Named;
8 use MooseX::Types -declare => [qw(Dict Tuple Optional)];
10 # -setup => { exports => [ qw( Optional) ] };
12 our $VERSION = '0.01';
13 our $AUTHORITY = 'cpan:JJNAPIORK';
17 MooseX::Types::Structured; Structured Type Constraints for Moose
21 The following is example usage for this module. You can define a class that has
22 an attribute with a structured type like so:
24 package MyApp::MyClass;
27 use MooseX::Types::Moose qw(Str Int);
28 use MooseX::Types::Structured qw(Dict Tuple);
30 has name => (isa=>Dict[first_name=>Str, last_name=>Str]);
32 Then you can instantiate this class with something like:
34 my $instance = MyApp::MyClass->new(
35 name=>{first_name=>'John', last_name=>'Napiorkowski'},
38 But all of these would cause an error:
40 my $instance = MyApp::MyClass->new(name=>'John');
41 my $instance = MyApp::MyClass->new(name=>{first_name=>'John'});
42 my $instance = MyApp::MyClass->new(name=>{first_name=>'John', age=>39});
44 Please see the test cases for more examples.
48 This type library enables structured type constraints. Basically, this is very
49 similar to parameterized constraints that are built into the core Moose types,
50 except that you are allowed to define the container's entire structure. For
51 example, you could define a parameterized constraint like so:
53 subtype HashOfInts, as Hashref[Int];
55 which would constraint a value to something like [1,2,3,...] and so one. A
56 structured constraint like so:
58 subtype StringFollowedByInt, as Tuple[Str,Int];
60 would constrain it's value to something like ['hello', 111];
62 These structures can be as simple or elaborate as you wish. You can even
63 combine various structured, parameterized and simple constraints all together:
65 subtype crazy, as Tuple[Int, Dict[name=>Str, age=>Int], ArrayRef[Int]];
67 Which would match "[1, {name=>'John', age=>25},[10,11,12]]".
69 You should exercise some care as to whether or not your complex structured
70 constraints would be better off contained by a real object as in the following
74 package MyApp::MyStruct;
77 has $_ for qw(name age);
79 package MyApp::MyClass;
82 has person => (isa=>'MyApp::MyStruct');
85 my $instance = MyApp::MyClass
86 ->new( person=>MyApp::MyStruct->new(name=>'John', age=>39) );
88 This method may take some additional time to setup but will give you more
89 flexibility. However, structured constraints are highly compatible with this
90 method, granting some interesting possibilities for coercion. Try:
96 from (Dict[name=>Str, age=>Int]),
98 MyApp::MyStruct->new(%$_);
100 from (Dict[last_name=>Str, first_name=>Str, dob=>DateTime]),
102 my $name = _->{first_name} .' '. $_->{last_name};
103 my $age = $_->{dob} - DateTime->now;
104 MyApp::MyStruct->new(
112 This class defines the following types and subtypes.
116 use MooseX::Meta::TypeConstraint::Structured::Positionable;
118 my $tuple = MooseX::Meta::TypeConstraint::Structured::Positionable->new(
120 package_defined_in => __PACKAGE__,
121 parent => find_type_constraint('Ref'),
124 Moose::Util::TypeConstraints::register_type_constraint($tuple);
126 subtype Tuple, as 'Tuple';
130 return bless {args=>shift}, 'MooseX::Types::Optional';
134 my ($args, $optional) = _normalize_args(@_);
136 my @optional = ref $optional eq 'ARRAY' ? @$optional : ();
138 return MooseX::Meta::TypeConstraint::Structured::Positional->new(
140 parent => find_type_constraint('ArrayRef'),
141 package_defined_in => __PACKAGE__,
143 _normalize_type_constraint($_);
145 optional_signature => [map {
146 _normalize_type_constraint($_);
152 my ($args, $optional) = _normalize_args(@_);
154 my %optional = ref $optional eq 'ARRAY' ? @$optional : ();
156 return MooseX::Meta::TypeConstraint::Structured::Named->new(
158 parent => find_type_constraint('HashRef'),
159 package_defined_in => __PACKAGE__,
161 $_ => _normalize_type_constraint($args{$_});
163 optional_signature => {map {
164 $_ => _normalize_type_constraint($optional{$_});
169 sub _normalize_args {
171 confess "Structured Type Constraints can only accept an ArrayRef as arguments"
172 unless ref $args eq 'ARRAY';
175 my $last = pop @args;
177 if(blessed $last && $last->isa('MooseX::Types::Optional')) {
178 return ([@args], $last->{args});
180 return ([@args, $last]);
184 sub _normalize_type_constraint {
187 ## If incoming is an object, we will assume it's something that implements
188 ## what a type constraint is. We should probably have a Role for this...
189 if(defined $tc && blessed $tc) {
192 return Moose::Util::TypeConstraints::find_or_parse_type_constraint($tc);
198 The following modules or resources may be of interest.
200 L<Moose>, L<MooseX::TypeLibrary>, L<Moose::Meta::TypeConstraint>
204 No known or reported bugs.
208 John Napiorkowski, C<< <jjnapiork@cpan.org> >>
210 =head1 COPYRIGHT & LICENSE
212 This program is free software; you can redistribute it and/or modify
213 it under the same terms as Perl itself.