1 package ## Hide from PAUSE
2 MooseX::Dependent::Meta::TypeConstraint::Dependent;
5 use Moose::Util::TypeConstraints ();
6 use Scalar::Util qw(blessed);
8 extends 'Moose::Meta::TypeConstraint';
12 MooseX::Dependent::Meta::TypeConstraint::Dependent - Metaclass for Dependent type constraints.
16 see L<MooseX::Dependent> for examples and details of how to use dependent
17 types. This class is a subclass of L<Moose::Meta::TypeConstraint> which
18 provides the gut functionality to enable dependent type constraints.
22 This class defines the following attributes.
24 =head2 parent_type_constraint
26 The type constraint whose validity is being made dependent.
30 has 'parent_type_constraint' => (
34 Moose::Util::TypeConstraints::find_type_constraint("Any");
40 =head2 constraining_value_type_constraint
42 This is a type constraint which defines what kind of value is allowed to be the
43 constraining value of the dependent type.
47 has 'constraining_value_type_constraint' => (
51 Moose::Util::TypeConstraints::find_type_constraint("Any");
56 =head2 constraining_value
58 This is the actual value that constraints the L</parent_type_constraint>
62 has 'constraining_value' => (
64 predicate=>'has_constraining_value',
69 This class defines the following methods.
71 =head2 parameterize (@args)
73 Given a ref of type constraints, create a structured type.
79 my $class = ref $self;
81 Moose->throw_error("$self already has a constraining value.") if
82 $self->has_constraining_value;
84 if(blessed $_[0] && $_[0]->isa('Moose::Meta::TypeConstraint')) {
87 if(blessed $_[0] && $_[0]->isa('Moose::Meta::TypeConstraint')) {
88 my $arg2 = shift @_ || $self->constraining_value_type_constraint;
90 ## TODO fix this crap!
91 Moose->throw_error("$arg2 is not a type constraint")
92 unless $arg2->isa('Moose::Meta::TypeConstraint');
94 Moose->throw_error("$arg1 is not a type of: ".$self->parent_type_constraint->name)
95 unless $arg1->is_a_type_of($self->parent_type_constraint);
97 Moose->throw_error("$arg2 is not a type of: ".$self->constraining_value_type_constraint->name)
98 unless $arg2->is_a_type_of($self->constraining_value_type_constraint);
100 Moose->throw_error('Too Many Args! Two are allowed.') if @_;
103 name => $self->_generate_subtype_name($arg1, $arg2),
105 constraint => $self->constraint,
106 parent_type_constraint=>$arg1,
107 constraining_value_type_constraint => $arg2,
110 Moose->throw_error("$arg1 is not a type of: ".$self->constraining_value_type_constraint->name)
111 unless $arg1->is_a_type_of($self->constraining_value_type_constraint);
114 name => $self->_generate_subtype_name($self->parent_type_constraint, $arg1),
116 constraint => $self->constraint,
117 parent_type_constraint=>$self->parent_type_constraint,
118 constraining_value_type_constraint => $arg1,
123 ## Jump through some hoops to let them do tc[key=>10] and tc[{key=>10}]
126 if($self->constraining_value_type_constraint->is_a_type_of('HashRef')) {
136 ## TODO: Is there a use case for parameterizing null or undef?
137 Moose->throw_error('Cannot Parameterize null values.');
140 if(my $err = $self->constraining_value_type_constraint->validate($args)) {
141 Moose->throw_error($err);
143 ## TODO memorize or do a registry lookup on the name as an optimization
145 name => $self->name."[$args]",
147 constraint => $self->constraint,
148 constraining_value => $args,
149 parent_type_constraint=>$self->parent_type_constraint,
150 constraining_value_type_constraint => $self->constraining_value_type_constraint,
156 =head2 _generate_subtype_name
158 Returns a name for the dependent type that should be unique
162 sub _generate_subtype_name {
163 my ($self, $parent_tc, $constraining_tc) = @_;
166 $parent_tc, $constraining_tc,
170 =head2 create_child_type
172 modifier to make sure we get the constraint_generator
176 around 'create_child_type' => sub {
177 my ($create_child_type, $self, %opts) = @_;
178 if($self->has_constraining_value) {
179 $opts{constraining_value} = $self->constraining_value;
181 return $self->$create_child_type(
184 parent_type_constraint=>$self->parent_type_constraint,
185 constraining_value_type_constraint => $self->constraining_value_type_constraint,
189 =head2 equals ($type_constraint)
191 Override the base class behavior so that a dependent type equal both the parent
192 type and the overall dependent container. This behavior may change if we can
193 figure out what a dependent type is (multiply inheritance or a role...)
197 around 'equals' => sub {
198 my ( $equals, $self, $type_or_name ) = @_;
200 my $other = defined $type_or_name ?
201 Moose::Util::TypeConstraints::find_type_constraint($type_or_name) :
202 Moose->throw_error("Can't call $self ->equals without a parameter");
204 Moose->throw_error("$type_or_name is not a registered Type")
207 if(my $parent = $other->parent) {
208 return $self->$equals($other)
209 || $self->parent->equals($parent);
211 return $self->$equals($other);
215 around 'is_subtype_of' => sub {
216 my ( $is_subtype_of, $self, $type_or_name ) = @_;
218 my $other = defined $type_or_name ?
219 Moose::Util::TypeConstraints::find_type_constraint($type_or_name) :
220 Moose->throw_error("Can't call $self ->equals without a parameter");
222 Moose->throw_error("$type_or_name is not a registered Type")
225 return $self->$is_subtype_of($other)
226 || $self->parent_type_constraint->is_subtype_of($other);
231 my ($self, @args) = @_;
232 return ($self->equals(@args) ||
233 $self->is_subtype_of(@args));
236 around 'check' => sub {
237 my ($check, $self, @args) = @_;
239 $self->parent_type_constraint->check(@args) &&
244 around 'validate' => sub {
245 my ($validate, $self, @args) = @_;
247 $self->parent_type_constraint->validate(@args) ||
248 $self->$validate(@args)
252 around '_compiled_type_constraint' => sub {
253 my ($method, $self, @args) = @_;
254 my $coderef = $self->$method(@args);
256 if($self->has_constraining_value) {
257 $constraining = $self->constraining_value;
262 if(my $err = $self->constraining_value_type_constraint->validate($constraining)) {
263 Moose->throw_error($err);
265 $coderef->(@local_args, $constraining);
271 Give you a better peek into what's causing the error.
273 around 'get_message' => sub {
274 my ($get_message, $self, $value) = @_;
275 return $self->$get_message($value);
280 The following modules or resources may be of interest.
282 L<Moose>, L<Moose::Meta::TypeConstraint>
286 John Napiorkowski, C<< <jjnapiork@cpan.org> >>
288 =head1 COPYRIGHT & LICENSE
290 This program is free software; you can redistribute it and/or modify
291 it under the same terms as Perl itself.
295 __PACKAGE__->meta->make_immutable(inline_constructor => 0);