Remove extra newline
[gitmo/Moose.git] / lib / Moose / Meta / TypeCoercion.pm
CommitLineData
6bf30233 1
2package Moose::Meta::TypeCoercion;
3
4use strict;
5use warnings;
6use metaclass;
7
a27aa600 8use Moose::Meta::Attribute;
a3c7e2fe 9use Moose::Util::TypeConstraints ();
a27aa600 10
a27aa600 11__PACKAGE__->meta->add_attribute('type_coercion_map' => (
12 reader => 'type_coercion_map',
13 default => sub { [] }
14));
d44714be 15
a27aa600 16__PACKAGE__->meta->add_attribute(
17 Moose::Meta::Attribute->new('type_constraint' => (
18 reader => 'type_constraint',
19 weak_ref => 1
20 ))
21);
22
23# private accessor
24__PACKAGE__->meta->add_attribute('compiled_type_coercion' => (
25 accessor => '_compiled_type_coercion'
26));
27
d03bd989 28sub new {
a27aa600 29 my $class = shift;
d4db37e2 30 my $self = Class::MOP::class_of($class)->new_object(@_);
41e007e4 31 $self->compile_type_coercion;
a27aa600 32 return $self;
33}
34
35sub compile_type_coercion {
36 my $self = shift;
37 my @coercion_map = @{$self->type_coercion_map};
38 my @coercions;
39 while (@coercion_map) {
40 my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
9c637fca 41 my $type_constraint = ref $constraint_name ? $constraint_name : Moose::Util::TypeConstraints::find_or_parse_type_constraint($constraint_name);
70ea9161 42
43 unless ( defined $type_constraint ) {
44 require Moose;
45 Moose->throw_error("Could not find the type constraint ($constraint_name) to coerce from");
46 }
47
d03bd989 48 push @coercions => [
49 $type_constraint->_compiled_type_constraint,
50 $action
e95c7c42 51 ];
a27aa600 52 }
d03bd989 53 $self->_compiled_type_coercion(sub {
a27aa600 54 my $thing = shift;
55 foreach my $coercion (@coercions) {
56 my ($constraint, $converter) = @$coercion;
42bc21a4 57 if ($constraint->($thing)) {
d03bd989 58 local $_ = $thing;
a27aa600 59 return $converter->($thing);
60 }
61 }
62 return $thing;
d03bd989 63 });
a27aa600 64}
65
41e007e4 66sub has_coercion_for_type {
67 my ($self, $type_name) = @_;
68 my %coercion_map = @{$self->type_coercion_map};
69 exists $coercion_map{$type_name} ? 1 : 0;
70}
71
72sub add_type_coercions {
73 my ($self, @new_coercion_map) = @_;
d03bd989 74
75 my $coercion_map = $self->type_coercion_map;
41e007e4 76 my %has_coercion = @$coercion_map;
d03bd989 77
41e007e4 78 while (@new_coercion_map) {
d03bd989 79 my ($constraint_name, $action) = splice(@new_coercion_map, 0, 2);
70ea9161 80
81 if ( exists $has_coercion{$constraint_name} ) {
82 require Moose;
83 Moose->throw_error("A coercion action already exists for '$constraint_name'")
84 }
85
41e007e4 86 push @{$coercion_map} => ($constraint_name, $action);
87 }
d03bd989 88
41e007e4 89 # and re-compile ...
90 $self->compile_type_coercion;
91}
92
a27aa600 93sub coerce { $_[0]->_compiled_type_coercion->($_[1]) }
94
95
6bf30233 961;
97
ad46f524 98# ABSTRACT: The Moose Type Coercion metaclass
99
6bf30233 100__END__
101
102=pod
103
6bf30233 104=head1 DESCRIPTION
105
3f961962 106A type coercion object is basically a mapping of one or more type
107constraints and the associated coercions subroutines.
6ba6d68c 108
3f961962 109It's unlikely that you will need to instantiate an object of this
110class directly, as it's part of the deep internals of Moose.
6ba6d68c 111
6bf30233 112=head1 METHODS
113
114=over 4
115
3f961962 116=item B<< Moose::Meta::TypeCoercion->new(%options) >>
6bf30233 117
3f961962 118Creates a new type coercion object, based on the options provided.
a27aa600 119
3f961962 120=over 8
a27aa600 121
3f961962 122=item * type_constraint
6ba6d68c 123
3f961962 124This is the L<Moose::Meta::TypeConstraint> object for the type that is
125being coerced I<to>.
a27aa600 126
3f961962 127=back
128
129=item B<< $coercion->type_coercion_map >>
130
131This returns the map of type constraints to coercions as an array
132reference. The values of the array alternate between type names and
133subroutine references which implement the coercion.
134
135The value is an array reference because coercions are tried in the
136order they are added.
137
138=item B<< $coercion->type_constraint >>
139
140This returns the L<Moose::Meta::TypeConstraint> that was passed to the
141constructor.
142
143=item B<< $coercion->has_coercion_for_type($type_name) >>
144
145Returns true if the coercion can coerce the named type.
146
147=item B<< $coercion->add_type_coercions( $type_name => $sub, ... ) >>
148
149This method takes a list of type names and subroutine references. If
150the coercion already has a mapping for a given type, it throws an
151exception.
152
153Coercions are actually
154
155=item B<< $coercion->coerce($value) >>
156
157This method takes a value and applies the first valid coercion it
158finds.
159
160This means that if the value could belong to more than type in the
161coercion object, the first coercion added is used.
a27aa600 162
3f961962 163=item B<< Moose::Meta::TypeCoercion->meta >>
41e007e4 164
3f961962 165This will return a L<Class::MOP::Class> instance for this class.
41e007e4 166
6bf30233 167=back
168
169=head1 BUGS
170
d4048ef3 171See L<Moose/BUGS> for details on reporting bugs.
6bf30233 172
42bc21a4 173=cut