Allow type coercions to be declared from anon types
[gitmo/Moose.git] / lib / Moose / Meta / TypeCoercion.pm
1
2 package Moose::Meta::TypeCoercion;
3
4 use strict;
5 use warnings;
6 use metaclass;
7
8 use Carp 'confess';
9
10 use Moose::Meta::Attribute;
11 use Moose::Util::TypeConstraints ();
12
13 our $VERSION   = '0.06';
14 our $AUTHORITY = 'cpan:STEVAN';
15
16 __PACKAGE__->meta->add_attribute('type_coercion_map' => (
17     reader  => 'type_coercion_map',
18     default => sub { [] }
19 ));
20
21 __PACKAGE__->meta->add_attribute(
22     Moose::Meta::Attribute->new('type_constraint' => (
23         reader   => 'type_constraint',
24         weak_ref => 1
25     ))
26 );
27
28 # private accessor
29 __PACKAGE__->meta->add_attribute('compiled_type_coercion' => (
30     accessor => '_compiled_type_coercion'
31 ));
32
33 sub new { 
34     my $class = shift;
35     my $self  = $class->meta->new_object(@_);
36     $self->compile_type_coercion;
37     return $self;
38 }
39
40 sub compile_type_coercion {
41     my $self = shift;
42     my @coercion_map = @{$self->type_coercion_map};
43     my @coercions;
44     while (@coercion_map) {
45         my ($constraint_name, $action) = splice(@coercion_map, 0, 2);
46         my $type_constraint = ref $constraint_name ? $constraint_name : Moose::Util::TypeConstraints::find_or_parse_type_constraint($constraint_name);
47         (defined $type_constraint)
48             || confess "Could not find the type constraint ($constraint_name) to coerce from";
49         push @coercions => [ 
50             $type_constraint->_compiled_type_constraint, 
51             $action 
52         ];
53     }
54     $self->_compiled_type_coercion(sub { 
55         my $thing = shift;
56         foreach my $coercion (@coercions) {
57             my ($constraint, $converter) = @$coercion;
58             if ($constraint->($thing)) {
59                 local $_ = $thing;                
60                 return $converter->($thing);
61             }
62         }
63         return $thing;
64     });    
65 }
66
67 sub has_coercion_for_type {
68     my ($self, $type_name) = @_;
69     my %coercion_map = @{$self->type_coercion_map};
70     exists $coercion_map{$type_name} ? 1 : 0;
71 }
72
73 sub add_type_coercions {
74     my ($self, @new_coercion_map) = @_;
75         
76     my $coercion_map = $self->type_coercion_map;    
77     my %has_coercion = @$coercion_map;
78     
79     while (@new_coercion_map) {
80         my ($constraint_name, $action) = splice(@new_coercion_map, 0, 2);        
81         
82         confess "A coercion action already exists for '$constraint_name'"
83             if exists $has_coercion{$constraint_name};
84         
85         push @{$coercion_map} => ($constraint_name, $action);
86     }
87     
88     # and re-compile ...
89     $self->compile_type_coercion;
90 }
91
92 sub coerce { $_[0]->_compiled_type_coercion->($_[1]) }
93
94
95 1;
96
97 __END__
98
99 =pod
100
101 =head1 NAME
102
103 Moose::Meta::TypeCoercion - The Moose Type Coercion metaclass
104
105 =head1 DESCRIPTION
106
107 For the most part, the only time you will ever encounter an 
108 instance of this class is if you are doing some serious deep 
109 introspection. This API should not be considered final, but 
110 it is B<highly unlikely> that this will matter to a regular 
111 Moose user.
112
113 If you wish to use features at this depth, please come to the 
114 #moose IRC channel on irc.perl.org and we can talk :)
115
116 =head1 METHODS
117
118 =over 4
119
120 =item B<meta>
121
122 =item B<new>
123
124 =item B<compile_type_coercion>
125
126 =item B<coerce>
127
128 =item B<type_coercion_map>
129
130 =item B<type_constraint>
131
132 =item B<has_coercion_for_type>
133
134 =item B<add_type_coercions>
135
136 =back
137
138 =head1 BUGS
139
140 All complex software has bugs lurking in it, and this module is no 
141 exception. If you find a bug please either email me, or add the bug
142 to cpan-RT.
143
144 =head1 AUTHOR
145
146 Stevan Little E<lt>stevan@iinteractive.comE<gt>
147
148 =head1 COPYRIGHT AND LICENSE
149
150 Copyright 2006-2008 by Infinity Interactive, Inc.
151
152 L<http://www.iinteractive.com>
153
154 This library is free software; you can redistribute it and/or modify
155 it under the same terms as Perl itself. 
156
157 =cut