Version 1.12
[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
bd2550f8 10our $VERSION = '1.12';
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;
a9e38dc7 46
ec9e38e5 47 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 48 if $class ne __PACKAGE__;
a9e38dc7 49
ec9e38e5 50 my $params = @_ == 1 ? $_[0] : {@_};
51
52 return bless {
53 # inherited from Class::MOP::Method
54 body => $params->{body},
55 associated_metaclass => $params->{associated_metaclass},
56 package_name => $params->{package_name},
57 name => $params->{name},
58 original_method => $params->{original_method},
59
60 # inherit from Class::MOP::Generated
61 is_inline => $params->{is_inline} || 0,
62 definition_context => $params->{definition_context},
63
64 # defined in this class
65 attribute => $params->{attribute},
66 accessor_type => $params->{accessor_type},
67 } => $class;
a9e38dc7 68}
69
ba38bf08 70## accessors
71
8683db0e 72sub associated_attribute { (shift)->{'attribute'} }
73sub accessor_type { (shift)->{'accessor_type'} }
ba38bf08 74
8d2d4c67 75## factory
ba38bf08 76
e9497117 77sub _initialize_body {
ba38bf08 78 my $self = shift;
8d2d4c67 79
ba38bf08 80 my $method_name = join "_" => (
afc92ac6 81 '_generate',
8d2d4c67 82 $self->accessor_type,
ba38bf08 83 'method',
d90b42a6 84 ($self->is_inline ? 'inline' : ())
ba38bf08 85 );
8d2d4c67 86
1be5f78f 87 $self->{'body'} = $self->$method_name();
ba38bf08 88}
89
90## generators
91
afc92ac6 92sub _generate_accessor_method {
8d2d4c67 93 my $attr = (shift)->associated_attribute;
ba38bf08 94 return sub {
95 $attr->set_value($_[0], $_[1]) if scalar(@_) == 2;
96 $attr->get_value($_[0]);
97 };
98}
99
afc92ac6 100sub _generate_reader_method {
8d2d4c67 101 my $attr = (shift)->associated_attribute;
102 return sub {
ba38bf08 103 confess "Cannot assign a value to a read-only accessor" if @_ > 1;
104 $attr->get_value($_[0]);
8d2d4c67 105 };
ba38bf08 106}
107
afc92ac6 108
109sub _generate_writer_method {
8d2d4c67 110 my $attr = (shift)->associated_attribute;
ba38bf08 111 return sub {
112 $attr->set_value($_[0], $_[1]);
113 };
114}
115
afc92ac6 116sub _generate_predicate_method {
8d2d4c67 117 my $attr = (shift)->associated_attribute;
118 return sub {
3545c727 119 $attr->has_value($_[0])
ba38bf08 120 };
121}
122
afc92ac6 123sub _generate_clearer_method {
8d2d4c67 124 my $attr = (shift)->associated_attribute;
125 return sub {
3545c727 126 $attr->clear_value($_[0])
ba38bf08 127 };
128}
129
130## Inline methods
131
afc92ac6 132sub _generate_accessor_method_inline {
03a3092d 133 my $self = shift;
134 my $attr = $self->associated_attribute;
ba38bf08 135
e24b19fb 136 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 137 {},
7f8de9b4 138 'sub {'
03a3092d 139 . $attr->inline_set( '$_[0]', '$_[1]' )
140 . ' if scalar(@_) == 2; '
141 . $attr->inline_get('$_[0]') . '}'
7f8de9b4 142 );
e24b19fb 143 confess "Could not generate inline accessor because : $e" if $e;
a6eef5a3 144
145 return $code;
ba38bf08 146}
147
afc92ac6 148sub _generate_reader_method_inline {
03a3092d 149 my $self = shift;
150 my $attr = $self->associated_attribute;
ba38bf08 151
03a3092d 152 my ( $code, $e ) = $self->_eval_closure(
153 {},
7f8de9b4 154 'sub {'
03a3092d 155 . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
156 . $attr->inline_get('$_[0]') . '}'
7f8de9b4 157 );
e24b19fb 158 confess "Could not generate inline reader because : $e" if $e;
a6eef5a3 159
160 return $code;
ba38bf08 161}
162
afc92ac6 163sub _generate_writer_method_inline {
03a3092d 164 my $self = shift;
165 my $attr = $self->associated_attribute;
ba38bf08 166
e24b19fb 167 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 168 {},
03a3092d 169 'sub {' . $attr->inline_set( '$_[0]', '$_[1]' ) . '}'
7f8de9b4 170 );
e24b19fb 171 confess "Could not generate inline writer because : $e" if $e;
a6eef5a3 172
173 return $code;
ba38bf08 174}
175
afc92ac6 176sub _generate_predicate_method_inline {
03a3092d 177 my $self = shift;
178 my $attr = $self->associated_attribute;
ba38bf08 179
e24b19fb 180 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 181 {},
03a3092d 182 'sub {' . $attr->inline_has('$_[0]') . '}'
7f8de9b4 183 );
e24b19fb 184 confess "Could not generate inline predicate because : $e" if $e;
a6eef5a3 185
186 return $code;
ba38bf08 187}
188
afc92ac6 189sub _generate_clearer_method_inline {
03a3092d 190 my $self = shift;
191 my $attr = $self->associated_attribute;
ba38bf08 192
e24b19fb 193 my ( $code, $e ) = $self->_eval_closure(
0c6f3280 194 {},
03a3092d 195 'sub {' . $attr->inline_clear('$_[0]') . '}'
7f8de9b4 196 );
e24b19fb 197 confess "Could not generate inline clearer because : $e" if $e;
a6eef5a3 198
199 return $code;
ba38bf08 200}
201
2021;
203
204__END__
205
206=pod
207
8d2d4c67 208=head1 NAME
ba38bf08 209
210Class::MOP::Method::Accessor - Method Meta Object for accessors
211
212=head1 SYNOPSIS
213
96e38ba6 214 use Class::MOP::Method::Accessor;
215
216 my $reader = Class::MOP::Method::Accessor->new(
217 attribute => $attribute,
218 is_inline => 1,
219 accessor_type => 'reader',
220 );
8d2d4c67 221
b7045e66 222 $reader->body->execute($instance); # call the reader method
ba38bf08 223
224=head1 DESCRIPTION
225
6f241a63 226This is a subclass of C<Class::MOP::Method> which is used by
1385ad9d 227C<Class::MOP::Attribute> to generate accessor code. It handles
228generation of readers, writers, predicates and clearers. For each type
229of method, it can either create a subroutine reference, or actually
230inline code by generating a string and C<eval>'ing it.
96e38ba6 231
ba38bf08 232=head1 METHODS
233
234=over 4
235
1385ad9d 236=item B<< Class::MOP::Method::Accessor->new(%options) >>
ba38bf08 237
1385ad9d 238This returns a new C<Class::MOP::Method::Accessor> based on the
239C<%options> provided.
96e38ba6 240
241=over 4
242
9258c369 243=item * attribute
96e38ba6 244
1385ad9d 245This is the C<Class::MOP::Attribute> for which accessors are being
246generated. This option is required.
96e38ba6 247
9258c369 248=item * accessor_type
96e38ba6 249
1385ad9d 250This is a string which should be one of "reader", "writer",
251"accessor", "predicate", or "clearer". This is the type of method
252being generated. This option is required.
96e38ba6 253
9258c369 254=item * is_inline
96e38ba6 255
1385ad9d 256This indicates whether or not the accessor should be inlined. This
cb8d08c6 257defaults to false.
96e38ba6 258
9258c369 259=item * name
260
261The method name (without a package name). This is required.
262
263=item * package_name
264
265The package name for the method. This is required.
266
96e38ba6 267=back
ba38bf08 268
1385ad9d 269=item B<< $metamethod->accessor_type >>
ba38bf08 270
1385ad9d 271Returns the accessor type which was passed to C<new>.
96e38ba6 272
1385ad9d 273=item B<< $metamethod->is_inline >>
ba38bf08 274
1385ad9d 275Returns a boolean indicating whether or not the accessor is inlined.
96e38ba6 276
1385ad9d 277=item B<< $metamethod->associated_attribute >>
ba38bf08 278
1385ad9d 279This returns the L<Class::MOP::Attribute> object which was passed to
280C<new>.
96e38ba6 281
1385ad9d 282=item B<< $metamethod->body >>
96e38ba6 283
1385ad9d 284The method itself is I<generated> when the accessor object is
285constructed.
ba38bf08 286
287=back
288
289=head1 AUTHORS
290
291Stevan Little E<lt>stevan@iinteractive.comE<gt>
292
ba38bf08 293=head1 COPYRIGHT AND LICENSE
294
3e2c8600 295Copyright 2006-2010 by Infinity Interactive, Inc.
ba38bf08 296
297L<http://www.iinteractive.com>
298
299This library is free software; you can redistribute it and/or modify
8d2d4c67 300it under the same terms as Perl itself.
ba38bf08 301
302=cut
303