foo
[gitmo/Class-MOP.git] / lib / Class / MOP / Attribute.pm
CommitLineData
8b978dd5 1
2package Class::MOP::Attribute;
3
4use strict;
5use warnings;
6
ba38bf08 7use Class::MOP::Method::Accessor;
8
2eb717d5 9use Carp 'confess';
9ec169fe 10use Scalar::Util 'blessed', 'reftype', 'weaken';
2eb717d5 11
9363ea89 12our $VERSION = '0.14';
f0480c45 13our $AUTHORITY = 'cpan:STEVAN';
8b978dd5 14
b1897d4d 15use base 'Class::MOP::Object';
16
727919c5 17sub meta {
18 require Class::MOP::Class;
aa448b16 19 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
727919c5 20}
2eb717d5 21
727919c5 22# NOTE: (meta-circularity)
16e960bd 23# This method will be replaced in the
727919c5 24# boostrap section of Class::MOP, by
25# a new version which uses the
26# &Class::MOP::Class::construct_instance
27# method to build an attribute meta-object
28# which itself is described with attribute
29# meta-objects.
30# - Ain't meta-circularity grand? :)
8b978dd5 31sub new {
32 my $class = shift;
33 my $name = shift;
34 my %options = @_;
35
cbd9f942 36 (defined $name && $name)
8b978dd5 37 || confess "You must provide a name for the attribute";
f8dfcfb7 38
5659d76e 39 $options{init_arg} = $name
40 if not exists $options{init_arg};
2eb717d5 41
148b4697 42 (is_default_a_coderef(\%options))
43 || confess("References are not allowed as default values, you must ".
44 "wrap then in a CODE reference (ex: sub { [] } and not [])")
45 if exists $options{default} && ref $options{default};
46
8b978dd5 47 bless {
c23184fc 48 '$!name' => $name,
49 '$!accessor' => $options{accessor},
50 '$!reader' => $options{reader},
51 '$!writer' => $options{writer},
52 '$!predicate' => $options{predicate},
53 '$!clearer' => $options{clearer},
54 '$!init_arg' => $options{init_arg},
55 '$!default' => $options{default},
9ec169fe 56 # keep a weakened link to the
57 # class we are associated with
c23184fc 58 '$!associated_class' => undef,
3545c727 59 # and a list of the methods
60 # associated with this attr
c23184fc 61 '@!associated_methods' => [],
8b978dd5 62 } => $class;
63}
64
7b31baf4 65# NOTE:
5659d76e 66# this is a primative (and kludgy) clone operation
16e960bd 67# for now, it will be replaced in the Class::MOP
5659d76e 68# bootstrap with a proper one, however we know
69# that this one will work fine for now.
70sub clone {
71 my $self = shift;
72 my %options = @_;
73 (blessed($self))
74 || confess "Can only clone an instance";
75 return bless { %{$self}, %options } => blessed($self);
76}
77
bd4e03f9 78sub initialize_instance_slot {
f892c0f0 79 my ($self, $meta_instance, $instance, $params) = @_;
c23184fc 80 my $init_arg = $self->{'$!init_arg'};
bd4e03f9 81 # try to fetch the init arg from the %params ...
82 my $val;
83 $val = $params->{$init_arg} if exists $params->{$init_arg};
84 # if nothing was in the %params, we can use the
85 # attribute's default value (if it has one)
c23184fc 86 if (!defined $val && defined $self->{'$!default'}) {
2d711cc8 87 $val = $self->default($instance);
88 }
43715282 89 $meta_instance->set_slot_value($instance, $self->name, $val);
bd4e03f9 90}
91
5659d76e 92# NOTE:
7b31baf4 93# the next bunch of methods will get bootstrapped
94# away in the Class::MOP bootstrapping section
95
c23184fc 96sub name { $_[0]->{'$!name'} }
c50c603e 97
c23184fc 98sub associated_class { $_[0]->{'$!associated_class'} }
99sub associated_methods { $_[0]->{'@!associated_methods'} }
7b31baf4 100
c23184fc 101sub has_accessor { defined($_[0]->{'$!accessor'}) ? 1 : 0 }
102sub has_reader { defined($_[0]->{'$!reader'}) ? 1 : 0 }
103sub has_writer { defined($_[0]->{'$!writer'}) ? 1 : 0 }
104sub has_predicate { defined($_[0]->{'$!predicate'}) ? 1 : 0 }
105sub has_clearer { defined($_[0]->{'$!clearer'}) ? 1 : 0 }
106sub has_init_arg { defined($_[0]->{'$!init_arg'}) ? 1 : 0 }
107sub has_default { defined($_[0]->{'$!default'}) ? 1 : 0 }
c50c603e 108
c23184fc 109sub accessor { $_[0]->{'$!accessor'} }
110sub reader { $_[0]->{'$!reader'} }
111sub writer { $_[0]->{'$!writer'} }
112sub predicate { $_[0]->{'$!predicate'} }
113sub clearer { $_[0]->{'$!clearer'} }
114sub init_arg { $_[0]->{'$!init_arg'} }
c50c603e 115
7b31baf4 116# end bootstrapped away method section.
117# (all methods below here are kept intact)
118
c0cbf4d9 119sub is_default_a_coderef {
c23184fc 120 ('CODE' eq (reftype($_[0]->{'$!default'} || $_[0]->{default}) || ''))
c0cbf4d9 121}
122
c50c603e 123sub default {
c0cbf4d9 124 my ($self, $instance) = @_;
9363ea89 125 if (defined $instance && $self->is_default_a_coderef) {
727919c5 126 # if the default is a CODE ref, then
127 # we pass in the instance and default
128 # can return a value based on that
129 # instance. Somewhat crude, but works.
c23184fc 130 return $self->{'$!default'}->($instance);
c50c603e 131 }
c23184fc 132 $self->{'$!default'};
c50c603e 133}
8b978dd5 134
c57c8b10 135# slots
136
137sub slots { (shift)->name }
138
9ec169fe 139# class association
727919c5 140
9ec169fe 141sub attach_to_class {
142 my ($self, $class) = @_;
143 (blessed($class) && $class->isa('Class::MOP::Class'))
144 || confess "You must pass a Class::MOP::Class instance (or a subclass)";
c23184fc 145 weaken($self->{'$!associated_class'} = $class);
9ec169fe 146}
147
148sub detach_from_class {
149 my $self = shift;
c23184fc 150 $self->{'$!associated_class'} = undef;
9ec169fe 151}
152
3545c727 153# method association
154
155sub associate_method {
156 my ($self, $method) = @_;
c23184fc 157 push @{$self->{'@!associated_methods'}} => $method;
3545c727 158}
159
16e960bd 160## Slot management
161
162sub set_value {
1396f86b 163 my ($self, $instance, $value) = @_;
16e960bd 164
3545c727 165 Class::MOP::Class->initialize(blessed($instance))
16e960bd 166 ->get_meta_instance
3545c727 167 ->set_slot_value($instance, $self->name, $value);
16e960bd 168}
169
170sub get_value {
1396f86b 171 my ($self, $instance) = @_;
16e960bd 172
3545c727 173 Class::MOP::Class->initialize(blessed($instance))
16e960bd 174 ->get_meta_instance
1396f86b 175 ->get_slot_value($instance, $self->name);
16e960bd 176}
177
3545c727 178sub has_value {
179 my ($self, $instance) = @_;
180
181 defined Class::MOP::Class->initialize(blessed($instance))
182 ->get_meta_instance
183 ->get_slot_value($instance, $self->name) ? 1 : 0;
184}
185
186sub clear_value {
187 my ($self, $instance) = @_;
188
189 Class::MOP::Class->initialize(blessed($instance))
190 ->get_meta_instance
191 ->deinitialize_slot($instance, $self->name);
192}
193
ba38bf08 194## load em up ...
c0cbf4d9 195
ba38bf08 196sub accessor_metaclass { 'Class::MOP::Method::Accessor' }
c0cbf4d9 197
9ec169fe 198sub process_accessors {
c0cbf4d9 199 my ($self, $type, $accessor, $generate_as_inline_methods) = @_;
013b1897 200 if (reftype($accessor)) {
201 (reftype($accessor) eq 'HASH')
7d28758b 202 || confess "bad accessor/reader/writer/predicate/clearer format, must be a HASH ref";
4d47b77f 203 my ($name, $method) = %{$accessor};
3545c727 204 $method = $self->accessor_metaclass->wrap($method);
205 $self->associate_method($method);
206 return ($name, $method);
2eb717d5 207 }
9ec169fe 208 else {
ba38bf08 209 my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable);
210 my $method;
211 eval {
212 $method = $self->accessor_metaclass->new(
213 attribute => $self,
d90b42a6 214 is_inline => $inline_me,
ba38bf08 215 accessor_type => $type,
216 );
217 };
218 confess "Could not create the '$type' method for " . $self->name . " because : $@" if $@;
3545c727 219 $self->associate_method($method);
ba38bf08 220 return ($accessor, $method);
9ec169fe 221 }
222}
223
224sub install_accessors {
c0cbf4d9 225 my $self = shift;
226 my $inline = shift;
227 my $class = $self->associated_class;
c50c603e 228
9ec169fe 229 $class->add_method(
c0cbf4d9 230 $self->process_accessors('accessor' => $self->accessor(), $inline)
9ec169fe 231 ) if $self->has_accessor();
232
233 $class->add_method(
c0cbf4d9 234 $self->process_accessors('reader' => $self->reader(), $inline)
9ec169fe 235 ) if $self->has_reader();
236
237 $class->add_method(
c0cbf4d9 238 $self->process_accessors('writer' => $self->writer(), $inline)
9ec169fe 239 ) if $self->has_writer();
240
241 $class->add_method(
c0cbf4d9 242 $self->process_accessors('predicate' => $self->predicate(), $inline)
9ec169fe 243 ) if $self->has_predicate();
c0cbf4d9 244
7d28758b 245 $class->add_method(
246 $self->process_accessors('clearer' => $self->clearer(), $inline)
247 ) if $self->has_clearer();
248
9ec169fe 249 return;
2eb717d5 250}
251
b51af7f9 252{
253 my $_remove_accessor = sub {
254 my ($accessor, $class) = @_;
c50c603e 255 if (reftype($accessor) && reftype($accessor) eq 'HASH') {
256 ($accessor) = keys %{$accessor};
257 }
b51af7f9 258 my $method = $class->get_method($accessor);
259 $class->remove_method($accessor)
ba38bf08 260 if (blessed($method) && $method->isa('Class::MOP::Method::Accessor'));
b51af7f9 261 };
c50c603e 262
b51af7f9 263 sub remove_accessors {
9ec169fe 264 my $self = shift;
2367814a 265 # TODO:
266 # we really need to make sure to remove from the
267 # associates methods here as well. But this is
268 # such a slimly used method, I am not worried
269 # about it right now.
9ec169fe 270 $_remove_accessor->($self->accessor(), $self->associated_class()) if $self->has_accessor();
271 $_remove_accessor->($self->reader(), $self->associated_class()) if $self->has_reader();
272 $_remove_accessor->($self->writer(), $self->associated_class()) if $self->has_writer();
273 $_remove_accessor->($self->predicate(), $self->associated_class()) if $self->has_predicate();
7d28758b 274 $_remove_accessor->($self->clearer(), $self->associated_class()) if $self->has_clearer();
b51af7f9 275 return;
276 }
277
8b978dd5 278}
279
2801;
281
282__END__
283
284=pod
285
286=head1 NAME
287
288Class::MOP::Attribute - Attribute Meta Object
289
290=head1 SYNOPSIS
291
292 Class::MOP::Attribute->new('$foo' => (
fe122940 293 accessor => 'foo', # dual purpose get/set accessor
294 predicate => 'has_foo' # predicate check for defined-ness
295 init_arg => '-foo', # class->new will look for a -foo key
296 default => 'BAR IS BAZ!' # if no -foo key is provided, use this
8b978dd5 297 ));
298
299 Class::MOP::Attribute->new('$.bar' => (
fe122940 300 reader => 'bar', # getter
301 writer => 'set_bar', # setter
302 predicate => 'has_bar' # predicate check for defined-ness
303 init_arg => ':bar', # class->new will look for a :bar key
8b978dd5 304 # no default value means it is undef
305 ));
306
307=head1 DESCRIPTION
308
fe122940 309The Attribute Protocol is almost entirely an invention of this module,
310and is completely optional to this MOP. This is because Perl 5 does not
311have consistent notion of what is an attribute of a class. There are
312so many ways in which this is done, and very few (if any) are
313easily discoverable by this module.
552e3d24 314
315So, all that said, this module attempts to inject some order into this
fe122940 316chaos, by introducing a consistent API which can be used to create
317object attributes.
552e3d24 318
319=head1 METHODS
320
321=head2 Creation
322
323=over 4
324
fe122940 325=item B<new ($name, ?%options)>
326
327An attribute must (at the very least), have a C<$name>. All other
a2e85e6c 328C<%options> are contained added as key-value pairs. Acceptable keys
fe122940 329are as follows:
330
331=over 4
332
333=item I<init_arg>
334
335This should be a string value representing the expected key in
336an initialization hash. For instance, if we have an I<init_arg>
337value of C<-foo>, then the following code will Just Work.
338
339 MyClass->meta->construct_instance(-foo => "Hello There");
340
7b31baf4 341In an init_arg is not assigned, it will automatically use the
342value of C<$name>.
343
fe122940 344=item I<default>
345
346The value of this key is the default value which
347C<Class::MOP::Class::construct_instance> will initialize the
348attribute to.
349
350B<NOTE:>
351If the value is a simple scalar (string or number), then it can
352be just passed as is. However, if you wish to initialize it with
353a HASH or ARRAY ref, then you need to wrap that inside a CODE
354reference, like so:
355
356 Class::MOP::Attribute->new('@foo' => (
357 default => sub { [] },
358 ));
359
360 # or ...
361
362 Class::MOP::Attribute->new('%foo' => (
363 default => sub { {} },
364 ));
365
366If you wish to initialize an attribute with a CODE reference
367itself, then you need to wrap that in a subroutine as well, like
368so:
369
370 Class::MOP::Attribute->new('&foo' => (
371 default => sub { sub { print "Hello World" } },
372 ));
373
374And lastly, if the value of your attribute is dependent upon
375some other aspect of the instance structure, then you can take
376advantage of the fact that when the I<default> value is a CODE
377reference, it is passed the raw (unblessed) instance structure
378as it's only argument. So you can do things like this:
379
380 Class::MOP::Attribute->new('$object_identity' => (
381 default => sub { Scalar::Util::refaddr($_[0]) },
382 ));
383
384This last feature is fairly limited as there is no gurantee of
385the order of attribute initializations, so you cannot perform
386any kind of dependent initializations. However, if this is
387something you need, you could subclass B<Class::MOP::Class> and
388this class to acheive it. However, this is currently left as
389an exercise to the reader :).
390
391=back
392
7d28758b 393The I<accessor>, I<reader>, I<writer>, I<predicate> and I<clearer> keys can
394contain either; the name of the method and an appropriate default one will be
395generated for you, B<or> a HASH ref containing exactly one key (which will be
396used as the name of the method) and one value, which should contain a CODE
397reference which will be installed as the method itself.
59e7697f 398
399=over 4
400
401=item I<accessor>
402
fe122940 403The I<accessor> is a standard perl-style read/write accessor. It will
404return the value of the attribute, and if a value is passed as an argument,
405it will assign that value to the attribute.
406
407B<NOTE:>
408This method will properly handle the following code, by assigning an
409C<undef> value to the attribute.
410
411 $object->set_something(undef);
412
59e7697f 413=item I<reader>
414
fe122940 415This is a basic read-only accessor, it will just return the value of
416the attribute.
417
59e7697f 418=item I<writer>
419
fe122940 420This is a basic write accessor, it accepts a single argument, and
421assigns that value to the attribute. This method does not intentially
422return a value, however perl will return the result of the last
423expression in the subroutine, which returns in this returning the
424same value that it was passed.
59e7697f 425
fe122940 426B<NOTE:>
427This method will properly handle the following code, by assigning an
428C<undef> value to the attribute.
59e7697f 429
fe122940 430 $object->set_something();
431
432=item I<predicate>
433
434This is a basic test to see if the value of the attribute is not
435C<undef>. It will return true (C<1>) if the attribute's value is
436defined, and false (C<0>) otherwise.
59e7697f 437
7d28758b 438=item I<clearer>
439
440This is the a method that will uninitialize the attr, reverting lazy values
441back to their "unfulfilled" state.
442
59e7697f 443=back
552e3d24 444
bd4e03f9 445=item B<clone (%options)>
446
447=item B<initialize_instance_slot ($instance, $params)>
448
552e3d24 449=back
450
16e960bd 451=head2 Value management
452
2367814a 453These methods are basically "backdoors" to the instance, which can be used
454to bypass the regular accessors, but still stay within the context of the MOP.
455
456These methods are not for general use, and should only be used if you really
457know what you are doing.
458
16e960bd 459=over 4
460
3545c727 461=item B<set_value ($instance, $value)>
16e960bd 462
463Set the value without going through the accessor. Note that this may be done to
464even attributes with just read only accessors.
465
3545c727 466=item B<get_value ($instance)>
16e960bd 467
468Return the value without going through the accessor. Note that this may be done
469even to attributes with just write only accessors.
470
3545c727 471=item B<has_value ($instance)>
472
2367814a 473Returns a boolean indicating if the item in the C<$instance> has a value in it.
474This is basically what the default C<predicate> method calls.
475
3545c727 476=item B<clear_value ($instance)>
477
2367814a 478This will clear the value in the C<$instance>. This is basically what the default
479C<clearer> would call. Note that this may be done even if the attirbute does not
480have any associated read, write or clear methods.
481
16e960bd 482=back
483
552e3d24 484=head2 Informational
485
fe122940 486These are all basic read-only value accessors for the values
487passed into C<new>. I think they are pretty much self-explanitory.
488
552e3d24 489=over 4
490
491=item B<name>
492
493=item B<accessor>
494
495=item B<reader>
496
497=item B<writer>
498
c50c603e 499=item B<predicate>
500
7d28758b 501=item B<clearer>
502
552e3d24 503=item B<init_arg>
504
495af518 505=item B<is_default_a_coderef>
506
fe122940 507=item B<default (?$instance)>
508
509As noted in the documentation for C<new> above, if the I<default>
510value is a CODE reference, this accessor will pass a single additional
511argument C<$instance> into it and return the value.
552e3d24 512
c57c8b10 513=item B<slots>
514
515Returns a list of slots required by the attribute. This is usually
516just one, which is the name of the attribute.
517
552e3d24 518=back
519
520=head2 Informational predicates
521
a2e85e6c 522These are all basic predicate methods for the values passed into C<new>.
fe122940 523
552e3d24 524=over 4
525
526=item B<has_accessor>
527
552e3d24 528=item B<has_reader>
529
552e3d24 530=item B<has_writer>
531
c50c603e 532=item B<has_predicate>
533
7d28758b 534=item B<has_clearer>
535
552e3d24 536=item B<has_init_arg>
537
552e3d24 538=item B<has_default>
539
552e3d24 540=back
541
9ec169fe 542=head2 Class association
543
2367814a 544These methods allow you to manage the attributes association with
545the class that contains it. These methods should not be used
546lightly, nor are they very magical, they are mostly used internally
547and by metaclass instances.
548
9ec169fe 549=over 4
550
551=item B<associated_class>
552
2367814a 553This returns the metaclass this attribute is associated with.
554
9ec169fe 555=item B<attach_to_class ($class)>
556
2367814a 557This will store a weaken reference to C<$class> internally. You should
558note that just changing the class assocation will not remove the attribute
559from it's old class, and initialize it (and it's accessors) in the new
560C<$class>. It is up to you to do this manually.
561
9ec169fe 562=item B<detach_from_class>
563
2367814a 564This will remove the weakened reference to the class. It does B<not>
565remove the attribute itself from the class (or remove it's accessors),
566you must do that yourself if you want too. Actually if that is what
567you want to do, you should probably be looking at
568L<Class::MOP::Class::remove_attribute> instead.
569
9ec169fe 570=back
571
552e3d24 572=head2 Attribute Accessor generation
573
574=over 4
575
ba38bf08 576=item B<accessor_metaclass>
577
2367814a 578Accessors are generated by an accessor metaclass, which is usually
579a subclass of C<Class::MOP::Method::Accessor>. This method returns
580the name of the accessor metaclass that this attribute uses.
581
582=item B<associate_method ($method)>
583
584This will associate a C<$method> with the given attribute which is
585used internally by the accessor generator.
3545c727 586
587=item B<associated_methods>
588
2367814a 589This will return the list of methods which have been associated with
590the C<associate_method> methods.
591
9ec169fe 592=item B<install_accessors>
2eb717d5 593
594This allows the attribute to generate and install code for it's own
a2e85e6c 595I<accessor/reader/writer/predicate> methods. This is called by
fe122940 596C<Class::MOP::Class::add_attribute>.
2eb717d5 597
9ec169fe 598This method will call C<process_accessors> for each of the possible
599method types (accessor, reader, writer & predicate).
600
601=item B<process_accessors ($type, $value)>
602
603This takes a C<$type> (accessor, reader, writer or predicate), and
604a C<$value> (the value passed into the constructor for each of the
605different types). It will then either generate the method itself
606(using the C<generate_*_method> methods listed below) or it will
607use the custom method passed through the constructor.
608
9ec169fe 609=item B<remove_accessors>
2eb717d5 610
611This allows the attribute to remove the method for it's own
7d28758b 612I<accessor/reader/writer/predicate/clearer>. This is called by
fe122940 613C<Class::MOP::Class::remove_attribute>.
2eb717d5 614
2367814a 615NOTE: This does not currently remove methods from the list returned
616by C<associated_methods>, that is on the TODO list.
617
2eb717d5 618=back
619
620=head2 Introspection
621
622=over 4
552e3d24 623
2eb717d5 624=item B<meta>
552e3d24 625
fe122940 626This will return a B<Class::MOP::Class> instance which is related
627to this class.
628
629It should also be noted that B<Class::MOP> will actually bootstrap
630this module by installing a number of attribute meta-objects into
631it's metaclass. This will allow this class to reap all the benifits
632of the MOP when subclassing it.
633
552e3d24 634=back
635
1a09d9cc 636=head1 AUTHORS
8b978dd5 637
a2e85e6c 638Stevan Little E<lt>stevan@iinteractive.comE<gt>
8b978dd5 639
1a09d9cc 640Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
641
8b978dd5 642=head1 COPYRIGHT AND LICENSE
643
2367814a 644Copyright 2006, 2007 by Infinity Interactive, Inc.
8b978dd5 645
646L<http://www.iinteractive.com>
647
648This library is free software; you can redistribute it and/or modify
649it under the same terms as Perl itself.
650
16e960bd 651=cut
652
7d28758b 653