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