2 package Moose::Meta::TypeCoercion;
8 use Moose::Meta::Attribute;
9 use Moose::Util::TypeConstraints ();
11 our $AUTHORITY = 'cpan:STEVAN';
13 __PACKAGE__->meta->add_attribute('type_coercion_map' => (
14 reader => 'type_coercion_map',
18 __PACKAGE__->meta->add_attribute(
19 Moose::Meta::Attribute->new('type_constraint' => (
20 reader => 'type_constraint',
26 __PACKAGE__->meta->add_attribute('compiled_type_coercion' => (
27 accessor => '_compiled_type_coercion'
32 my $self = Class::MOP::class_of($class)->new_object(@_);
33 $self->compile_type_coercion;
37 sub compile_type_coercion {
39 my @coercion_map = @{$self->type_coercion_map};
41 while (@coercion_map) {
42 my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
43 my $type_constraint = ref $constraint_name ? $constraint_name : Moose::Util::TypeConstraints::find_or_parse_type_constraint($constraint_name);
45 unless ( defined $type_constraint ) {
47 Moose->throw_error("Could not find the type constraint ($constraint_name) to coerce from");
51 $type_constraint->_compiled_type_constraint,
55 $self->_compiled_type_coercion(sub {
57 foreach my $coercion (@coercions) {
58 my ($constraint, $converter) = @$coercion;
59 if ($constraint->($thing)) {
61 return $converter->($thing);
68 sub has_coercion_for_type {
69 my ($self, $type_name) = @_;
70 my %coercion_map = @{$self->type_coercion_map};
71 exists $coercion_map{$type_name} ? 1 : 0;
74 sub add_type_coercions {
75 my ($self, @new_coercion_map) = @_;
77 my $coercion_map = $self->type_coercion_map;
78 my %has_coercion = @$coercion_map;
80 while (@new_coercion_map) {
81 my ($constraint_name, $action) = splice(@new_coercion_map, 0, 2);
83 if ( exists $has_coercion{$constraint_name} ) {
85 Moose->throw_error("A coercion action already exists for '$constraint_name'")
88 push @{$coercion_map} => ($constraint_name, $action);
92 $self->compile_type_coercion;
95 sub coerce { $_[0]->_compiled_type_coercion->($_[1]) }
100 # ABSTRACT: The Moose Type Coercion metaclass
108 A type coercion object is basically a mapping of one or more type
109 constraints and the associated coercions subroutines.
111 It's unlikely that you will need to instantiate an object of this
112 class directly, as it's part of the deep internals of Moose.
118 =item B<< Moose::Meta::TypeCoercion->new(%options) >>
120 Creates a new type coercion object, based on the options provided.
124 =item * type_constraint
126 This is the L<Moose::Meta::TypeConstraint> object for the type that is
131 =item B<< $coercion->type_coercion_map >>
133 This returns the map of type constraints to coercions as an array
134 reference. The values of the array alternate between type names and
135 subroutine references which implement the coercion.
137 The value is an array reference because coercions are tried in the
138 order they are added.
140 =item B<< $coercion->type_constraint >>
142 This returns the L<Moose::Meta::TypeConstraint> that was passed to the
145 =item B<< $coercion->has_coercion_for_type($type_name) >>
147 Returns true if the coercion can coerce the named type.
149 =item B<< $coercion->add_type_coercions( $type_name => $sub, ... ) >>
151 This method takes a list of type names and subroutine references. If
152 the coercion already has a mapping for a given type, it throws an
155 Coercions are actually
157 =item B<< $coercion->coerce($value) >>
159 This method takes a value and applies the first valid coercion it
162 This means that if the value could belong to more than type in the
163 coercion object, the first coercion added is used.
165 =item B<< Moose::Meta::TypeCoercion->meta >>
167 This will return a L<Class::MOP::Class> instance for this class.
173 See L<Moose/BUGS> for details on reporting bugs.