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