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