aa8cf2d0a3c9bbf43d7e6904e75ac5f1b1b5bff6
[gitmo/Moose.git] / lib / Moose / Meta / TypeConstraint / Parameterizable.pm
1 package Moose::Meta::TypeConstraint::Parameterizable;
2
3 use strict;
4 use warnings;
5 use metaclass;
6
7 use base 'Moose::Meta::TypeConstraint';
8 use Moose::Meta::TypeConstraint::Parameterized;
9 use Moose::Util::TypeConstraints ();
10
11 use Carp 'confess';
12
13 __PACKAGE__->meta->add_attribute('constraint_generator' => (
14     accessor  => 'constraint_generator',
15     predicate => 'has_constraint_generator',
16     Class::MOP::_definition_context(),
17 ));
18
19 __PACKAGE__->meta->add_attribute('inline_generator' => (
20     accessor  => 'inline_generator',
21     predicate => 'has_inline_generator',
22     Class::MOP::_definition_context(),
23 ));
24
25 sub generate_constraint_for {
26     my ($self, $type) = @_;
27
28     return unless $self->has_constraint_generator;
29
30     return $self->constraint_generator->($type->type_parameter)
31         if $type->is_subtype_of($self->name);
32
33     return $self->_can_coerce_constraint_from($type)
34         if $self->has_coercion
35         && $self->coercion->has_coercion_for_type($type->parent->name);
36
37     return;
38 }
39
40 sub _can_coerce_constraint_from {
41     my ($self, $type) = @_;
42     my $coercion   = $self->coercion;
43     my $constraint = $self->constraint_generator->($type->type_parameter);
44     return sub {
45         local $_ = $coercion->coerce($_);
46         $constraint->(@_);
47     };
48 }
49
50 sub generate_inline_for {
51     my ($self, $type, $val) = @_;
52
53     confess "Can't generate an inline constraint for $type, since none "
54           . "was defined"
55         unless $self->has_inline_generator;
56
57     return '( do { ' . $self->inline_generator->( $self, $type, $val ) . ' } )';
58 }
59
60 sub _parse_type_parameter {
61     my ($self, $type_parameter) = @_;
62     return Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($type_parameter);
63 }
64
65 sub parameterize {
66     my ($self, $type_parameter) = @_;
67
68     my $contained_tc = $self->_parse_type_parameter($type_parameter);
69
70     ## The type parameter should be a subtype of the parent's type parameter
71     ## if there is one.
72
73     if(my $parent = $self->parent) {
74         if($parent->can('type_parameter')) {
75             unless ( $contained_tc->is_a_type_of($parent->type_parameter) ) {
76                 require Moose;
77                 Moose->throw_error("$type_parameter is not a subtype of ".$parent->type_parameter);
78             }
79         }
80     }
81
82     if ( $contained_tc->isa('Moose::Meta::TypeConstraint') ) {
83         my $tc_name = $self->name . '[' . $contained_tc->name . ']';
84         return Moose::Meta::TypeConstraint::Parameterized->new(
85             name               => $tc_name,
86             parent             => $self,
87             type_parameter     => $contained_tc,
88             parameterized_from => $self,
89         );
90     }
91     else {
92         require Moose;
93         Moose->throw_error("The type parameter must be a Moose meta type");
94     }
95 }
96
97
98 1;
99
100 # ABSTRACT: Type constraints which can take a parameter (ArrayRef)
101
102 __END__
103
104
105 =pod
106
107 =head1 DESCRIPTION
108
109 This class represents a parameterizable type constraint. This is a
110 type constraint like C<ArrayRef> or C<HashRef>, that can be
111 parameterized and made more specific by specifying a contained
112 type. For example, instead of just an C<ArrayRef> of anything, you can
113 specify that is an C<ArrayRef[Int]>.
114
115 A parameterizable constraint should not be used as an attribute type
116 constraint. Instead, when parameterized it creates a
117 L<Moose::Meta::TypeConstraint::Parameterized> which should be used.
118
119 =head1 INHERITANCE
120
121 C<Moose::Meta::TypeConstraint::Parameterizable> is a subclass of
122 L<Moose::Meta::TypeConstraint>.
123
124 =head1 METHODS
125
126 This class is intentionally not documented because the API is
127 confusing and needs some work.
128
129 =head1 BUGS
130
131 See L<Moose/BUGS> for details on reporting bugs.
132
133 =cut