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