Fix RT 48985
[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
d499b013 11our $VERSION = '0.92_01';
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';
8683db0e 103 \%{$_[0]->{'package'} . '::'}
56dcfc1a 104}
6d5355c3 105
b1ff395f 106sub method_metaclass { $_[0]->{'method_metaclass'} }
107sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'} }
108
4eb970b2 109sub _method_map { $_[0]->{'methods'} }
110
a5e51f0b 111# utility methods
6d5355c3 112
c0cbf4d9 113{
114 my %SIGIL_MAP = (
115 '$' => 'SCALAR',
116 '@' => 'ARRAY',
117 '%' => 'HASH',
118 '&' => 'CODE',
119 );
6d5355c3 120
a5e51f0b 121 sub _deconstruct_variable_name {
122 my ($self, $variable) = @_;
123
c0cbf4d9 124 (defined $variable)
125 || confess "You must pass a variable name";
a5e51f0b 126
f430cfa4 127 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 128
c0cbf4d9 129 (defined $sigil)
130 || confess "The variable name must include a sigil";
a5e51f0b 131
c0cbf4d9 132 (exists $SIGIL_MAP{$sigil})
a5e51f0b 133 || confess "I do not recognize that sigil '$sigil'";
134
f430cfa4 135 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 136 }
a5e51f0b 137}
6d5355c3 138
a5e51f0b 139# Class attributes
6d5355c3 140
c46b802b 141# ... these functions have to touch the symbol table itself,.. yuk
142
86e1c8d8 143sub add_package_symbol {
144 my ($self, $variable, $initial_value) = @_;
145
146 my ($name, $sigil, $type) = ref $variable eq 'HASH'
147 ? @{$variable}{qw[name sigil type]}
148 : $self->_deconstruct_variable_name($variable);
149
150 my $pkg = $self->{'package'};
151
152 no strict 'refs';
153 no warnings 'redefine', 'misc', 'prototype';
154 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
155}
156
c46b802b 157sub remove_package_glob {
158 my ($self, $name) = @_;
86e1c8d8 159 no strict 'refs';
160 delete ${$self->name . '::'}{$name};
161}
162
163# ... these functions deal with stuff on the namespace level
164
165sub has_package_symbol {
166 my ( $self, $variable ) = @_;
167
168 my ( $name, $sigil, $type )
169 = ref $variable eq 'HASH'
170 ? @{$variable}{qw[name sigil type]}
171 : $self->_deconstruct_variable_name($variable);
172
173 my $namespace = $self->namespace;
174
175 return 0 unless exists $namespace->{$name};
176
177 my $entry_ref = \$namespace->{$name};
178 if ( reftype($entry_ref) eq 'GLOB' ) {
179 if ( $type eq 'SCALAR' ) {
180 return defined( ${ *{$entry_ref}{SCALAR} } );
181 }
182 else {
183 return defined( *{$entry_ref}{$type} );
184 }
185 }
186 else {
187
188 # a symbol table entry can be -1 (stub), string (stub with prototype),
189 # or reference (constant)
190 return $type eq 'CODE';
191 }
192}
193
194sub get_package_symbol {
195 my ($self, $variable) = @_;
196
197 my ($name, $sigil, $type) = ref $variable eq 'HASH'
198 ? @{$variable}{qw[name sigil type]}
199 : $self->_deconstruct_variable_name($variable);
200
201 my $namespace = $self->namespace;
202
203 # FIXME
204 $self->add_package_symbol($variable)
205 unless exists $namespace->{$name};
206
207 my $entry_ref = \$namespace->{$name};
208
209 if ( ref($entry_ref) eq 'GLOB' ) {
210 return *{$entry_ref}{$type};
211 }
212 else {
213 if ( $type eq 'CODE' ) {
214 no strict 'refs';
215 return \&{ $self->name . '::' . $name };
216 }
217 else {
218 return undef;
219 }
220 }
a5e51f0b 221}
6d5355c3 222
a5e51f0b 223sub remove_package_symbol {
224 my ($self, $variable) = @_;
225
8b49a472 226 my ($name, $sigil, $type) = ref $variable eq 'HASH'
227 ? @{$variable}{qw[name sigil type]}
228 : $self->_deconstruct_variable_name($variable);
a5e51f0b 229
c46b802b 230 # FIXME:
231 # no doubt this is grossly inefficient and
232 # could be done much easier and faster in XS
233
8b49a472 234 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
235 { sigil => '$', type => 'SCALAR', name => $name },
236 { sigil => '@', type => 'ARRAY', name => $name },
237 { sigil => '%', type => 'HASH', name => $name },
238 { sigil => '&', type => 'CODE', name => $name },
239 );
240
c46b802b 241 my ($scalar, $array, $hash, $code);
a5e51f0b 242 if ($type eq 'SCALAR') {
8b49a472 243 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
244 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
245 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 246 }
247 elsif ($type eq 'ARRAY') {
8b49a472 248 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
249 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
250 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 251 }
252 elsif ($type eq 'HASH') {
8b49a472 253 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
254 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
255 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 256 }
257 elsif ($type eq 'CODE') {
8b49a472 258 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
259 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
260 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 261 }
262 else {
263 confess "This should never ever ever happen";
7f436b8c 264 }
c46b802b 265
266 $self->remove_package_glob($name);
267
8b49a472 268 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
269 $self->add_package_symbol($array_desc => $array) if defined $array;
270 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
271 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 272}
c0cbf4d9 273
9d6dce77 274sub list_all_package_symbols {
92330ee2 275 my ($self, $type_filter) = @_;
a38e4d1a 276
277 my $namespace = $self->namespace;
278 return keys %{$namespace} unless defined $type_filter;
279
91e0eb4a 280 # NOTE:
92330ee2 281 # or we can filter based on
282 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 283 if ( $type_filter eq 'CODE' ) {
284 return grep {
92af7fdf 285 (ref($namespace->{$_})
3609af79 286 ? (ref($namespace->{$_}) eq 'SCALAR')
287 : (ref(\$namespace->{$_}) eq 'GLOB'
288 && defined(*{$namespace->{$_}}{CODE})));
289 } keys %{$namespace};
290 } else {
291 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
292 }
6d5355c3 293}
294
b1ff395f 295## Methods
296
297sub wrap_method_body {
298 my ( $self, %args ) = @_;
299
300 ('CODE' eq ref $args{body})
301 || confess "Your code block must be a CODE reference";
302
303 $self->method_metaclass->wrap(
304 package_name => $self->name,
305 %args,
306 );
307}
308
309sub add_method {
310 my ($self, $method_name, $method) = @_;
311 (defined $method_name && $method_name)
312 || confess "You must define a method name";
313
314 my $body;
315 if (blessed($method)) {
316 $body = $method->body;
317 if ($method->package_name ne $self->name) {
318 $method = $method->clone(
319 package_name => $self->name,
4eb970b2 320 name => $method_name
b1ff395f 321 ) if $method->can('clone');
322 }
4eb970b2 323
324 $method->attach_to_class($self);
b1ff395f 325 }
326 else {
4eb970b2 327 # If a raw code reference is supplied, its method object is not created.
328 # The method object won't be created until required.
b1ff395f 329 $body = $method;
b1ff395f 330 }
331
5327fc78 332 $self->_method_map->{$method_name} = $method;
6eefe0df 333
334 my ( $current_package, $current_name ) = Class::MOP::get_code_info($body);
335
336 if ( !defined $current_name || $current_name eq '__ANON__' ) {
337 my $full_method_name = ($self->name . '::' . $method_name);
338 subname($full_method_name => $body);
339 }
340
b1ff395f 341 $self->add_package_symbol(
342 { sigil => '&', type => 'CODE', name => $method_name },
343 $body,
344 );
345}
346
4eb970b2 347sub _code_is_mine {
348 my ( $self, $code ) = @_;
349
350 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
351
352 return $code_package && $code_package eq $self->name
353 || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
354}
355
b1ff395f 356sub has_method {
357 my ($self, $method_name) = @_;
358 (defined $method_name && $method_name)
359 || confess "You must define a method name";
360
4eb970b2 361 return defined($self->get_method($method_name));
b1ff395f 362}
363
364sub get_method {
5327fc78 365 my ( $self, $method_name ) = @_;
366 ( defined $method_name && $method_name )
b1ff395f 367 || confess "You must define a method name";
368
5327fc78 369 my $method_map = $self->_method_map;
370 my $map_entry = $method_map->{$method_name};
371 my $code = $self->get_package_symbol(
372 {
373 name => $method_name,
374 sigil => '&',
375 type => 'CODE',
4eb970b2 376 }
5327fc78 377 );
378
379 return $map_entry if blessed $map_entry && $map_entry->body == $code;
380
381 # we should never have a blessed map entry but no $code in the package
382 die 'WTF' if blessed $map_entry && ! $code;
383
384 unless ($map_entry) {
385 return unless $code && $self->_code_is_mine($code);
4eb970b2 386 }
387
5327fc78 388 $code ||= $map_entry;
389
390 return $method_map->{$method_name} = $self->wrap_method_body(
391 body => $code,
392 name => $method_name,
393 associated_metaclass => $self,
394 );
b1ff395f 395}
396
397sub remove_method {
398 my ($self, $method_name) = @_;
399 (defined $method_name && $method_name)
400 || confess "You must define a method name";
401
402 my $removed_method = delete $self->get_method_map->{$method_name};
4eb970b2 403
b1ff395f 404 $self->remove_package_symbol(
405 { sigil => '&', type => 'CODE', name => $method_name }
406 );
407
5327fc78 408 $removed_method->detach_from_class if $removed_method && blessed $removed_method;
b1ff395f 409
410 $self->update_package_cache_flag; # still valid, since we just removed the method from the map
411
412 return $removed_method;
413}
414
415sub get_method_list {
416 my $self = shift;
4eb970b2 417 return grep { $self->has_method($_) } keys %{ $self->namespace };
b1ff395f 418}
419
2243a22b 4201;
421
422__END__
423
424=pod
425
426=head1 NAME
427
428Class::MOP::Package - Package Meta Object
429
2243a22b 430=head1 DESCRIPTION
431
116a9f45 432The Package Protocol provides an abstraction of a Perl 5 package. A
433package is basically namespace, and this module provides methods for
434looking at and changing that namespace's symbol table.
121991f6 435
2243a22b 436=head1 METHODS
437
438=over 4
439
116a9f45 440=item B<< Class::MOP::Package->initialize($package_name) >>
441
442This method creates a new C<Class::MOP::Package> instance which
443represents specified package. If an existing metaclass object exists
444for the package, that will be returned instead.
445
7975280a 446=item B<< Class::MOP::Package->reinitialize($package) >>
2243a22b 447
116a9f45 448This method forcibly removes any existing metaclass for the package
7975280a 449before calling C<initialize>. In contrast to C<initialize>, you may
450also pass an existing C<Class::MOP::Package> instance instead of just
451a package name as C<$package>.
127d39a7 452
116a9f45 453Do not call this unless you know what you are doing.
6d5355c3 454
116a9f45 455=item B<< $metapackage->name >>
127d39a7 456
116a9f45 457This is returns the package's name, as passed to the constructor.
a19fcb5b 458
116a9f45 459=item B<< $metapackage->namespace >>
a19fcb5b 460
116a9f45 461This returns a hash reference to the package's symbol table. The keys
462are symbol names and the values are typeglob references.
6d5355c3 463
116a9f45 464=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 465
116a9f45 466This method accepts a variable name and an optional initial value. The
467C<$variable_name> must contain a leading sigil.
a5e51f0b 468
116a9f45 469This method creates the variable in the package's symbol table, and
470sets it to the initial value if one was provided.
b9d9fc0b 471
116a9f45 472=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 473
116a9f45 474Given a variable name, this method returns the variable as a reference
475or undef if it does not exist. The C<$variable_name> must contain a
476leading sigil.
b9d9fc0b 477
116a9f45 478=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 479
116a9f45 480Returns true if there is a package variable defined for
481C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 482
116a9f45 483=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 484
116a9f45 485This will remove the package variable specified C<$variable_name>. The
486C<$variable_name> must contain a leading sigil.
6d5355c3 487
116a9f45 488=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 489
116a9f45 490Given the name of a glob, this will remove that glob from the
491package's symbol table. Glob names do not include a sigil. Removing
492the glob removes all variables and subroutines with the specified
493name.
b9d9fc0b 494
116a9f45 495=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 496
116a9f45 497This will list all the glob names associated with the current
498package. These names do not have leading sigils.
c46b802b 499
116a9f45 500You can provide an optional type filter, which should be one of
501'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 502
116a9f45 503=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 504
116a9f45 505This works much like C<list_all_package_symbols>, but it returns a
506hash reference. The keys are glob names and the values are references
507to the value for that name.
92330ee2 508
b1ff395f 509=back
510
511=head2 Method introspection and creation
512
513These methods allow you to introspect a class's methods, as well as
514add, remove, or change methods.
515
516Determining what is truly a method in a Perl 5 class requires some
517heuristics (aka guessing).
518
519Methods defined outside the package with a fully qualified name (C<sub
520Package::name { ... }>) will be included. Similarly, methods named
521with a fully qualified name using L<Sub::Name> are also included.
522
523However, we attempt to ignore imported functions.
524
525Ultimately, we are using heuristics to determine what truly is a
526method in a class, and these heuristics may get the wrong answer in
527some edge cases. However, for most "normal" cases the heuristics work
528correctly.
529
530=over 4
531
532=item B<< $metapackage->get_method($method_name) >>
533
534This will return a L<Class::MOP::Method> for the specified
535C<$method_name>. If the class does not have the specified method, it
536returns C<undef>
537
538=item B<< $metapackage->has_method($method_name) >>
539
540Returns a boolean indicating whether or not the class defines the
541named method. It does not include methods inherited from parent
542classes.
543
544=item B<< $metapackage->get_method_map >>
545
546Returns a hash reference representing the methods defined in this
547class. The keys are method names and the values are
548L<Class::MOP::Method> objects.
549
550=item B<< $metapackage->get_method_list >>
551
552This will return a list of method I<names> for all methods defined in
553this class.
554
555=item B<< $metapackage->add_method($method_name, $method) >>
556
557This method takes a method name and a subroutine reference, and adds
558the method to the class.
559
560The subroutine reference can be a L<Class::MOP::Method>, and you are
561strongly encouraged to pass a meta method object instead of a code
562reference. If you do so, that object gets stored as part of the
563class's method map directly. If not, the meta information will have to
564be recreated later, and may be incorrect.
565
566If you provide a method object, this method will clone that object if
567the object's package name does not match the class name. This lets us
568track the original source of any methods added from other classes
569(notably Moose roles).
570
571=item B<< $metapackage->remove_method($method_name) >>
572
573Remove the named method from the class. This method returns the
574L<Class::MOP::Method> object for the method.
575
576=item B<< $metapackage->method_metaclass >>
577
578Returns the class name of the method metaclass, see
579L<Class::MOP::Method> for more information on the method metaclass.
580
581=item B<< $metapackage->wrapped_method_metaclass >>
582
583Returns the class name of the wrapped method metaclass, see
584L<Class::MOP::Method::Wrapped> for more information on the wrapped
585method metaclass.
586
116a9f45 587=item B<< Class::MOP::Package->meta >>
ae234dc6 588
116a9f45 589This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 590
2243a22b 591=back
592
1a09d9cc 593=head1 AUTHORS
2243a22b 594
595Stevan Little E<lt>stevan@iinteractive.comE<gt>
596
597=head1 COPYRIGHT AND LICENSE
598
070bb6c9 599Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 600
601L<http://www.iinteractive.com>
602
603This library is free software; you can redistribute it and/or modify
604it under the same terms as Perl itself.
605
92af7fdf 606=cut