1 package MooseX::Types::Structured;
4 use Moose::Util::TypeConstraints;
5 use MooseX::Meta::TypeConstraint::Structured;
6 use MooseX::Types -declare => [qw(Dict Tuple)];
10 our $AUTHORITY = 'cpan:JJNAPIORK';
14 MooseX::Types::Structured; Structured Type Constraints for Moose
18 The following is example usage for this module. You can define a class that has
19 an attribute with a structured type like so:
21 package MyApp::MyClass;
24 use MooseX::Types::Moose qw(Str Int);
25 use MooseX::Types::Structured qw(Dict Tuple);
27 has name => (isa=>Dict[first_name=>Str, last_name=>Str]);
29 Then you can instantiate this class with something like:
31 my $instance = MyApp::MyClass->new(
32 name=>{first_name=>'John', last_name=>'Napiorkowski'},
35 But all of these would cause an error:
37 my $instance = MyApp::MyClass->new(name=>'John');
38 my $instance = MyApp::MyClass->new(name=>{first_name=>'John'});
39 my $instance = MyApp::MyClass->new(name=>{first_name=>'John', age=>39});
41 Please see the test cases for more examples.
45 This type library enables structured type constraints. Basically, this is very
46 similar to parameterized constraints that are built into the core Moose types,
47 except that you are allowed to define the container's entire structure. For
48 example, you could define a parameterized constraint like so:
50 subtype HashOfInts, as Hashref[Int];
52 which would constraint a value to something like [1,2,3,...] and so one. A
53 structured constraint like so:
55 subtype StringFollowedByInt, as Tuple[Str,Int];
57 would constrain it's value to something like ['hello', 111];
59 These structures can be as simple or elaborate as you wish. You can even
60 combine various structured, parameterized and simple constraints all together:
62 subtype crazy, as Tuple[Int, Dict[name=>Str, age=>Int], ArrayRef[Int]];
64 Which would match "[1, {name=>'John', age=>25},[10,11,12]]".
66 You should exercise some care as to whether or not your complex structured
67 constraints would be better off contained by a real object as in the following
71 package MyApp::MyStruct;
74 has $_ for qw(name age);
76 package MyApp::MyClass;
79 has person => (isa=>'MyApp::MyStruct');
82 my $instance = MyApp::MyClass
83 ->new( person=>MyApp::MyStruct->new(name=>'John', age=>39) );
85 This method may take some additional time to setup but will give you more
86 flexibility. However, structured constraints are highly compatible with this
87 method, granting some interesting possibilities for coercion. Try:
93 from (Dict[name=>Str, age=>Int]),
95 MyApp::MyStruct->new(%$_);
97 from (Dict[last_name=>Str, first_name=>Str, dob=>DateTime]),
99 my $name = _->{first_name} .' '. $_->{last_name};
100 my $age = $_->{dob} - DateTime->now;
101 MyApp::MyStruct->new(
106 You also need to exercise some care when you try to structure a structured type
110 as Dict[name=>Str, age=>iIt];
112 subtype FriendlyPerson,
113 as Person[name=>Str, age=>Int, totalFriends=>Int];
115 This will actually work BUT you have to take care the the subtype has a
116 structure that does not contradict the structure of it's parent. For now the
117 above works, but I will probably clarify how this works at a future point, so
118 it's recommended to avoid (should not realy be needed so much anyway). For
119 now this is supported in an EXPERIMENTAL way.
123 Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
124 MooseX::Meta::TypeConstraint::Structured->new(
125 name => "MooseX::Types::Structured::Tuple" ,
126 parent => find_type_constraint('ArrayRef'),
127 constraint_generator=> sub {
128 ## Get the constraints and values to check
129 my @type_constraints = @{shift @_};
130 my @values = @{shift @_};
131 ## Perform the checking
132 while(@type_constraints) {
133 my $type_constraint = shift @type_constraints;
135 my $value = shift @values;
136 unless($type_constraint->check($value)) {
143 ## Make sure there are no leftovers.
146 } elsif(@type_constraints) {
155 Moose::Util::TypeConstraints::get_type_constraint_registry->add_type_constraint(
156 MooseX::Meta::TypeConstraint::Structured->new(
157 name => "MooseX::Types::Structured::Dict",
158 parent => find_type_constraint('HashRef'),
159 constraint_generator=> sub {
160 ## Get the constraints and values to check
161 my %type_constraints = @{shift @_};
162 my %values = %{shift @_};
163 ## Perform the checking
164 while(%type_constraints) {
165 my($key, $type_constraint) = each %type_constraints;
166 delete $type_constraints{$key};
167 if(exists $values{$key}) {
168 my $value = $values{$key};
169 delete $values{$key};
170 unless($type_constraint->check($value)) {
177 ## Make sure there are no leftovers.
180 } elsif(%type_constraints) {
191 The following modules or resources may be of interest.
193 L<Moose>, L<MooseX::TypeLibrary>, L<Moose::Meta::TypeConstraint>,
194 L<MooseX::Meta::TypeConstraint::Structured>
198 John Napiorkowski, C<< <jjnapiork@cpan.org> >>
200 =head1 COPYRIGHT & LICENSE
202 This program is free software; you can redistribute it and/or modify
203 it under the same terms as Perl itself.