move some anonymous class functionality further up the food chain and split out how...
[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';
eef853a1 10use Devel::GlobalDestruction 'in_global_destruction';
2243a22b 11
4b18c1b3 12our $VERSION = '0.91';
d519662a 13$VERSION = eval $VERSION;
f0480c45 14our $AUTHORITY = 'cpan:STEVAN';
2243a22b 15
6e57504d 16use base 'Class::MOP::Object';
17
6d5355c3 18# creation ...
19
20sub initialize {
3be6bc1c 21 my ( $class, @args ) = @_;
22
23 unshift @args, "package" if @args % 2;
24
25 my %options = @args;
26 my $package_name = $options{package};
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
a19fcb5b 52 (defined $package_name && $package_name && !blessed($package_name))
53 || confess "You must pass a package name and it cannot be blessed";
3be6bc1c 54
a19fcb5b 55 Class::MOP::remove_metaclass_by_name($package_name);
3be6bc1c 56
3eda22f8 57 $class->initialize($package_name, %options); # call with first arg form for compat
682655a3 58}
59
60sub _new {
0bfc85b8 61 my $class = shift;
682655a3 62
ec9e38e5 63 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 64 if $class ne __PACKAGE__;
682655a3 65
ec9e38e5 66 my $params = @_ == 1 ? $_[0] : {@_};
eef853a1 67 $params->{anonymous} = 0 unless defined $params->{anonymous};
ec9e38e5 68
69 return bless {
70 package => $params->{package},
eef853a1 71 anonymous => $params->{anonymous},
0bfc85b8 72
ec9e38e5 73 # NOTE:
74 # because of issues with the Perl API
75 # to the typeglob in some versions, we
76 # need to just always grab a new
77 # reference to the hash in the accessor.
78 # Ideally we could just store a ref and
79 # it would Just Work, but oh well :\
80
81 namespace => \undef,
0bfc85b8 82
ec9e38e5 83 } => $class;
6d5355c3 84}
85
eef853a1 86# Anonymous Packages
87
88my $ANON_PACKAGE_SERIAL = 0;
89sub anonymous_package_postfix { ++$ANON_PACKAGE_SERIAL }
90sub anonymous_package_prefix { undef }
91
92# NOTE:
93# this will only get called for
94# anon-packages, all other calls
95# are assumed to occur during
96# global destruction and so don't
97# really need to be handled explicitly
98sub DESTROY {
99 my $self = shift;
100
101 return if in_global_destruction(); # it'll happen soon anyway and this just makes things more complicated
102
103 my $name = $self->name;
104 return unless $self->is_anonymous;
105 # Moose does a weird thing where it replaces the metaclass for
106 # class when fixing metaclass incompatibility. In that case,
107 # we don't want to clean out the namespace now. We can detect
108 # that because Moose will explicitly update the singleton
109 # cache in Class::MOP.
110 my $current_meta = Class::MOP::get_metaclass_by_name($name);
111 return if $current_meta ne $self;
112 my $prefix = $self->anonymous_package_prefix . '::';
113 my ($postfix) = ($name =~ /^$prefix(.+)/o);
114 no strict 'refs';
115 @{$name . '::ISA'} = ();
116 %{$name . '::'} = ();
117 delete ${$prefix}{$postfix . '::'};
118
119 Class::MOP::remove_metaclass_by_name($name);
120}
121
6d5355c3 122# Attributes
123
124# NOTE:
125# all these attribute readers will be bootstrapped
126# away in the Class::MOP bootstrap section
127
56dcfc1a 128sub namespace {
129 # NOTE:
130 # because of issues with the Perl API
131 # to the typeglob in some versions, we
132 # need to just always grab a new
133 # reference to the hash here. Ideally
134 # we could just store a ref and it would
135 # Just Work, but oh well :\
136 no strict 'refs';
8683db0e 137 \%{$_[0]->{'package'} . '::'}
56dcfc1a 138}
6d5355c3 139
b1ff395f 140sub method_metaclass { $_[0]->{'method_metaclass'} }
141sub wrapped_method_metaclass { $_[0]->{'wrapped_method_metaclass'} }
142
4eb970b2 143sub _method_map { $_[0]->{'methods'} }
eef853a1 144sub is_anonymous { $_[0]->{'anonymous'} }
4eb970b2 145
a5e51f0b 146# utility methods
6d5355c3 147
c0cbf4d9 148{
149 my %SIGIL_MAP = (
150 '$' => 'SCALAR',
151 '@' => 'ARRAY',
152 '%' => 'HASH',
153 '&' => 'CODE',
154 );
6d5355c3 155
a5e51f0b 156 sub _deconstruct_variable_name {
157 my ($self, $variable) = @_;
158
c0cbf4d9 159 (defined $variable)
160 || confess "You must pass a variable name";
a5e51f0b 161
f430cfa4 162 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 163
c0cbf4d9 164 (defined $sigil)
165 || confess "The variable name must include a sigil";
a5e51f0b 166
c0cbf4d9 167 (exists $SIGIL_MAP{$sigil})
a5e51f0b 168 || confess "I do not recognize that sigil '$sigil'";
169
f430cfa4 170 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 171 }
a5e51f0b 172}
6d5355c3 173
a5e51f0b 174# Class attributes
6d5355c3 175
c46b802b 176# ... these functions have to touch the symbol table itself,.. yuk
177
a5e51f0b 178sub add_package_symbol {
179 my ($self, $variable, $initial_value) = @_;
6d5355c3 180
8b49a472 181 my ($name, $sigil, $type) = ref $variable eq 'HASH'
182 ? @{$variable}{qw[name sigil type]}
26159d55 183 : $self->_deconstruct_variable_name($variable);
6d5355c3 184
8683db0e 185 my $pkg = $self->{'package'};
9a8bbfc9 186
a5e51f0b 187 no strict 'refs';
26159d55 188 no warnings 'redefine', 'misc', 'prototype';
189 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 190}
191
192sub remove_package_glob {
193 my ($self, $name) = @_;
194 no strict 'refs';
195 delete ${$self->name . '::'}{$name};
a5e51f0b 196}
6d5355c3 197
c46b802b 198# ... these functions deal with stuff on the namespace level
199
a5e51f0b 200sub has_package_symbol {
812d58f9 201 my ( $self, $variable ) = @_;
a5e51f0b 202
812d58f9 203 my ( $name, $sigil, $type )
204 = ref $variable eq 'HASH'
8b49a472 205 ? @{$variable}{qw[name sigil type]}
206 : $self->_deconstruct_variable_name($variable);
812d58f9 207
ae234dc6 208 my $namespace = $self->namespace;
812d58f9 209
210 return 0 unless exists $namespace->{$name};
211
55039f82 212 my $entry_ref = \$namespace->{$name};
812d58f9 213 if ( reftype($entry_ref) eq 'GLOB' ) {
214 if ( $type eq 'SCALAR' ) {
215 return defined( ${ *{$entry_ref}{SCALAR} } );
55039f82 216 }
217 else {
812d58f9 218 return defined( *{$entry_ref}{$type} );
55039f82 219 }
d852f4d2 220 }
221 else {
812d58f9 222
223 # a symbol table entry can be -1 (stub), string (stub with prototype),
224 # or reference (constant)
225 return $type eq 'CODE';
d852f4d2 226 }
a5e51f0b 227}
228
229sub get_package_symbol {
230 my ($self, $variable) = @_;
231
8b49a472 232 my ($name, $sigil, $type) = ref $variable eq 'HASH'
233 ? @{$variable}{qw[name sigil type]}
234 : $self->_deconstruct_variable_name($variable);
a5e51f0b 235
ae234dc6 236 my $namespace = $self->namespace;
237
55039f82 238 # FIXME
c20522bd 239 $self->add_package_symbol($variable)
ae234dc6 240 unless exists $namespace->{$name};
92af7fdf 241
55039f82 242 my $entry_ref = \$namespace->{$name};
243
812d58f9 244 if ( ref($entry_ref) eq 'GLOB' ) {
55039f82 245 return *{$entry_ref}{$type};
246 }
812d58f9 247 else {
248 if ( $type eq 'CODE' ) {
92af7fdf 249 no strict 'refs';
812d58f9 250 return \&{ $self->name . '::' . $name };
92af7fdf 251 }
252 else {
253 return undef;
254 }
255 }
a5e51f0b 256}
257
258sub remove_package_symbol {
259 my ($self, $variable) = @_;
260
8b49a472 261 my ($name, $sigil, $type) = ref $variable eq 'HASH'
262 ? @{$variable}{qw[name sigil type]}
263 : $self->_deconstruct_variable_name($variable);
a5e51f0b 264
c46b802b 265 # FIXME:
266 # no doubt this is grossly inefficient and
267 # could be done much easier and faster in XS
268
8b49a472 269 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
270 { sigil => '$', type => 'SCALAR', name => $name },
271 { sigil => '@', type => 'ARRAY', name => $name },
272 { sigil => '%', type => 'HASH', name => $name },
273 { sigil => '&', type => 'CODE', name => $name },
274 );
275
c46b802b 276 my ($scalar, $array, $hash, $code);
a5e51f0b 277 if ($type eq 'SCALAR') {
8b49a472 278 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
279 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
280 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 281 }
282 elsif ($type eq 'ARRAY') {
8b49a472 283 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
284 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
285 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 286 }
287 elsif ($type eq 'HASH') {
8b49a472 288 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
289 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
290 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 291 }
292 elsif ($type eq 'CODE') {
8b49a472 293 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
294 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
295 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 296 }
297 else {
298 confess "This should never ever ever happen";
7f436b8c 299 }
c46b802b 300
301 $self->remove_package_glob($name);
302
8b49a472 303 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
304 $self->add_package_symbol($array_desc => $array) if defined $array;
305 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
306 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 307}
c0cbf4d9 308
9d6dce77 309sub list_all_package_symbols {
92330ee2 310 my ($self, $type_filter) = @_;
a38e4d1a 311
312 my $namespace = $self->namespace;
313 return keys %{$namespace} unless defined $type_filter;
314
91e0eb4a 315 # NOTE:
92330ee2 316 # or we can filter based on
317 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 318 if ( $type_filter eq 'CODE' ) {
319 return grep {
92af7fdf 320 (ref($namespace->{$_})
3609af79 321 ? (ref($namespace->{$_}) eq 'SCALAR')
322 : (ref(\$namespace->{$_}) eq 'GLOB'
323 && defined(*{$namespace->{$_}}{CODE})));
324 } keys %{$namespace};
325 } else {
326 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
327 }
6d5355c3 328}
329
b1ff395f 330## Methods
331
332sub wrap_method_body {
333 my ( $self, %args ) = @_;
334
335 ('CODE' eq ref $args{body})
336 || confess "Your code block must be a CODE reference";
337
338 $self->method_metaclass->wrap(
339 package_name => $self->name,
340 %args,
341 );
342}
343
344sub add_method {
345 my ($self, $method_name, $method) = @_;
346 (defined $method_name && $method_name)
347 || confess "You must define a method name";
348
349 my $body;
350 if (blessed($method)) {
351 $body = $method->body;
352 if ($method->package_name ne $self->name) {
353 $method = $method->clone(
354 package_name => $self->name,
4eb970b2 355 name => $method_name
b1ff395f 356 ) if $method->can('clone');
357 }
4eb970b2 358
359 $method->attach_to_class($self);
360 $self->_method_map->{$method_name} = $method;
b1ff395f 361 }
362 else {
4eb970b2 363 # If a raw code reference is supplied, its method object is not created.
364 # The method object won't be created until required.
b1ff395f 365 $body = $method;
b1ff395f 366 }
367
b1ff395f 368
369 my ( $current_package, $current_name ) = Class::MOP::get_code_info($body);
370
371 if ( !defined $current_name || $current_name eq '__ANON__' ) {
372 my $full_method_name = ($self->name . '::' . $method_name);
373 subname($full_method_name => $body);
374 }
375
376 $self->add_package_symbol(
377 { sigil => '&', type => 'CODE', name => $method_name },
378 $body,
379 );
380}
381
4eb970b2 382sub _code_is_mine {
383 my ( $self, $code ) = @_;
384
385 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
386
387 return $code_package && $code_package eq $self->name
388 || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
389}
390
b1ff395f 391sub has_method {
392 my ($self, $method_name) = @_;
393 (defined $method_name && $method_name)
394 || confess "You must define a method name";
395
4eb970b2 396 return defined($self->get_method($method_name));
b1ff395f 397}
398
399sub get_method {
400 my ($self, $method_name) = @_;
401 (defined $method_name && $method_name)
402 || confess "You must define a method name";
403
4eb970b2 404 my $method_map = $self->_method_map;
405 my $method_object = $method_map->{$method_name};
406 my $code = $self->get_package_symbol({
407 name => $method_name,
408 sigil => '&',
409 type => 'CODE',
410 });
411
412 unless ( $method_object && $method_object->body == ( $code || 0 ) ) {
413 if ( $code && $self->_code_is_mine($code) ) {
414 $method_object = $method_map->{$method_name}
415 = $self->wrap_method_body(
416 body => $code,
417 name => $method_name,
418 associated_metaclass => $self,
419 );
420 }
421 else {
422 delete $method_map->{$method_name};
423 return undef;
424 }
425 }
426
427 return $method_object;
b1ff395f 428}
429
430sub remove_method {
431 my ($self, $method_name) = @_;
432 (defined $method_name && $method_name)
433 || confess "You must define a method name";
434
435 my $removed_method = delete $self->get_method_map->{$method_name};
4eb970b2 436
b1ff395f 437 $self->remove_package_symbol(
438 { sigil => '&', type => 'CODE', name => $method_name }
439 );
440
441 $removed_method->detach_from_class if $removed_method;
442
443 $self->update_package_cache_flag; # still valid, since we just removed the method from the map
444
445 return $removed_method;
446}
447
448sub get_method_list {
449 my $self = shift;
4eb970b2 450 return grep { $self->has_method($_) } keys %{ $self->namespace };
b1ff395f 451}
452
2243a22b 4531;
454
455__END__
456
457=pod
458
459=head1 NAME
460
461Class::MOP::Package - Package Meta Object
462
2243a22b 463=head1 DESCRIPTION
464
116a9f45 465The Package Protocol provides an abstraction of a Perl 5 package. A
466package is basically namespace, and this module provides methods for
467looking at and changing that namespace's symbol table.
121991f6 468
2243a22b 469=head1 METHODS
470
471=over 4
472
116a9f45 473=item B<< Class::MOP::Package->initialize($package_name) >>
474
475This method creates a new C<Class::MOP::Package> instance which
476represents specified package. If an existing metaclass object exists
477for the package, that will be returned instead.
478
479=item B<< Class::MOP::Package->reinitialize($package_name) >>
2243a22b 480
116a9f45 481This method forcibly removes any existing metaclass for the package
482before calling C<initialize>
127d39a7 483
116a9f45 484Do not call this unless you know what you are doing.
6d5355c3 485
116a9f45 486=item B<< $metapackage->name >>
127d39a7 487
116a9f45 488This is returns the package's name, as passed to the constructor.
a19fcb5b 489
116a9f45 490=item B<< $metapackage->namespace >>
a19fcb5b 491
116a9f45 492This returns a hash reference to the package's symbol table. The keys
493are symbol names and the values are typeglob references.
6d5355c3 494
116a9f45 495=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 496
116a9f45 497This method accepts a variable name and an optional initial value. The
498C<$variable_name> must contain a leading sigil.
a5e51f0b 499
116a9f45 500This method creates the variable in the package's symbol table, and
501sets it to the initial value if one was provided.
b9d9fc0b 502
116a9f45 503=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 504
116a9f45 505Given a variable name, this method returns the variable as a reference
506or undef if it does not exist. The C<$variable_name> must contain a
507leading sigil.
b9d9fc0b 508
116a9f45 509=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 510
116a9f45 511Returns true if there is a package variable defined for
512C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 513
116a9f45 514=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 515
116a9f45 516This will remove the package variable specified C<$variable_name>. The
517C<$variable_name> must contain a leading sigil.
6d5355c3 518
116a9f45 519=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 520
116a9f45 521Given the name of a glob, this will remove that glob from the
522package's symbol table. Glob names do not include a sigil. Removing
523the glob removes all variables and subroutines with the specified
524name.
b9d9fc0b 525
116a9f45 526=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 527
116a9f45 528This will list all the glob names associated with the current
529package. These names do not have leading sigils.
c46b802b 530
116a9f45 531You can provide an optional type filter, which should be one of
532'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 533
116a9f45 534=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 535
116a9f45 536This works much like C<list_all_package_symbols>, but it returns a
537hash reference. The keys are glob names and the values are references
538to the value for that name.
92330ee2 539
b1ff395f 540=back
541
542=head2 Method introspection and creation
543
544These methods allow you to introspect a class's methods, as well as
545add, remove, or change methods.
546
547Determining what is truly a method in a Perl 5 class requires some
548heuristics (aka guessing).
549
550Methods defined outside the package with a fully qualified name (C<sub
551Package::name { ... }>) will be included. Similarly, methods named
552with a fully qualified name using L<Sub::Name> are also included.
553
554However, we attempt to ignore imported functions.
555
556Ultimately, we are using heuristics to determine what truly is a
557method in a class, and these heuristics may get the wrong answer in
558some edge cases. However, for most "normal" cases the heuristics work
559correctly.
560
561=over 4
562
563=item B<< $metapackage->get_method($method_name) >>
564
565This will return a L<Class::MOP::Method> for the specified
566C<$method_name>. If the class does not have the specified method, it
567returns C<undef>
568
569=item B<< $metapackage->has_method($method_name) >>
570
571Returns a boolean indicating whether or not the class defines the
572named method. It does not include methods inherited from parent
573classes.
574
575=item B<< $metapackage->get_method_map >>
576
577Returns a hash reference representing the methods defined in this
578class. The keys are method names and the values are
579L<Class::MOP::Method> objects.
580
581=item B<< $metapackage->get_method_list >>
582
583This will return a list of method I<names> for all methods defined in
584this class.
585
586=item B<< $metapackage->add_method($method_name, $method) >>
587
588This method takes a method name and a subroutine reference, and adds
589the method to the class.
590
591The subroutine reference can be a L<Class::MOP::Method>, and you are
592strongly encouraged to pass a meta method object instead of a code
593reference. If you do so, that object gets stored as part of the
594class's method map directly. If not, the meta information will have to
595be recreated later, and may be incorrect.
596
597If you provide a method object, this method will clone that object if
598the object's package name does not match the class name. This lets us
599track the original source of any methods added from other classes
600(notably Moose roles).
601
602=item B<< $metapackage->remove_method($method_name) >>
603
604Remove the named method from the class. This method returns the
605L<Class::MOP::Method> object for the method.
606
607=item B<< $metapackage->method_metaclass >>
608
609Returns the class name of the method metaclass, see
610L<Class::MOP::Method> for more information on the method metaclass.
611
612=item B<< $metapackage->wrapped_method_metaclass >>
613
614Returns the class name of the wrapped method metaclass, see
615L<Class::MOP::Method::Wrapped> for more information on the wrapped
616method metaclass.
617
116a9f45 618=item B<< Class::MOP::Package->meta >>
ae234dc6 619
116a9f45 620This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 621
2243a22b 622=back
623
1a09d9cc 624=head1 AUTHORS
2243a22b 625
626Stevan Little E<lt>stevan@iinteractive.comE<gt>
627
628=head1 COPYRIGHT AND LICENSE
629
070bb6c9 630Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 631
632L<http://www.iinteractive.com>
633
634This library is free software; you can redistribute it and/or modify
635it under the same terms as Perl itself.
636
92af7fdf 637=cut