Add some "bridge code" to keep old and new native traits all working
[gitmo/Moose.git] / lib / Moose / Meta / Attribute / Native / Trait.pm
1
2 package Moose::Meta::Attribute::Native::Trait;
3 use Moose::Role;
4 use Moose::Util::TypeConstraints;
5
6 our $VERSION   = '1.14';
7 $VERSION = eval $VERSION;
8 our $AUTHORITY = 'cpan:STEVAN';
9
10 requires '_helper_type';
11
12 before '_process_options' => sub {
13     my ( $self, $name, $options ) = @_;
14
15     $self->_check_helper_type( $options, $name );
16
17     $options->{is} = $self->_default_is
18         if !exists $options->{is} && $self->can('_default_is');
19
20     $options->{default} = $self->_default_default
21         if !exists $options->{default} && $self->can('_default_default');
22 };
23
24 sub _check_helper_type {
25     my ( $self, $options, $name ) = @_;
26
27     my $type = $self->_helper_type;
28
29     $options->{isa} = $type
30         unless exists $options->{isa};
31
32     my $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint(
33         $options->{isa} );
34
35     ( $isa->is_a_type_of($type) )
36         || confess
37         "The type constraint for $name must be a subtype of $type but it's a $isa";
38 }
39
40 before 'install_accessors' => sub { (shift)->_check_handles_values };
41
42 sub _check_handles_values {
43     my $self = shift;
44
45     my $method_constructors = $self->method_constructors;
46
47     my %handles = $self->_canonicalize_handles;
48
49     for my $original_method ( values %handles ) {
50         my $name = $original_method->[0];
51
52         my $accessor_class = $self->_native_accessor_class_for($name);
53
54         # XXX - bridge code
55         ( ( $accessor_class && $accessor_class->can('new') )
56                 || exists $method_constructors->{$name} )
57             || confess "$name is an unsupported method type";
58     }
59 }
60
61 around '_canonicalize_handles' => sub {
62     shift;
63     my $self    = shift;
64     my $handles = $self->handles;
65
66     return unless $handles;
67
68     unless ( 'HASH' eq ref $handles ) {
69         $self->throw_error(
70             "The 'handles' option must be a HASH reference, not $handles");
71     }
72
73     return map {
74         my $to = $handles->{$_};
75         $to = [$to] unless ref $to;
76         $_ => $to
77     } keys %$handles;
78 };
79
80 around '_make_delegation_method' => sub {
81     my $next = shift;
82     my ( $self, $handle_name, $method_to_call ) = @_;
83
84     my ( $name, @curried_args ) = @$method_to_call;
85
86     my $accessor_class = $self->_native_accessor_class_for($name);
87
88     # XXX - bridge code
89     if ( $accessor_class && $accessor_class->can('new') ) {
90         return $accessor_class->new(
91             name              => $handle_name,
92             package_name      => $self->associated_class->name,
93             attribute         => $self,
94             curried_arguments => \@curried_args,
95         );
96     }
97     # XXX - bridge code
98     else {
99         my $method_constructors = $self->method_constructors;
100
101         my $code = $method_constructors->{$name}->(
102             $self,
103             $self->get_read_method_ref,
104             $self->get_write_method_ref,
105         );
106
107         return $next->(
108             $self,
109             $handle_name,
110             sub {
111                 my $instance = shift;
112                 return $code->( $instance, @curried_args, @_ );
113             }
114         );
115     }
116 };
117
118 sub _native_accessor_class_for {
119     my ( $self, $suffix ) = @_;
120
121     # XXX - bridge code
122     return unless $self->can('_native_type');
123
124     return 'Moose::Meta::Method::Accessor::Native::' . $self->_native_type . '::' . $suffix;
125 }
126
127 has 'method_constructors' => (
128     is      => 'ro',
129     isa     => 'HashRef',
130     lazy    => 1,
131     default => sub {
132         my $self = shift;
133         return +{}
134             unless $self->can('has_method_provider')
135                 && $self->has_method_provider;
136
137         # or grab them from the role/class
138         my $method_provider = $self->method_provider->meta;
139         return +{ map { $_->name => $_ }
140                 $method_provider->_get_local_methods };
141     },
142 );
143
144 no Moose::Role;
145 no Moose::Util::TypeConstraints;
146
147 1;
148
149 __END__
150
151 =head1 NAME
152
153 Moose::Meta::Attribute::Native::Trait - Base role for helpers
154
155 =head1 BUGS
156
157 See L<Moose/BUGS> for details on reporting bugs.
158
159 =head1 SEE ALSO
160
161 Documentation for Moose native traits starts at L<Moose::Meta::Attribute Native>
162
163 =head1 AUTHORS
164
165 Yuval Kogman
166
167 Shawn M Moore
168
169 Jesse Luehrs
170
171 =head1 COPYRIGHT AND LICENSE
172
173 Copyright 2007-2009 by Infinity Interactive, Inc.
174
175 L<http://www.iinteractive.com>
176
177 This library is free software; you can redistribute it and/or modify
178 it under the same terms as Perl itself.
179
180 =cut