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