Make default is deprecation warning happen at run time
[gitmo/Moose.git] / lib / Moose / Meta / Attribute / Native / Trait.pm
1
2 package Moose::Meta::Attribute::Native::Trait;
3 use Moose::Role;
4
5 use List::MoreUtils qw( any uniq );
6 use Moose::Util::TypeConstraints;
7 use Moose::Deprecated;
8
9 our $VERSION   = '1.15';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
12
13 requires '_helper_type';
14
15 has _used_default_is => (
16     is      => 'rw',
17     isa     => 'Bool',
18     default => 0,
19 );
20
21 before '_process_options' => sub {
22     my ( $self, $name, $options ) = @_;
23
24     $self->_check_helper_type( $options, $name );
25
26     if ( !( any { exists $options->{$_} } qw( is reader writer accessor ) )
27         && $self->can('_default_is') ) {
28
29         $options->{is} = $self->_default_is;
30
31         $options->{_used_default_is} = 1;
32     }
33
34     if (
35         !(
36             $options->{required}
37             || any { exists $options->{$_} } qw( default builder lazy_build )
38         )
39         && $self->can('_default_default')
40         ) {
41
42         $options->{default} = $self->_default_default;
43
44         Moose::Deprecated::deprecated(
45             feature => 'default default for Native Trait',
46             message =>
47                 'Allowing a native trait to automatically supply a default is deprecated'
48         );
49     }
50 };
51
52 after 'install_accessors' => sub {
53     my $self = shift;
54
55     return unless $self->_used_default_is;
56
57     my @methods
58         = $self->_default_is eq 'rw'
59         ? qw( reader writer accessor )
60         : 'reader';
61
62     my $name = $self->name;
63     my $class = $self->associated_class->name;
64
65     for my $meth ( uniq grep {defined} map { $self->$_ } @methods ) {
66
67         my $message
68             = "The $meth method in the $class class was automatically created"
69             . " by the native delegation trait for the $name attribute."
70             . q{ This "default is" feature is deprecated.}
71             . q{ Explicitly set "is" or define accessor names to avoid this};
72
73         $self->associated_class->add_before_method_modifier(
74             $meth => sub {
75                 Moose::Deprecated::deprecated(
76                     feature => 'default is for Native Trait',
77                     message =>$message,
78                 );
79             }
80         );
81     }
82     };
83
84 sub _check_helper_type {
85     my ( $self, $options, $name ) = @_;
86
87     my $type = $self->_helper_type;
88
89     $options->{isa} = $type
90         unless exists $options->{isa};
91
92     my $isa = Moose::Util::TypeConstraints::find_or_create_type_constraint(
93         $options->{isa} );
94
95     ( $isa->is_a_type_of($type) )
96         || confess
97         "The type constraint for $name must be a subtype of $type but it's a $isa";
98 }
99
100 before 'install_accessors' => sub { (shift)->_check_handles_values };
101
102 sub _check_handles_values {
103     my $self = shift;
104
105     my %handles = $self->_canonicalize_handles;
106
107     for my $original_method ( values %handles ) {
108         my $name = $original_method->[0];
109
110         my $accessor_class = $self->_native_accessor_class_for($name);
111
112         ( $accessor_class && $accessor_class->can('new') )
113             || confess
114             "$name is an unsupported method type - $accessor_class";
115     }
116 }
117
118 around '_canonicalize_handles' => sub {
119     shift;
120     my $self    = shift;
121     my $handles = $self->handles;
122
123     return unless $handles;
124
125     unless ( 'HASH' eq ref $handles ) {
126         $self->throw_error(
127             "The 'handles' option must be a HASH reference, not $handles");
128     }
129
130     return map {
131         my $to = $handles->{$_};
132         $to = [$to] unless ref $to;
133         $_ => $to
134     } keys %$handles;
135 };
136
137 around '_make_delegation_method' => sub {
138     my $next = shift;
139     my ( $self, $handle_name, $method_to_call ) = @_;
140
141     my ( $name, @curried_args ) = @$method_to_call;
142
143     my $accessor_class = $self->_native_accessor_class_for($name);
144
145     die "Cannot find an accessor class for $name"
146         unless $accessor_class && $accessor_class->can('new');
147
148     return $accessor_class->new(
149         name               => $handle_name,
150         package_name       => $self->associated_class->name,
151         delegate_to_method => $name,
152         attribute          => $self,
153         is_inline          => 1,
154         curried_arguments  => \@curried_args,
155         root_types         => [ $self->_root_types ],
156     );
157 };
158
159 sub _root_types {
160     return $_[0]->_helper_type;
161 }
162
163 sub _native_accessor_class_for {
164     my ( $self, $suffix ) = @_;
165
166     my $role
167         = 'Moose::Meta::Method::Accessor::Native::'
168         . $self->_native_type . '::'
169         . $suffix;
170
171     return Moose::Meta::Class->create_anon_class(
172         superclasses =>
173             [ $self->accessor_metaclass, $self->delegation_metaclass ],
174         roles => [$role],
175         cache => 1,
176     )->name;
177 }
178
179 sub _build_native_type {
180     my $self = shift;
181
182     for my $role_name ( map { $_->name } $self->meta->calculate_all_roles ) {
183         return $1 if $role_name =~ /::Native::Trait::(\w+)$/;
184     }
185
186     die "Cannot calculate native type for " . ref $self;
187 }
188
189 has '_native_type' => (
190     is      => 'ro',
191     isa     => 'Str',
192     lazy    => 1,
193     builder => '_build_native_type',
194 );
195
196 no Moose::Role;
197 no Moose::Util::TypeConstraints;
198
199 1;
200
201 __END__
202
203 =head1 NAME
204
205 Moose::Meta::Attribute::Native::Trait - Shared role for native delegation traits
206
207 =head1 BUGS
208
209 See L<Moose/BUGS> for details on reporting bugs.
210
211 =head1 SEE ALSO
212
213 Documentation for Moose native traits can be found in
214 L<Moose::Meta::Attribute::Native>.
215
216 =head1 AUTHORS
217
218 Yuval Kogman
219
220 Shawn M Moore
221
222 Jesse Luehrs
223
224 =head1 COPYRIGHT AND LICENSE
225
226 Copyright 2007-2009 by Infinity Interactive, Inc.
227
228 L<http://www.iinteractive.com>
229
230 This library is free software; you can redistribute it and/or modify
231 it under the same terms as Perl itself.
232
233 =cut