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