c69ab026a448fa1455f21e75566d07f596a31501
[gitmo/Class-MOP.git] / lib / Class / MOP / Package.pm
1
2 package Class::MOP::Package;
3
4 use strict;
5 use warnings;
6
7 use Scalar::Util 'blessed', 'reftype';
8 use Carp         'confess';
9 use Sub::Name    'subname';
10
11 our $VERSION   = '0.92';
12 $VERSION = eval $VERSION;
13 our $AUTHORITY = 'cpan:STEVAN';
14
15 use base 'Class::MOP::Object';
16
17 # creation ...
18
19 sub initialize {
20     my ( $class, @args ) = @_;
21
22     unshift @args, "package" if @args % 2;
23
24     my %options = @args;
25     my $package_name = $options{package};
26
27
28     # we hand-construct the class 
29     # until we can bootstrap it
30     if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
31         return $meta;
32     } else {
33         my $meta = ( ref $class || $class )->_new({
34             'package'   => $package_name,
35             %options,
36         });
37
38         Class::MOP::store_metaclass_by_name($package_name, $meta);
39
40         return $meta;
41     }
42 }
43
44 sub reinitialize {
45     my ( $class, @args ) = @_;
46
47     unshift @args, "package" if @args % 2;
48
49     my %options = @args;
50     my $package_name = delete $options{package};
51
52     (defined $package_name && $package_name
53       && (!blessed $package_name || $package_name->isa('Class::MOP::Package')))
54         || confess "You must pass a package name or an existing Class::MOP::Package instance";
55
56     $package_name = $package_name->name
57         if blessed $package_name;
58
59     Class::MOP::remove_metaclass_by_name($package_name);
60
61     $class->initialize($package_name, %options); # call with first arg form for compat
62 }
63
64 sub _new {
65     my $class = shift;
66
67     return Class::MOP::Class->initialize($class)->new_object(@_)
68         if $class ne __PACKAGE__;
69
70     my $params = @_ == 1 ? $_[0] : {@_};
71
72     return bless {
73         package   => $params->{package},
74
75         # NOTE:
76         # because of issues with the Perl API
77         # to the typeglob in some versions, we
78         # need to just always grab a new
79         # reference to the hash in the accessor.
80         # Ideally we could just store a ref and
81         # it would Just Work, but oh well :\
82
83         namespace => \undef,
84
85     } => $class;
86 }
87
88 # Attributes
89
90 # NOTE:
91 # all these attribute readers will be bootstrapped 
92 # away in the Class::MOP bootstrap section
93
94 sub namespace { 
95     # NOTE:
96     # because of issues with the Perl API 
97     # to the typeglob in some versions, we 
98     # need to just always grab a new 
99     # reference to the hash here. Ideally 
100     # we could just store a ref and it would
101     # Just Work, but oh well :\    
102     no strict 'refs';    
103     no warnings 'uninitialized';
104     \%{$_[0]->{'package'} . '::'} 
105 }
106
107 sub method_metaclass         { $_[0]->{'method_metaclass'}            }
108 sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'}    }
109
110 sub _method_map              { $_[0]->{'methods'}                     }
111
112 # utility methods
113
114 {
115     my %SIGIL_MAP = (
116         '$' => 'SCALAR',
117         '@' => 'ARRAY',
118         '%' => 'HASH',
119         '&' => 'CODE',
120     );
121     
122     sub _deconstruct_variable_name {
123         my ($self, $variable) = @_;
124
125         (defined $variable)
126             || confess "You must pass a variable name";    
127
128         my $sigil = substr($variable, 0, 1, '');
129
130         (defined $sigil)
131             || confess "The variable name must include a sigil";    
132
133         (exists $SIGIL_MAP{$sigil})
134             || confess "I do not recognize that sigil '$sigil'";    
135         
136         return ($variable, $sigil, $SIGIL_MAP{$sigil});
137     }
138 }
139
140 # Class attributes
141
142 # ... these functions have to touch the symbol table itself,.. yuk
143
144 sub remove_package_glob {
145     my ($self, $name) = @_;
146     delete $self->namespace->{$name};
147 }
148
149 sub remove_package_symbol {
150     my ($self, $variable) = @_;
151
152     my ($name, $sigil, $type) = ref $variable eq 'HASH'
153         ? @{$variable}{qw[name sigil type]}
154         : $self->_deconstruct_variable_name($variable);
155
156     # FIXME:
157     # no doubt this is grossly inefficient and 
158     # could be done much easier and faster in XS
159
160     my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
161         { sigil => '$', type => 'SCALAR', name => $name },
162         { sigil => '@', type => 'ARRAY',  name => $name },
163         { sigil => '%', type => 'HASH',   name => $name },
164         { sigil => '&', type => 'CODE',   name => $name },
165     );
166
167     my ($scalar, $array, $hash, $code);
168     if ($type eq 'SCALAR') {
169         $array  = $self->get_package_symbol($array_desc)  if $self->has_package_symbol($array_desc);
170         $hash   = $self->get_package_symbol($hash_desc)   if $self->has_package_symbol($hash_desc);     
171         $code   = $self->get_package_symbol($code_desc)   if $self->has_package_symbol($code_desc);     
172     }
173     elsif ($type eq 'ARRAY') {
174         $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
175         $hash   = $self->get_package_symbol($hash_desc)   if $self->has_package_symbol($hash_desc);     
176         $code   = $self->get_package_symbol($code_desc)   if $self->has_package_symbol($code_desc);
177     }
178     elsif ($type eq 'HASH') {
179         $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
180         $array  = $self->get_package_symbol($array_desc)  if $self->has_package_symbol($array_desc);        
181         $code   = $self->get_package_symbol($code_desc)   if $self->has_package_symbol($code_desc);      
182     }
183     elsif ($type eq 'CODE') {
184         $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
185         $array  = $self->get_package_symbol($array_desc)  if $self->has_package_symbol($array_desc);        
186         $hash   = $self->get_package_symbol($hash_desc)   if $self->has_package_symbol($hash_desc);        
187     }    
188     else {
189         confess "This should never ever ever happen";
190     }
191         
192     $self->remove_package_glob($name);
193     
194     $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;      
195     $self->add_package_symbol($array_desc  => $array)  if defined $array;    
196     $self->add_package_symbol($hash_desc   => $hash)   if defined $hash;
197     $self->add_package_symbol($code_desc   => $code)   if defined $code;            
198 }
199
200 sub list_all_package_symbols {
201     my ($self, $type_filter) = @_;
202
203     my $namespace = $self->namespace;
204     return keys %{$namespace} unless defined $type_filter;
205     
206     # NOTE:
207     # or we can filter based on 
208     # type (SCALAR|ARRAY|HASH|CODE)
209     if ( $type_filter eq 'CODE' ) {
210         return grep { 
211         (ref($namespace->{$_})
212                 ? (ref($namespace->{$_}) eq 'SCALAR')
213                 : (ref(\$namespace->{$_}) eq 'GLOB'
214                    && defined(*{$namespace->{$_}}{CODE})));
215         } keys %{$namespace};
216     } else {
217         return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
218     }
219 }
220
221 ## Methods
222
223 sub wrap_method_body {
224     my ( $self, %args ) = @_;
225
226     ('CODE' eq ref $args{body})
227         || confess "Your code block must be a CODE reference";
228
229     $self->method_metaclass->wrap(
230         package_name => $self->name,
231         %args,
232     );
233 }
234
235 sub add_method {
236     my ($self, $method_name, $method) = @_;
237     (defined $method_name && $method_name)
238         || confess "You must define a method name";
239
240     my $body;
241     if (blessed($method)) {
242         $body = $method->body;
243         if ($method->package_name ne $self->name) {
244             $method = $method->clone(
245                 package_name => $self->name,
246                 name         => $method_name            
247             ) if $method->can('clone');
248         }
249
250         $method->attach_to_class($self);
251         $self->_method_map->{$method_name} = $method;
252     }
253     else {
254         # If a raw code reference is supplied, its method object is not created.
255         # The method object won't be created until required.
256         $body = $method;
257     }
258
259     $self->add_package_symbol(
260         { sigil => '&', type => 'CODE', name => $method_name },
261         $body,
262     );
263 }
264
265 sub _code_is_mine {
266     my ( $self, $code ) = @_;
267
268     my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
269
270     return $code_package && $code_package eq $self->name
271         || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
272 }
273
274 sub has_method {
275     my ($self, $method_name) = @_;
276     (defined $method_name && $method_name)
277         || confess "You must define a method name";
278
279     return defined($self->get_method($method_name));
280 }
281
282 sub get_method {
283     my ($self, $method_name) = @_;
284     (defined $method_name && $method_name)
285         || confess "You must define a method name";
286
287     my $method_map    = $self->_method_map;
288     my $method_object = $method_map->{$method_name};
289     my $code = $self->get_package_symbol({
290         name  => $method_name,
291         sigil => '&',
292         type  => 'CODE',
293     });
294
295     unless ( $method_object && $method_object->body == ( $code || 0 ) ) {
296         if ( $code && $self->_code_is_mine($code) ) {
297             $method_object = $method_map->{$method_name}
298                 = $self->wrap_method_body(
299                 body                 => $code,
300                 name                 => $method_name,
301                 associated_metaclass => $self,
302                 );
303         }
304         else {
305             delete $method_map->{$method_name};
306             return undef;
307         }
308     }
309
310     return $method_object;
311 }
312
313 sub remove_method {
314     my ($self, $method_name) = @_;
315     (defined $method_name && $method_name)
316         || confess "You must define a method name";
317
318     my $removed_method = delete $self->get_method_map->{$method_name};
319     
320     $self->remove_package_symbol(
321         { sigil => '&', type => 'CODE', name => $method_name }
322     );
323
324     $removed_method->detach_from_class if $removed_method;
325
326     $self->update_package_cache_flag; # still valid, since we just removed the method from the map
327
328     return $removed_method;
329 }
330
331 sub get_method_list {
332     my $self = shift;
333     return grep { $self->has_method($_) } keys %{ $self->namespace };
334 }
335
336 1;
337
338 __END__
339
340 =pod
341
342 =head1 NAME 
343
344 Class::MOP::Package - Package Meta Object
345
346 =head1 DESCRIPTION
347
348 The Package Protocol provides an abstraction of a Perl 5 package. A
349 package is basically namespace, and this module provides methods for
350 looking at and changing that namespace's symbol table.
351
352 =head1 METHODS
353
354 =over 4
355
356 =item B<< Class::MOP::Package->initialize($package_name) >>
357
358 This method creates a new C<Class::MOP::Package> instance which
359 represents specified package. If an existing metaclass object exists
360 for the package, that will be returned instead.
361
362 =item B<< Class::MOP::Package->reinitialize($package) >>
363
364 This method forcibly removes any existing metaclass for the package
365 before calling C<initialize>. In contrast to C<initialize>, you may
366 also pass an existing C<Class::MOP::Package> instance instead of just
367 a package name as C<$package>.
368
369 Do not call this unless you know what you are doing.
370
371 =item B<< $metapackage->name >>
372
373 This is returns the package's name, as passed to the constructor.
374
375 =item B<< $metapackage->namespace >>
376
377 This returns a hash reference to the package's symbol table. The keys
378 are symbol names and the values are typeglob references.
379
380 =item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
381
382 This method accepts a variable name and an optional initial value. The
383 C<$variable_name> must contain a leading sigil.
384
385 This method creates the variable in the package's symbol table, and
386 sets it to the initial value if one was provided.
387
388 =item B<< $metapackage->get_package_symbol($variable_name) >>
389
390 Given a variable name, this method returns the variable as a reference
391 or undef if it does not exist. The C<$variable_name> must contain a
392 leading sigil.
393
394 =item B<< $metapackage->has_package_symbol($variable_name) >>
395
396 Returns true if there is a package variable defined for
397 C<$variable_name>. The C<$variable_name> must contain a leading sigil.
398
399 =item B<< $metapackage->remove_package_symbol($variable_name) >>
400
401 This will remove the package variable specified C<$variable_name>. The
402 C<$variable_name> must contain a leading sigil.
403
404 =item B<< $metapackage->remove_package_glob($glob_name) >>
405
406 Given the name of a glob, this will remove that glob from the
407 package's symbol table. Glob names do not include a sigil. Removing
408 the glob removes all variables and subroutines with the specified
409 name.
410
411 =item B<< $metapackage->list_all_package_symbols($type_filter) >>
412
413 This will list all the glob names associated with the current
414 package. These names do not have leading sigils.
415
416 You can provide an optional type filter, which should be one of
417 'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
418
419 =item B<< $metapackage->get_all_package_symbols($type_filter) >>
420
421 This works much like C<list_all_package_symbols>, but it returns a
422 hash reference. The keys are glob names and the values are references
423 to the value for that name.
424
425 =back
426
427 =head2 Method introspection and creation
428
429 These methods allow you to introspect a class's methods, as well as
430 add, remove, or change methods.
431
432 Determining what is truly a method in a Perl 5 class requires some
433 heuristics (aka guessing).
434
435 Methods defined outside the package with a fully qualified name (C<sub
436 Package::name { ... }>) will be included. Similarly, methods named
437 with a fully qualified name using L<Sub::Name> are also included.
438
439 However, we attempt to ignore imported functions.
440
441 Ultimately, we are using heuristics to determine what truly is a
442 method in a class, and these heuristics may get the wrong answer in
443 some edge cases. However, for most "normal" cases the heuristics work
444 correctly.
445
446 =over 4
447
448 =item B<< $metapackage->get_method($method_name) >>
449
450 This will return a L<Class::MOP::Method> for the specified
451 C<$method_name>. If the class does not have the specified method, it
452 returns C<undef>
453
454 =item B<< $metapackage->has_method($method_name) >>
455
456 Returns a boolean indicating whether or not the class defines the
457 named method. It does not include methods inherited from parent
458 classes.
459
460 =item B<< $metapackage->get_method_map >>
461
462 Returns a hash reference representing the methods defined in this
463 class. The keys are method names and the values are
464 L<Class::MOP::Method> objects.
465
466 =item B<< $metapackage->get_method_list >>
467
468 This will return a list of method I<names> for all methods defined in
469 this class.
470
471 =item B<< $metapackage->add_method($method_name, $method) >>
472
473 This method takes a method name and a subroutine reference, and adds
474 the method to the class.
475
476 The subroutine reference can be a L<Class::MOP::Method>, and you are
477 strongly encouraged to pass a meta method object instead of a code
478 reference. If you do so, that object gets stored as part of the
479 class's method map directly. If not, the meta information will have to
480 be recreated later, and may be incorrect.
481
482 If you provide a method object, this method will clone that object if
483 the object's package name does not match the class name. This lets us
484 track the original source of any methods added from other classes
485 (notably Moose roles).
486
487 =item B<< $metapackage->remove_method($method_name) >>
488
489 Remove the named method from the class. This method returns the
490 L<Class::MOP::Method> object for the method.
491
492 =item B<< $metapackage->method_metaclass >>
493
494 Returns the class name of the method metaclass, see
495 L<Class::MOP::Method> for more information on the method metaclass.
496
497 =item B<< $metapackage->wrapped_method_metaclass >>
498
499 Returns the class name of the wrapped method metaclass, see
500 L<Class::MOP::Method::Wrapped> for more information on the wrapped
501 method metaclass.
502
503 =item B<< Class::MOP::Package->meta >>
504
505 This will return a L<Class::MOP::Class> instance for this class.
506
507 =back
508
509 =head1 AUTHORS
510
511 Stevan Little E<lt>stevan@iinteractive.comE<gt>
512
513 =head1 COPYRIGHT AND LICENSE
514
515 Copyright 2006-2009 by Infinity Interactive, Inc.
516
517 L<http://www.iinteractive.com>
518
519 This library is free software; you can redistribute it and/or modify
520 it under the same terms as Perl itself.
521
522 =cut