Class::MOP - lots of knot tying, this should make subclassing more reliable and strai...
[gitmo/Class-MOP.git] / lib / Class / MOP / Class.pm
1
2 package Class::MOP::Class;
3
4 use strict;
5 use warnings;
6
7 use Carp         'confess';
8 use Scalar::Util 'blessed', 'reftype';
9 use Sub::Name    'subname';
10 use B            'svref_2object';
11
12 our $VERSION = '0.01';
13
14 # Self-introspection
15
16 sub meta { $_[0]->initialize($_[0]) }
17
18 # Creation
19
20 {
21     # Metaclasses are singletons, so we cache them here.
22     # there is no need to worry about destruction though
23     # because they should die only when the program dies.
24     # After all, do package definitions even get reaped?
25     my %METAS;
26     sub initialize {
27         my ($class, $package_name) = @_;
28         (defined $package_name && $package_name)
29             || confess "You must pass a package name";        
30         return $METAS{$package_name} if exists $METAS{$package_name};
31         $METAS{$package_name} = $class->construct_class_instance($package_name);
32     }
33     
34     # NOTE: (meta-circularity) 
35     # this is a special form of &construct_instance 
36     # (see below), which is used to construct class
37     # meta-object instances. It will be replaces in 
38     # the bootstrap section in Class::MOP with one 
39     # which uses the normal &construct_instance.
40     sub construct_class_instance {
41         my ($class, $package_name) = @_;
42         (defined $package_name && $package_name)
43             || confess "You must pass a package name";        
44         bless { 
45             '$:pkg'   => $package_name, 
46             '%:attrs' => {} 
47         } => blessed($class) || $class        
48     }
49 }
50
51 sub create {
52     my ($class, $package_name, $package_version, %options) = @_;
53     (defined $package_name && $package_name)
54         || confess "You must pass a package name";
55     my $code = "package $package_name;";
56     $code .= "\$$package_name\:\:VERSION = '$package_version';" 
57         if defined $package_version;
58     eval $code;
59     confess "creation of $package_name failed : $@" if $@;    
60     my $meta = $class->initialize($package_name);
61     $meta->superclasses(@{$options{superclasses}})
62         if exists $options{superclasses};
63     # NOTE:
64     # process attributes first, so that they can 
65     # install accessors, but locally defined methods
66     # can then overwrite them. It is maybe a little odd, but
67     # I think this should be the order of things.
68     if (exists $options{attributes}) {
69         foreach my $attr (@{$options{attributes}}) {
70             $meta->add_attribute($attr);
71         }
72     }        
73     if (exists $options{methods}) {
74         foreach my $method_name (keys %{$options{methods}}) {
75             $meta->add_method($method_name, $options{methods}->{$method_name});
76         }
77     }  
78     return $meta;
79 }
80
81 # Instance Construction
82
83 sub construct_instance {
84     my ($class, %params) = @_;
85     my $instance = {};
86     foreach my $attr (map { $_->{attribute} } $class->compute_all_applicable_attributes()) {
87         # if the attr has an init_arg, use that, otherwise,
88         # use the attributes name itself as the init_arg
89         my $init_arg = $attr->has_init_arg() ? $attr->init_arg() : $attr->name;
90         # try to fetch the init arg from the %params ...
91         my $val;        
92         $val = $params{$init_arg} if exists $params{$init_arg};
93         # if nothing was in the %params, we can use the 
94         # attribute's default value (if it has one)
95         $val ||= $attr->default($instance) if $attr->has_default();
96         # now add this to the instance structure
97         $instance->{$attr->name} = $val;
98     }
99     return $instance;
100 }
101
102 # Informational 
103
104 sub name { $_[0]->{'$:pkg'} }
105
106 sub version {  
107     my $self = shift;
108     no strict 'refs';
109     ${$self->name . '::VERSION'};
110 }
111
112 # Inheritance
113
114 sub superclasses {
115     my $self = shift;
116     no strict 'refs';
117     if (@_) {
118         my @supers = @_;
119         @{$self->name . '::ISA'} = @supers;
120     }
121     @{$self->name . '::ISA'};        
122 }
123
124 sub class_precedence_list {
125     my $self = shift;
126     # NOTE:
127     # We need to check for ciruclar inheirtance here.
128     # This will do nothing if all is well, and blow
129     # up otherwise. Yes, it's an ugly hack, better 
130     # suggestions are welcome.
131     { $self->name->isa('This is a test for circular inheritance') }
132     # ... and no back to our regularly scheduled program
133     (
134         $self->name, 
135         map { 
136             $self->initialize($_)->class_precedence_list()
137         } $self->superclasses()
138     );   
139 }
140
141 ## Methods
142
143 sub add_method {
144     my ($self, $method_name, $method) = @_;
145     (defined $method_name && $method_name)
146         || confess "You must define a method name";
147     # use reftype here to allow for blessed subs ...
148     (reftype($method) && reftype($method) eq 'CODE')
149         || confess "Your code block must be a CODE reference";
150     my $full_method_name = ($self->name . '::' . $method_name);    
151         
152     no strict 'refs';
153     no warnings 'redefine';
154     *{$full_method_name} = subname $full_method_name => $method;
155 }
156
157 {
158
159     ## private utility functions for has_method
160     my $_find_subroutine_package_name = sub { eval { svref_2object($_[0])->GV->STASH->NAME } || '' };
161     my $_find_subroutine_name         = sub { eval { svref_2object($_[0])->GV->NAME        } || '' };
162
163     sub has_method {
164         my ($self, $method_name) = @_;
165         (defined $method_name && $method_name)
166             || confess "You must define a method name";    
167     
168         my $sub_name = ($self->name . '::' . $method_name);    
169         
170         no strict 'refs';
171         return 0 if !defined(&{$sub_name});        
172         return 0 if $_find_subroutine_package_name->(\&{$sub_name}) ne $self->name &&
173                     $_find_subroutine_name->(\&{$sub_name})         ne '__ANON__';
174         return 1;
175     }
176
177 }
178
179 sub get_method {
180     my ($self, $method_name) = @_;
181     (defined $method_name && $method_name)
182         || confess "You must define a method name";
183
184     no strict 'refs';    
185     return \&{$self->name . '::' . $method_name} 
186         if $self->has_method($method_name);   
187     return; # <- make sure to return undef
188 }
189
190 sub remove_method {
191     my ($self, $method_name) = @_;
192     (defined $method_name && $method_name)
193         || confess "You must define a method name";
194     
195     my $removed_method = $self->get_method($method_name);    
196     
197     no strict 'refs';
198     delete ${$self->name . '::'}{$method_name}
199         if defined $removed_method;
200         
201     return $removed_method;
202 }
203
204 sub get_method_list {
205     my $self = shift;
206     no strict 'refs';
207     grep { $self->has_method($_) } %{$self->name . '::'};
208 }
209
210 sub compute_all_applicable_methods {
211     my $self = shift;
212     my @methods;
213     # keep a record of what we have seen
214     # here, this will handle all the 
215     # inheritence issues because we are 
216     # using the &class_precedence_list
217     my (%seen_class, %seen_method);
218     foreach my $class ($self->class_precedence_list()) {
219         next if $seen_class{$class};
220         $seen_class{$class}++;
221         # fetch the meta-class ...
222         my $meta = $self->initialize($class);
223         foreach my $method_name ($meta->get_method_list()) { 
224             next if exists $seen_method{$method_name};
225             $seen_method{$method_name}++;
226             push @methods => {
227                 name  => $method_name, 
228                 class => $class,
229                 code  => $meta->get_method($method_name)
230             };
231         }
232     }
233     return @methods;
234 }
235
236 sub find_all_methods_by_name {
237     my ($self, $method_name) = @_;
238     (defined $method_name && $method_name)
239         || confess "You must define a method name to find";    
240     my @methods;
241     # keep a record of what we have seen
242     # here, this will handle all the 
243     # inheritence issues because we are 
244     # using the &class_precedence_list
245     my %seen_class;
246     foreach my $class ($self->class_precedence_list()) {
247         next if $seen_class{$class};
248         $seen_class{$class}++;
249         # fetch the meta-class ...
250         my $meta = $self->initialize($class);
251         push @methods => {
252             name  => $method_name, 
253             class => $class,
254             code  => $meta->get_method($method_name)
255         } if $meta->has_method($method_name);
256     }
257     return @methods;
258
259 }
260
261 ## Attributes
262
263 sub add_attribute {
264     my ($self,$attribute) = @_;
265     (blessed($attribute) && $attribute->isa('Class::MOP::Attribute'))
266         || confess "Your attribute must be an instance of Class::MOP::Attribute (or a subclass)";
267     $attribute->install_accessors($self);        
268     $self->{'%:attrs'}->{$attribute->name} = $attribute;
269 }
270
271 sub has_attribute {
272     my ($self, $attribute_name) = @_;
273     (defined $attribute_name && $attribute_name)
274         || confess "You must define an attribute name";
275     exists $self->{'%:attrs'}->{$attribute_name} ? 1 : 0;    
276
277
278 sub get_attribute {
279     my ($self, $attribute_name) = @_;
280     (defined $attribute_name && $attribute_name)
281         || confess "You must define an attribute name";
282     return $self->{'%:attrs'}->{$attribute_name} 
283         if $self->has_attribute($attribute_name);    
284
285
286 sub remove_attribute {
287     my ($self, $attribute_name) = @_;
288     (defined $attribute_name && $attribute_name)
289         || confess "You must define an attribute name";
290     my $removed_attribute = $self->{'%:attrs'}->{$attribute_name};    
291     delete $self->{'%:attrs'}->{$attribute_name} 
292         if defined $removed_attribute;
293     $removed_attribute->remove_accessors($self);        
294     return $removed_attribute;
295
296
297 sub get_attribute_list {
298     my $self = shift;
299     keys %{$self->{'%:attrs'}};
300
301
302 sub compute_all_applicable_attributes {
303     my $self = shift;
304     my @attrs;
305     # keep a record of what we have seen
306     # here, this will handle all the 
307     # inheritence issues because we are 
308     # using the &class_precedence_list
309     my (%seen_class, %seen_attr);
310     foreach my $class ($self->class_precedence_list()) {
311         next if $seen_class{$class};
312         $seen_class{$class}++;
313         # fetch the meta-class ...
314         my $meta = $self->initialize($class);
315         foreach my $attr_name ($meta->get_attribute_list()) { 
316             next if exists $seen_attr{$attr_name};
317             $seen_attr{$attr_name}++;
318             push @attrs => {
319                 name      => $attr_name, 
320                 class     => $class,
321                 attribute => $meta->get_attribute($attr_name)
322             };
323         }
324     }
325     return @attrs;    
326 }
327
328 1;
329
330 __END__
331
332 =pod
333
334 =head1 NAME 
335
336 Class::MOP::Class - Class Meta Object
337
338 =head1 SYNOPSIS
339
340 =head1 DESCRIPTION
341
342 =head1 METHODS
343
344 =head2 Self Introspection
345
346 =over 4
347
348 =item B<meta>
349
350 This allows Class::MOP::Class to actually introspect itself.
351
352 =back
353
354 =head2 Class construction
355
356 These methods handle creating Class objects, which can be used to 
357 both create new classes, and analyze pre-existing ones. 
358
359 This module will internally store references to all the instances 
360 you create with these methods, so that they do not need to be 
361 created any more than nessecary. Basically, they are singletons.
362
363 =over 4
364
365 =item B<create ($package_name, ?$package_version,
366                 superclasses => ?@superclasses, 
367                 methods      => ?%methods, 
368                 attributes   => ?%attributes)>
369
370 This returns the basic Class object, bringing the specified 
371 C<$package_name> into existence and adding any of the 
372 C<$package_version>, C<@superclasses>, C<%methods> and C<%attributes> 
373 to it.
374
375 =item B<initialize ($package_name)>
376
377 This initializes a Class object for a given a C<$package_name>.
378
379 =back
380
381 =head2 Instance construction
382
383 =over 4
384
385 =item B<construct_instance (%params)>
386
387 This will construct and instance using a HASH ref as storage 
388 (currently only HASH references are supported). This will collect all 
389 the applicable attribute meta-objects and layout out the fields in the 
390 HASH ref, it will then initialize them using either use the 
391 corresponding key in C<%params> or any default value or initializer 
392 found in the attribute meta-object.
393
394 =item B<construct_class_instance ($package_name)>
395
396 This will construct an instance of B<Class::MOP::Class>, it is 
397 here so that we can actually "tie the knot" for B<Class::MOP::Class> 
398 to use C<construct_instance> once all the bootstrapping is done. This 
399 method is used internally by C<initialize> and should never be called
400 from outside of that method really.
401
402 =back
403
404 =head2 Informational 
405
406 =over 4
407
408 =item B<name>
409
410 This is a read-only attribute which returns the package name that 
411 the Class is stored in.
412
413 =item B<version>
414
415 This is a read-only attribute which returns the C<$VERSION> of the 
416 package the Class is stored in.
417
418 =back
419
420 =head2 Inheritance Relationships
421
422 =over 4
423
424 =item B<superclasses (?@superclasses)>
425
426 This is a read-write attribute which represents the superclass 
427 relationships of this Class. Basically, it can get and set the 
428 C<@ISA> for you.
429
430 =item B<class_precedence_list>
431
432 This computes the a list of the Class's ancestors in the same order 
433 in which method dispatch will be done. 
434
435 =back
436
437 =head2 Methods
438
439 =over 4
440
441 =item B<add_method ($method_name, $method)>
442
443 This will take a C<$method_name> and CODE reference to that 
444 C<$method> and install it into the Class. 
445
446 B<NOTE> : This does absolutely nothing special to C<$method> 
447 other than use B<Sub::Name> to make sure it is tagged with the 
448 correct name, and therefore show up correctly in stack traces and 
449 such.
450
451 =item B<has_method ($method_name)>
452
453 This just provides a simple way to check if the Class implements 
454 a specific C<$method_name>. It will I<not> however, attempt to check 
455 if the class inherits the method.
456
457 This will correctly handle functions defined outside of the package 
458 that use a fully qualified name (C<sub Package::name { ... }>).
459
460 This will correctly handle functions renamed with B<Sub::Name> and 
461 installed using the symbol tables. However, if you are naming the 
462 subroutine outside of the package scope, you must use the fully 
463 qualified name, including the package name, for C<has_method> to 
464 correctly identify it. 
465
466 This will attempt to correctly ignore functions imported from other 
467 packages using B<Exporter>. It breaks down if the function imported 
468 is an C<__ANON__> sub (such as with C<use constant>), which very well 
469 may be a valid method being applied to the class. 
470
471 In short, this method cannot always be trusted to determine if the 
472 C<$method_name> is actually a method. However, it will DWIM about 
473 90% of the time, so it's a small trade off IMO.
474
475 =item B<get_method ($method_name)>
476
477 This will return a CODE reference of the specified C<$method_name>, 
478 or return undef if that method does not exist.
479
480 =item B<remove_method ($method_name)>
481
482 This will attempt to remove a given C<$method_name> from the Class. 
483 It will return the CODE reference that it has removed, and will 
484 attempt to use B<Sub::Name> to clear the methods associated name.
485
486 =item B<get_method_list>
487
488 This will return a list of method names for all I<locally> defined 
489 methods. It does B<not> provide a list of all applicable methods, 
490 including any inherited ones. If you want a list of all applicable 
491 methods, use the C<compute_all_applicable_methods> method.
492
493 =item B<compute_all_applicable_methods>
494
495 This will return a list of all the methods names this Class will 
496 support, taking into account inheritance. The list will be a list of 
497 HASH references, each one containing the following information; method 
498 name, the name of the class in which the method lives and a CODE 
499 reference for the actual method.
500
501 =item B<find_all_methods_by_name ($method_name)>
502
503 This will traverse the inheritence hierarchy and locate all methods 
504 with a given C<$method_name>. Similar to 
505 C<compute_all_applicable_methods> it returns a list of HASH references 
506 with the following information; method name (which will always be the 
507 same as C<$method_name>), the name of the class in which the method 
508 lives and a CODE reference for the actual method.
509
510 The list of methods produced is a distinct list, meaning there are no 
511 duplicates in it. This is especially useful for things like object 
512 initialization and destruction where you only want the method called 
513 once, and in the correct order.
514
515 =back
516
517 =head2 Attributes
518
519 It should be noted that since there is no one consistent way to define 
520 the attributes of a class in Perl 5. These methods can only work with 
521 the information given, and can not easily discover information on 
522 their own.
523
524 =over 4
525
526 =item B<add_attribute ($attribute_name, $attribute_meta_object)>
527
528 This stores a C<$attribute_meta_object> in the Class object and 
529 associates it with the C<$attribute_name>. Unlike methods, attributes 
530 within the MOP are stored as meta-information only. They will be used 
531 later to construct instances from (see C<construct_instance> above).
532 More details about the attribute meta-objects can be found in the 
533 L<The Attribute protocol> section of this document.
534
535 =item B<has_attribute ($attribute_name)>
536
537 Checks to see if this Class has an attribute by the name of 
538 C<$attribute_name> and returns a boolean.
539
540 =item B<get_attribute ($attribute_name)>
541
542 Returns the attribute meta-object associated with C<$attribute_name>, 
543 if none is found, it will return undef. 
544
545 =item B<remove_attribute ($attribute_name)>
546
547 This will remove the attribute meta-object stored at 
548 C<$attribute_name>, then return the removed attribute meta-object. 
549
550 B<NOTE:> Removing an attribute will only affect future instances of 
551 the class, it will not make any attempt to remove the attribute from 
552 any existing instances of the class.
553
554 =item B<get_attribute_list>
555
556 This returns a list of attribute names which are defined in the local 
557 class. If you want a list of all applicable attributes for a class, 
558 use the C<compute_all_applicable_attributes> method.
559
560 =item B<compute_all_applicable_attributes>
561
562 This will traverse the inheritance heirachy and return a list of HASH 
563 references for all the applicable attributes for this class. The HASH 
564 references will contain the following information; the attribute name, 
565 the class which the attribute is associated with and the actual 
566 attribute meta-object.
567
568 =back
569
570 =head1 AUTHOR
571
572 Stevan Little E<gt>stevan@iinteractive.comE<lt>
573
574 =head1 COPYRIGHT AND LICENSE
575
576 Copyright 2006 by Infinity Interactive, Inc.
577
578 L<http://www.iinteractive.com>
579
580 This library is free software; you can redistribute it and/or modify
581 it under the same terms as Perl itself. 
582
583 =cut