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