Revert "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';
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);
325 $self->_method_map->{$method_name} = $method;
b1ff395f 326 }
327 else {
4eb970b2 328 # If a raw code reference is supplied, its method object is not created.
329 # The method object won't be created until required.
b1ff395f 330 $body = $method;
b1ff395f 331 }
332
b1ff395f 333 $self->add_package_symbol(
334 { sigil => '&', type => 'CODE', name => $method_name },
335 $body,
336 );
337}
338
4eb970b2 339sub _code_is_mine {
340 my ( $self, $code ) = @_;
341
342 my ( $code_package, $code_name ) = Class::MOP::get_code_info($code);
343
344 return $code_package && $code_package eq $self->name
345 || ( $code_package eq 'constant' && $code_name eq '__ANON__' );
346}
347
b1ff395f 348sub has_method {
349 my ($self, $method_name) = @_;
350 (defined $method_name && $method_name)
351 || confess "You must define a method name";
352
4eb970b2 353 return defined($self->get_method($method_name));
b1ff395f 354}
355
356sub get_method {
357 my ($self, $method_name) = @_;
358 (defined $method_name && $method_name)
359 || confess "You must define a method name";
360
4eb970b2 361 my $method_map = $self->_method_map;
362 my $method_object = $method_map->{$method_name};
363 my $code = $self->get_package_symbol({
364 name => $method_name,
365 sigil => '&',
366 type => 'CODE',
367 });
368
369 unless ( $method_object && $method_object->body == ( $code || 0 ) ) {
370 if ( $code && $self->_code_is_mine($code) ) {
371 $method_object = $method_map->{$method_name}
372 = $self->wrap_method_body(
373 body => $code,
374 name => $method_name,
375 associated_metaclass => $self,
376 );
377 }
378 else {
379 delete $method_map->{$method_name};
380 return undef;
381 }
382 }
383
384 return $method_object;
b1ff395f 385}
386
387sub remove_method {
388 my ($self, $method_name) = @_;
389 (defined $method_name && $method_name)
390 || confess "You must define a method name";
391
392 my $removed_method = delete $self->get_method_map->{$method_name};
4eb970b2 393
b1ff395f 394 $self->remove_package_symbol(
395 { sigil => '&', type => 'CODE', name => $method_name }
396 );
397
398 $removed_method->detach_from_class if $removed_method;
399
400 $self->update_package_cache_flag; # still valid, since we just removed the method from the map
401
402 return $removed_method;
403}
404
405sub get_method_list {
406 my $self = shift;
4eb970b2 407 return grep { $self->has_method($_) } keys %{ $self->namespace };
b1ff395f 408}
409
2243a22b 4101;
411
412__END__
413
414=pod
415
416=head1 NAME
417
418Class::MOP::Package - Package Meta Object
419
2243a22b 420=head1 DESCRIPTION
421
116a9f45 422The Package Protocol provides an abstraction of a Perl 5 package. A
423package is basically namespace, and this module provides methods for
424looking at and changing that namespace's symbol table.
121991f6 425
2243a22b 426=head1 METHODS
427
428=over 4
429
116a9f45 430=item B<< Class::MOP::Package->initialize($package_name) >>
431
432This method creates a new C<Class::MOP::Package> instance which
433represents specified package. If an existing metaclass object exists
434for the package, that will be returned instead.
435
7975280a 436=item B<< Class::MOP::Package->reinitialize($package) >>
2243a22b 437
116a9f45 438This method forcibly removes any existing metaclass for the package
7975280a 439before calling C<initialize>. In contrast to C<initialize>, you may
440also pass an existing C<Class::MOP::Package> instance instead of just
441a package name as C<$package>.
127d39a7 442
116a9f45 443Do not call this unless you know what you are doing.
6d5355c3 444
116a9f45 445=item B<< $metapackage->name >>
127d39a7 446
116a9f45 447This is returns the package's name, as passed to the constructor.
a19fcb5b 448
116a9f45 449=item B<< $metapackage->namespace >>
a19fcb5b 450
116a9f45 451This returns a hash reference to the package's symbol table. The keys
452are symbol names and the values are typeglob references.
6d5355c3 453
116a9f45 454=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 455
116a9f45 456This method accepts a variable name and an optional initial value. The
457C<$variable_name> must contain a leading sigil.
a5e51f0b 458
116a9f45 459This method creates the variable in the package's symbol table, and
460sets it to the initial value if one was provided.
b9d9fc0b 461
116a9f45 462=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 463
116a9f45 464Given a variable name, this method returns the variable as a reference
465or undef if it does not exist. The C<$variable_name> must contain a
466leading sigil.
b9d9fc0b 467
116a9f45 468=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 469
116a9f45 470Returns true if there is a package variable defined for
471C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 472
116a9f45 473=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 474
116a9f45 475This will remove the package variable specified C<$variable_name>. The
476C<$variable_name> must contain a leading sigil.
6d5355c3 477
116a9f45 478=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 479
116a9f45 480Given the name of a glob, this will remove that glob from the
481package's symbol table. Glob names do not include a sigil. Removing
482the glob removes all variables and subroutines with the specified
483name.
b9d9fc0b 484
116a9f45 485=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 486
116a9f45 487This will list all the glob names associated with the current
488package. These names do not have leading sigils.
c46b802b 489
116a9f45 490You can provide an optional type filter, which should be one of
491'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 492
116a9f45 493=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 494
116a9f45 495This works much like C<list_all_package_symbols>, but it returns a
496hash reference. The keys are glob names and the values are references
497to the value for that name.
92330ee2 498
b1ff395f 499=back
500
501=head2 Method introspection and creation
502
503These methods allow you to introspect a class's methods, as well as
504add, remove, or change methods.
505
506Determining what is truly a method in a Perl 5 class requires some
507heuristics (aka guessing).
508
509Methods defined outside the package with a fully qualified name (C<sub
510Package::name { ... }>) will be included. Similarly, methods named
511with a fully qualified name using L<Sub::Name> are also included.
512
513However, we attempt to ignore imported functions.
514
515Ultimately, we are using heuristics to determine what truly is a
516method in a class, and these heuristics may get the wrong answer in
517some edge cases. However, for most "normal" cases the heuristics work
518correctly.
519
520=over 4
521
522=item B<< $metapackage->get_method($method_name) >>
523
524This will return a L<Class::MOP::Method> for the specified
525C<$method_name>. If the class does not have the specified method, it
526returns C<undef>
527
528=item B<< $metapackage->has_method($method_name) >>
529
530Returns a boolean indicating whether or not the class defines the
531named method. It does not include methods inherited from parent
532classes.
533
534=item B<< $metapackage->get_method_map >>
535
536Returns a hash reference representing the methods defined in this
537class. The keys are method names and the values are
538L<Class::MOP::Method> objects.
539
540=item B<< $metapackage->get_method_list >>
541
542This will return a list of method I<names> for all methods defined in
543this class.
544
545=item B<< $metapackage->add_method($method_name, $method) >>
546
547This method takes a method name and a subroutine reference, and adds
548the method to the class.
549
550The subroutine reference can be a L<Class::MOP::Method>, and you are
551strongly encouraged to pass a meta method object instead of a code
552reference. If you do so, that object gets stored as part of the
553class's method map directly. If not, the meta information will have to
554be recreated later, and may be incorrect.
555
556If you provide a method object, this method will clone that object if
557the object's package name does not match the class name. This lets us
558track the original source of any methods added from other classes
559(notably Moose roles).
560
561=item B<< $metapackage->remove_method($method_name) >>
562
563Remove the named method from the class. This method returns the
564L<Class::MOP::Method> object for the method.
565
566=item B<< $metapackage->method_metaclass >>
567
568Returns the class name of the method metaclass, see
569L<Class::MOP::Method> for more information on the method metaclass.
570
571=item B<< $metapackage->wrapped_method_metaclass >>
572
573Returns the class name of the wrapped method metaclass, see
574L<Class::MOP::Method::Wrapped> for more information on the wrapped
575method metaclass.
576
116a9f45 577=item B<< Class::MOP::Package->meta >>
ae234dc6 578
116a9f45 579This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 580
2243a22b 581=back
582
1a09d9cc 583=head1 AUTHORS
2243a22b 584
585Stevan Little E<lt>stevan@iinteractive.comE<gt>
586
587=head1 COPYRIGHT AND LICENSE
588
070bb6c9 589Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 590
591L<http://www.iinteractive.com>
592
593This library is free software; you can redistribute it and/or modify
594it under the same terms as Perl itself.
595
92af7fdf 596=cut