minor doc tweaks
[gitmo/MooseX-Types-Structured.git] / lib / MooseX / Meta / TypeConstraint / Structured.pm
CommitLineData
65748864 1package MooseX::Meta::TypeConstraint::Structured;
2
3use 5.8.8; ## Minimum tested Perl Version
4use Moose;
5use Moose::Util::TypeConstraints;
6
7extends 'Moose::Meta::TypeConstraint';
8
9our $AUTHORITY = 'cpan:JJNAPIORK';
10
11=head1 NAME
12
13MooseX::Meta::TypeConstraint::Structured - Structured Type Constraints
14
15=head1 VERSION
16
170.01
18
19=cut
20
21our $VERSION = '0.01';
22
23=head1 DESCRIPTION
24
25Structured type constraints let you assign an internal pattern of type
26constraints to a 'container' constraint. The goal is to make it easier to
27declare constraints like "ArrayRef[Int, Int, Str]" where the constraint is an
28ArrayRef of three elements and the internal constraint on the three is Int, Int
29and Str.
30
27941057 31To accomplish this, we add an attribute to the base L<Moose::Meta::TypeConstraint>
32to hold a L</signature>, which is a reference to a pattern of type constraints.
33We then override L</constraint> to check our incoming value to the attribute
34against this signature pattern.
35
8b276dd4 36=head1 SUBTYPES
65748864 37
8b276dd4 38The following subtypes and coercions are defined in this class.
65748864 39
8b276dd4 40=head2 MooseX::Meta::TypeConstraint::Structured::Signature
65748864 41
27941057 42This is a type constraint to normalize the incoming L</signature>. We want
43everything as a HashRef in the end.
65748864 44
45=cut
46
bc64165b 47subtype 'MooseX::Meta::TypeConstraint::Structured::Signature',
48 as 'HashRef[Object]',
49 where {
50 my %signature = %$_;
51 foreach my $key (keys %signature) {
52 $signature{$key}->isa('Moose::Meta::TypeConstraint');
53 } 1;
54 };
55
56coerce 'MooseX::Meta::TypeConstraint::Structured::Signature',
57 from 'ArrayRef[Object]',
58 via {
59 my @signature = @$_;
60 my %hashed_signature = map { $_ => $signature[$_] } 0..$#signature;
61 \%hashed_signature;
62 };
63
8b276dd4 64=head1 ATTRIBUTES
65
66This class defines the following attributes.
67
68=head2 signature
69
70This is a signature of internal contraints for the contents of the outer
71contraint container.
72
73=cut
74
65748864 75has 'signature' => (
76 is=>'ro',
bc64165b 77 isa=>'MooseX::Meta::TypeConstraint::Structured::Signature',
78 coerce=>1,
65748864 79 required=>1,
80);
81
82=head1 METHODS
83
84This class defines the following methods.
85
86=head2 _normalize_args
87
bc64165b 88Get arguments into a known state or die trying. Ideally we try to make this
89into a HashRef so we can match it up with the L</signature> HashRef.
65748864 90
91=cut
92
93sub _normalize_args {
94 my ($self, $args) = @_;
bc64165b 95 if(defined $args) {
96 if(ref $args eq 'ARRAY') {
97 return map { $_ => $args->[$_] } (0..$#$args);
98 } elsif (ref $args eq 'HASH') {
99 return %$args;
100 } else {
101 confess 'Signature must be a reference';
102 }
65748864 103 } else {
bc64165b 104 confess 'Signature cannot be empty';
65748864 105 }
106}
107
108=head2 constraint
109
110The constraint is basically validating the L</signature> against the incoming
111
112=cut
113
114sub constraint {
115 my $self = shift;
116 return sub {
bc64165b 117 my %args = $self->_normalize_args(shift);
118 foreach my $idx (keys %{$self->signature}) {
119 my $type_constraint = $self->signature->{$idx};
120 if(my $error = $type_constraint->validate($args{$idx})) {
65748864 121 confess $error;
122 }
123 } 1;
124 };
125}
126
bc64165b 127=head2 equals
128
129modifier to make sure equals descends into the L</signature>
130
131=cut
132
133around 'equals' => sub {
134 my ($equals, $self, $compared_type_constraint) = @_;
135
136 ## Make sure we are comparing typeconstraints of the same base class
137 return unless $compared_type_constraint->isa(__PACKAGE__);
138
139 ## Make sure the base equals is also good
140 return unless $self->$equals($compared_type_constraint);
141
142 ## Make sure the signatures match
143 return unless $self->signature_equals($compared_type_constraint);
144
145 ## If we get this far, the two are equal
146 return 1;
147};
148
149=head2 signature_equals
150
151Check that the signature equals another signature.
152
153=cut
154
155sub signature_equals {
156 my ($self, $compared_type_constraint) = @_;
157
158 foreach my $idx (keys %{$self->signature}) {
159 my $this = $self->signature->{$idx};
160 my $that = $compared_type_constraint->signature->{$idx};
161 return unless $this->equals($that);
162 }
163
164 return 1;
165}
166
65748864 167=head1 AUTHOR
168
169John James Napiorkowski <jjnapiork@cpan.org>
170
171=head1 LICENSE
172
173You may distribute this code under the same terms as Perl itself.
174
175=cut
176
177no Moose; 1;