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