simplify more stuff
[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';
15961c86 9use Try::Tiny;
ba38bf08 10
a9f48b4b 11our $VERSION = '1.11';
d519662a 12$VERSION = eval $VERSION;
ba38bf08 13our $AUTHORITY = 'cpan:STEVAN';
14
565f0cbb 15use base 'Class::MOP::Method::Generated';
ba38bf08 16
ba38bf08 17sub new {
18 my $class = shift;
19 my %options = @_;
8d2d4c67 20
ba38bf08 21 (exists $options{attribute})
22 || confess "You must supply an attribute to construct with";
8d2d4c67 23
ba38bf08 24 (exists $options{accessor_type})
8d2d4c67 25 || confess "You must supply an accessor_type to construct with";
26
ba38bf08 27 (blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute'))
8d2d4c67 28 || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance";
29
b38f3848 30 ($options{package_name} && $options{name})
32202ce2 31 || confess "You must supply the package_name and name parameters $Class::MOP::Method::UPGRADE_ERROR_TEXT";
b38f3848 32
0bfc85b8 33 my $self = $class->_new(\%options);
8d2d4c67 34
35 # we don't want this creating
36 # a cycle in the code, if not
ba38bf08 37 # needed
8683db0e 38 weaken($self->{'attribute'});
8d2d4c67 39
e9497117 40 $self->_initialize_body;
8d2d4c67 41
ba38bf08 42 return $self;
43}
44
a9e38dc7 45sub _new {
0bfc85b8 46 my $class = shift;
a9e38dc7 47
ec9e38e5 48 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 49 if $class ne __PACKAGE__;
a9e38dc7 50
ec9e38e5 51 my $params = @_ == 1 ? $_[0] : {@_};
52
53 return bless {
54 # inherited from Class::MOP::Method
55 body => $params->{body},
56 associated_metaclass => $params->{associated_metaclass},
57 package_name => $params->{package_name},
58 name => $params->{name},
59 original_method => $params->{original_method},
60
61 # inherit from Class::MOP::Generated
62 is_inline => $params->{is_inline} || 0,
63 definition_context => $params->{definition_context},
64
65 # defined in this class
66 attribute => $params->{attribute},
67 accessor_type => $params->{accessor_type},
68 } => $class;
a9e38dc7 69}
70
ba38bf08 71## accessors
72
8683db0e 73sub associated_attribute { (shift)->{'attribute'} }
74sub accessor_type { (shift)->{'accessor_type'} }
ba38bf08 75
8d2d4c67 76## factory
ba38bf08 77
e9497117 78sub _initialize_body {
ba38bf08 79 my $self = shift;
8d2d4c67 80
ba38bf08 81 my $method_name = join "_" => (
afc92ac6 82 '_generate',
8d2d4c67 83 $self->accessor_type,
ba38bf08 84 'method',
d90b42a6 85 ($self->is_inline ? 'inline' : ())
ba38bf08 86 );
8d2d4c67 87
1be5f78f 88 $self->{'body'} = $self->$method_name();
ba38bf08 89}
90
91## generators
92
afc92ac6 93sub _generate_accessor_method {
8d2d4c67 94 my $attr = (shift)->associated_attribute;
ba38bf08 95 return sub {
96 $attr->set_value($_[0], $_[1]) if scalar(@_) == 2;
97 $attr->get_value($_[0]);
98 };
99}
100
afc92ac6 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
afc92ac6 109
110sub _generate_writer_method {
8d2d4c67 111 my $attr = (shift)->associated_attribute;
ba38bf08 112 return sub {
113 $attr->set_value($_[0], $_[1]);
114 };
115}
116
afc92ac6 117sub _generate_predicate_method {
8d2d4c67 118 my $attr = (shift)->associated_attribute;
119 return sub {
3545c727 120 $attr->has_value($_[0])
ba38bf08 121 };
122}
123
afc92ac6 124sub _generate_clearer_method {
8d2d4c67 125 my $attr = (shift)->associated_attribute;
126 return sub {
3545c727 127 $attr->clear_value($_[0])
ba38bf08 128 };
129}
130
131## Inline methods
132
afc92ac6 133sub _generate_accessor_method_inline {
03a3092d 134 my $self = shift;
135 my $attr = $self->associated_attribute;
ba38bf08 136
15961c86 137 my $code = try {
5efa6a46 138 $self->_compile_code([
139 'sub {',
140 $attr->inline_set('$_[0]', '$_[1]'),
141 'if scalar(@_) == 2;',
142 $attr->inline_get('$_[0]') . ';',
143 '}',
144 ]);
15961c86 145 }
146 catch {
147 confess "Could not generate inline accessor because : $_";
148 };
a6eef5a3 149
150 return $code;
ba38bf08 151}
152
afc92ac6 153sub _generate_reader_method_inline {
03a3092d 154 my $self = shift;
155 my $attr = $self->associated_attribute;
ba38bf08 156
15961c86 157 my $code = try {
5efa6a46 158 $self->_compile_code([
159 'sub {',
160 'confess "Cannot assign a value to a read-only accessor"',
161 'if @_ > 1;',
162 $attr->inline_get('$_[0]') . ';',
163 '}',
164 ]);
15961c86 165 }
166 catch {
167 confess "Could not generate inline reader because : $_";
168 };
a6eef5a3 169
170 return $code;
ba38bf08 171}
172
afc92ac6 173sub _generate_writer_method_inline {
03a3092d 174 my $self = shift;
175 my $attr = $self->associated_attribute;
ba38bf08 176
15961c86 177 my $code = try {
5efa6a46 178 $self->_compile_code([
179 'sub {',
180 $attr->inline_set('$_[0]', '$_[1]') . ';',
181 '}',
182 ]);
15961c86 183 }
184 catch {
185 confess "Could not generate inline writer because : $_";
186 };
a6eef5a3 187
188 return $code;
ba38bf08 189}
190
afc92ac6 191sub _generate_predicate_method_inline {
03a3092d 192 my $self = shift;
193 my $attr = $self->associated_attribute;
ba38bf08 194
15961c86 195 my $code = try {
5efa6a46 196 $self->_compile_code([
197 'sub {',
198 $attr->inline_has('$_[0]') . ';',
199 '}',
200 ]);
15961c86 201 }
202 catch {
203 confess "Could not generate inline predicate because : $_";
204 };
a6eef5a3 205
206 return $code;
ba38bf08 207}
208
afc92ac6 209sub _generate_clearer_method_inline {
03a3092d 210 my $self = shift;
211 my $attr = $self->associated_attribute;
ba38bf08 212
15961c86 213 my $code = try {
5efa6a46 214 $self->_compile_code([
215 'sub {',
216 $attr->inline_clear('$_[0]') . ';',
217 '}',
218 ]);
15961c86 219 }
220 catch {
221 confess "Could not generate inline clearer because : $_";
222 };
a6eef5a3 223
224 return $code;
ba38bf08 225}
226
2271;
228
229__END__
230
231=pod
232
8d2d4c67 233=head1 NAME
ba38bf08 234
235Class::MOP::Method::Accessor - Method Meta Object for accessors
236
237=head1 SYNOPSIS
238
96e38ba6 239 use Class::MOP::Method::Accessor;
240
241 my $reader = Class::MOP::Method::Accessor->new(
242 attribute => $attribute,
243 is_inline => 1,
244 accessor_type => 'reader',
245 );
8d2d4c67 246
b7045e66 247 $reader->body->execute($instance); # call the reader method
ba38bf08 248
249=head1 DESCRIPTION
250
6f241a63 251This is a subclass of C<Class::MOP::Method> which is used by
1385ad9d 252C<Class::MOP::Attribute> to generate accessor code. It handles
253generation of readers, writers, predicates and clearers. For each type
254of method, it can either create a subroutine reference, or actually
255inline code by generating a string and C<eval>'ing it.
96e38ba6 256
ba38bf08 257=head1 METHODS
258
259=over 4
260
1385ad9d 261=item B<< Class::MOP::Method::Accessor->new(%options) >>
ba38bf08 262
1385ad9d 263This returns a new C<Class::MOP::Method::Accessor> based on the
264C<%options> provided.
96e38ba6 265
266=over 4
267
9258c369 268=item * attribute
96e38ba6 269
1385ad9d 270This is the C<Class::MOP::Attribute> for which accessors are being
271generated. This option is required.
96e38ba6 272
9258c369 273=item * accessor_type
96e38ba6 274
1385ad9d 275This is a string which should be one of "reader", "writer",
276"accessor", "predicate", or "clearer". This is the type of method
277being generated. This option is required.
96e38ba6 278
9258c369 279=item * is_inline
96e38ba6 280
1385ad9d 281This indicates whether or not the accessor should be inlined. This
cb8d08c6 282defaults to false.
96e38ba6 283
9258c369 284=item * name
285
286The method name (without a package name). This is required.
287
288=item * package_name
289
290The package name for the method. This is required.
291
96e38ba6 292=back
ba38bf08 293
1385ad9d 294=item B<< $metamethod->accessor_type >>
ba38bf08 295
1385ad9d 296Returns the accessor type which was passed to C<new>.
96e38ba6 297
1385ad9d 298=item B<< $metamethod->is_inline >>
ba38bf08 299
1385ad9d 300Returns a boolean indicating whether or not the accessor is inlined.
96e38ba6 301
1385ad9d 302=item B<< $metamethod->associated_attribute >>
ba38bf08 303
1385ad9d 304This returns the L<Class::MOP::Attribute> object which was passed to
305C<new>.
96e38ba6 306
1385ad9d 307=item B<< $metamethod->body >>
96e38ba6 308
1385ad9d 309The method itself is I<generated> when the accessor object is
310constructed.
ba38bf08 311
312=back
313
314=head1 AUTHORS
315
316Stevan Little E<lt>stevan@iinteractive.comE<gt>
317
ba38bf08 318=head1 COPYRIGHT AND LICENSE
319
3e2c8600 320Copyright 2006-2010 by Infinity Interactive, Inc.
ba38bf08 321
322L<http://www.iinteractive.com>
323
324This library is free software; you can redistribute it and/or modify
8d2d4c67 325it under the same terms as Perl itself.
ba38bf08 326
327=cut
328