bump version to 0.87
[gitmo/Class-MOP.git] / lib / Class / MOP / Method / Accessor.pm
1
2 package Class::MOP::Method::Accessor;
3
4 use strict;
5 use warnings;
6
7 use Carp         'confess';
8 use Scalar::Util 'blessed', 'weaken';
9
10 our $VERSION   = '0.87';
11 $VERSION = eval $VERSION;
12 our $AUTHORITY = 'cpan:STEVAN';
13
14 use base 'Class::MOP::Method::Generated';
15
16 sub new {
17     my $class   = shift;
18     my %options = @_;
19
20     (exists $options{attribute})
21         || confess "You must supply an attribute to construct with";
22
23     (exists $options{accessor_type})
24         || confess "You must supply an accessor_type to construct with";
25
26     (blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
27         || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
28
29     ($options{package_name} && $options{name})
30         || confess "You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT";
31
32     my $self = $class->_new(\%options);
33
34     # we don't want this creating
35     # a cycle in the code, if not
36     # needed
37     weaken($self->{'attribute'});
38
39     $self->_initialize_body;
40
41     return $self;
42 }
43
44 sub _new {
45     my $class = shift;
46     my $options = @_ == 1 ? $_[0] : {@_};
47
48     $options->{is_inline} ||= 0;
49
50     return bless $options, $class;
51 }
52
53 ## accessors
54
55 sub associated_attribute { (shift)->{'attribute'}     }
56 sub accessor_type        { (shift)->{'accessor_type'} }
57
58 ## factory
59
60 sub initialize_body {
61     Carp::cluck('The initialize_body method has been made private.'
62         . " The public version is deprecated and will be removed in a future release.\n");
63     shift->_initialize_body;
64 }
65
66 sub _initialize_body {
67     my $self = shift;
68
69     my $method_name = join "_" => (
70         '_generate',
71         $self->accessor_type,
72         'method',
73         ($self->is_inline ? 'inline' : ())
74     );
75
76     $self->{'body'} = $self->$method_name();
77 }
78
79 ## generators
80
81 sub generate_accessor_method {
82     Carp::cluck('The generate_accessor_method method has been made private.'
83         . " The public version is deprecated and will be removed in a future release.\n");
84     shift->_generate_accessor_method;
85 }
86
87 sub _generate_accessor_method {
88     my $attr = (shift)->associated_attribute;
89     return sub {
90         $attr->set_value($_[0], $_[1]) if scalar(@_) == 2;
91         $attr->get_value($_[0]);
92     };
93 }
94
95 sub generate_reader_method {
96     Carp::cluck('The generate_reader_method method has been made private.'
97         . " The public version is deprecated and will be removed in a future release.\n");
98     shift->_generate_reader_method;
99 }
100
101 sub _generate_reader_method {
102     my $attr = (shift)->associated_attribute;
103     return sub {
104         confess "Cannot assign a value to a read-only accessor" if @_ > 1;
105         $attr->get_value($_[0]);
106     };
107 }
108
109 sub generate_writer_method {
110     Carp::cluck('The generate_writer_method method has been made private.'
111         . " The public version is deprecated and will be removed in a future release.\n");
112     shift->_generate_writer_method;
113 }
114
115 sub _generate_writer_method {
116     my $attr = (shift)->associated_attribute;
117     return sub {
118         $attr->set_value($_[0], $_[1]);
119     };
120 }
121
122 sub generate_predicate_method {
123     Carp::cluck('The generate_predicate_method method has been made private.'
124         . " The public version is deprecated and will be removed in a future release.\n");
125     shift->_generate_predicate_method;
126 }
127
128 sub _generate_predicate_method {
129     my $attr = (shift)->associated_attribute;
130     return sub {
131         $attr->has_value($_[0])
132     };
133 }
134
135 sub generate_clearer_method {
136     Carp::cluck('The generate_clearer_method method has been made private.'
137         . " The public version is deprecated and will be removed in a future release.\n");
138     shift->_generate_clearer_method;
139 }
140
141 sub _generate_clearer_method {
142     my $attr = (shift)->associated_attribute;
143     return sub {
144         $attr->clear_value($_[0])
145     };
146 }
147
148 ## Inline methods
149
150 sub generate_accessor_method_inline {
151     Carp::cluck('The generate_accessor_method_inline method has been made private.'
152         . " The public version is deprecated and will be removed in a future release.\n");
153     shift->_generate_accessor_method_inline;
154 }
155
156 sub _generate_accessor_method_inline {
157     my $self          = shift;
158     my $attr          = $self->associated_attribute;
159     my $attr_name     = $attr->name;
160     my $meta_instance = $attr->associated_class->instance_metaclass;
161
162     my ( $code, $e ) = $self->_eval_closure(
163         {},
164         'sub {'
165         . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
166         . ' if scalar(@_) == 2; '
167         . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
168         . '}'
169     );
170     confess "Could not generate inline accessor because : $e" if $e;
171
172     return $code;
173 }
174
175 sub generate_reader_method_inline {
176     Carp::cluck('The generate_reader_method_inline method has been made private.'
177         . " The public version is deprecated and will be removed in a future release.\n");
178     shift->_generate_reader_method_inline;
179 }
180
181 sub _generate_reader_method_inline {
182     my $self          = shift;
183     my $attr          = $self->associated_attribute;
184     my $attr_name     = $attr->name;
185     my $meta_instance = $attr->associated_class->instance_metaclass;
186
187      my ( $code, $e ) = $self->_eval_closure(
188          {},
189         'sub {'
190         . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
191         . $meta_instance->inline_get_slot_value('$_[0]', $attr_name)
192         . '}'
193     );
194     confess "Could not generate inline reader because : $e" if $e;
195
196     return $code;
197 }
198
199 sub generate_writer_method_inline {
200     Carp::cluck('The generate_writer_method_inline method has been made private.'
201         . " The public version is deprecated and will be removed in a future release.\n");
202     shift->_generate_writer_method_inline;
203 }
204
205 sub _generate_writer_method_inline {
206     my $self          = shift;
207     my $attr          = $self->associated_attribute;
208     my $attr_name     = $attr->name;
209     my $meta_instance = $attr->associated_class->instance_metaclass;
210
211     my ( $code, $e ) = $self->_eval_closure(
212         {},
213         'sub {'
214         . $meta_instance->inline_set_slot_value('$_[0]', $attr_name, '$_[1]')
215         . '}'
216     );
217     confess "Could not generate inline writer because : $e" if $e;
218
219     return $code;
220 }
221
222 sub generate_predicate_method_inline {
223     Carp::cluck('The generate_predicate_method_inline method has been made private.'
224         . " The public version is deprecated and will be removed in a future release.\n");
225     shift->_generate_predicate_method_inline;
226 }
227
228 sub _generate_predicate_method_inline {
229     my $self          = shift;
230     my $attr          = $self->associated_attribute;
231     my $attr_name     = $attr->name;
232     my $meta_instance = $attr->associated_class->instance_metaclass;
233
234     my ( $code, $e ) = $self->_eval_closure(
235         {},
236        'sub {'
237        . $meta_instance->inline_is_slot_initialized('$_[0]', $attr_name)
238        . '}'
239     );
240     confess "Could not generate inline predicate because : $e" if $e;
241
242     return $code;
243 }
244
245 sub generate_clearer_method_inline {
246     Carp::cluck('The generate_clearer_method_inline method has been made private.'
247         . " The public version is deprecated and will be removed in a future release.\n");
248     shift->_generate_clearer_method_inline;
249 }
250
251 sub _generate_clearer_method_inline {
252     my $self          = shift;
253     my $attr          = $self->associated_attribute;
254     my $attr_name     = $attr->name;
255     my $meta_instance = $attr->associated_class->instance_metaclass;
256
257     my ( $code, $e ) = $self->_eval_closure(
258         {},
259         'sub {'
260         . $meta_instance->inline_deinitialize_slot('$_[0]', $attr_name)
261         . '}'
262     );
263     confess "Could not generate inline clearer because : $e" if $e;
264
265     return $code;
266 }
267
268 1;
269
270 __END__
271
272 =pod
273
274 =head1 NAME
275
276 Class::MOP::Method::Accessor - Method Meta Object for accessors
277
278 =head1 SYNOPSIS
279
280     use Class::MOP::Method::Accessor;
281
282     my $reader = Class::MOP::Method::Accessor->new(
283         attribute     => $attribute,
284         is_inline     => 1,
285         accessor_type => 'reader',
286     );
287
288     $reader->body->execute($instance); # call the reader method
289
290 =head1 DESCRIPTION
291
292 This is a subclass of <Class::MOP::Method> which is used by
293 C<Class::MOP::Attribute> to generate accessor code. It handles
294 generation of readers, writers, predicates and clearers. For each type
295 of method, it can either create a subroutine reference, or actually
296 inline code by generating a string and C<eval>'ing it.
297
298 =head1 METHODS
299
300 =over 4
301
302 =item B<< Class::MOP::Method::Accessor->new(%options) >>
303
304 This returns a new C<Class::MOP::Method::Accessor> based on the
305 C<%options> provided.
306
307 =over 4
308
309 =item * attribute
310
311 This is the C<Class::MOP::Attribute> for which accessors are being
312 generated. This option is required.
313
314 =item * accessor_type
315
316 This is a string which should be one of "reader", "writer",
317 "accessor", "predicate", or "clearer". This is the type of method
318 being generated. This option is required.
319
320 =item * is_inline
321
322 This indicates whether or not the accessor should be inlined. This
323 defaults to false.
324
325 =item * name
326
327 The method name (without a package name). This is required.
328
329 =item * package_name
330
331 The package name for the method. This is required.
332
333 =back
334
335 =item B<< $metamethod->accessor_type >>
336
337 Returns the accessor type which was passed to C<new>.
338
339 =item B<< $metamethod->is_inline >>
340
341 Returns a boolean indicating whether or not the accessor is inlined.
342
343 =item B<< $metamethod->associated_attribute >>
344
345 This returns the L<Class::MOP::Attribute> object which was passed to
346 C<new>.
347
348 =item B<< $metamethod->body >>
349
350 The method itself is I<generated> when the accessor object is
351 constructed.
352
353 =back
354
355 =head1 AUTHORS
356
357 Stevan Little E<lt>stevan@iinteractive.comE<gt>
358
359 =head1 COPYRIGHT AND LICENSE
360
361 Copyright 2006-2009 by Infinity Interactive, Inc.
362
363 L<http://www.iinteractive.com>
364
365 This library is free software; you can redistribute it and/or modify
366 it under the same terms as Perl itself.
367
368 =cut
369