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