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