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