Merge the topic/mi-methods-attributes branch.
[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';
2243a22b 9
ec52b37a 10our $VERSION = '0.97';
d519662a 11$VERSION = eval $VERSION;
f0480c45 12our $AUTHORITY = 'cpan:STEVAN';
2243a22b 13
9b871d79 14use base 'Class::MOP::Object', 'Class::MOP::Mixin::HasMethods';
6e57504d 15
6d5355c3 16# creation ...
17
18sub initialize {
3be6bc1c 19 my ( $class, @args ) = @_;
20
21 unshift @args, "package" if @args % 2;
22
23 my %options = @args;
24 my $package_name = $options{package};
25
26
9d6dce77 27 # we hand-construct the class
28 # until we can bootstrap it
a19fcb5b 29 if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
973de492 30 return $meta;
a19fcb5b 31 } else {
973de492 32 my $meta = ( ref $class || $class )->_new({
33 'package' => $package_name,
11ac821d 34 %options,
973de492 35 });
973de492 36 Class::MOP::store_metaclass_by_name($package_name, $meta);
a19fcb5b 37
973de492 38 return $meta;
a19fcb5b 39 }
40}
41
42sub reinitialize {
3be6bc1c 43 my ( $class, @args ) = @_;
44
45 unshift @args, "package" if @args % 2;
46
47 my %options = @args;
3eda22f8 48 my $package_name = delete $options{package};
3be6bc1c 49
7975280a 50 (defined $package_name && $package_name
51 && (!blessed $package_name || $package_name->isa('Class::MOP::Package')))
52 || confess "You must pass a package name or an existing Class::MOP::Package instance";
53
54 $package_name = $package_name->name
55 if blessed $package_name;
3be6bc1c 56
a19fcb5b 57 Class::MOP::remove_metaclass_by_name($package_name);
3be6bc1c 58
3eda22f8 59 $class->initialize($package_name, %options); # call with first arg form for compat
682655a3 60}
61
62sub _new {
0bfc85b8 63 my $class = shift;
812d58f9 64
ec9e38e5 65 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 66 if $class ne __PACKAGE__;
682655a3 67
ec9e38e5 68 my $params = @_ == 1 ? $_[0] : {@_};
69
70 return bless {
71 package => $params->{package},
72
73 # NOTE:
74 # because of issues with the Perl API
75 # to the typeglob in some versions, we
76 # need to just always grab a new
77 # reference to the hash in the accessor.
78 # Ideally we could just store a ref and
79 # it would Just Work, but oh well :\
80
81 namespace => \undef,
0bfc85b8 82
ec9e38e5 83 } => $class;
6d5355c3 84}
85
86# Attributes
87
88# NOTE:
89# all these attribute readers will be bootstrapped
90# away in the Class::MOP bootstrap section
91
56dcfc1a 92sub namespace {
93 # NOTE:
94 # because of issues with the Perl API
95 # to the typeglob in some versions, we
96 # need to just always grab a new
97 # reference to the hash here. Ideally
98 # we could just store a ref and it would
99 # Just Work, but oh well :\
100 no strict 'refs';
8683db0e 101 \%{$_[0]->{'package'} . '::'}
56dcfc1a 102}
6d5355c3 103
a5e51f0b 104# utility methods
6d5355c3 105
c0cbf4d9 106{
107 my %SIGIL_MAP = (
108 '$' => 'SCALAR',
109 '@' => 'ARRAY',
110 '%' => 'HASH',
111 '&' => 'CODE',
112 );
6d5355c3 113
a5e51f0b 114 sub _deconstruct_variable_name {
115 my ($self, $variable) = @_;
116
c0cbf4d9 117 (defined $variable)
118 || confess "You must pass a variable name";
a5e51f0b 119
f430cfa4 120 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 121
c0cbf4d9 122 (defined $sigil)
123 || confess "The variable name must include a sigil";
a5e51f0b 124
c0cbf4d9 125 (exists $SIGIL_MAP{$sigil})
a5e51f0b 126 || confess "I do not recognize that sigil '$sigil'";
127
f430cfa4 128 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 129 }
a5e51f0b 130}
6d5355c3 131
a5e51f0b 132# Class attributes
6d5355c3 133
c46b802b 134# ... these functions have to touch the symbol table itself,.. yuk
135
86e1c8d8 136sub add_package_symbol {
137 my ($self, $variable, $initial_value) = @_;
138
139 my ($name, $sigil, $type) = ref $variable eq 'HASH'
140 ? @{$variable}{qw[name sigil type]}
141 : $self->_deconstruct_variable_name($variable);
142
143 my $pkg = $self->{'package'};
144
145 no strict 'refs';
146 no warnings 'redefine', 'misc', 'prototype';
147 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
148}
149
c46b802b 150sub remove_package_glob {
151 my ($self, $name) = @_;
86e1c8d8 152 no strict 'refs';
153 delete ${$self->name . '::'}{$name};
154}
155
156# ... these functions deal with stuff on the namespace level
157
158sub has_package_symbol {
159 my ( $self, $variable ) = @_;
160
161 my ( $name, $sigil, $type )
162 = ref $variable eq 'HASH'
163 ? @{$variable}{qw[name sigil type]}
164 : $self->_deconstruct_variable_name($variable);
165
166 my $namespace = $self->namespace;
167
168 return 0 unless exists $namespace->{$name};
169
170 my $entry_ref = \$namespace->{$name};
171 if ( reftype($entry_ref) eq 'GLOB' ) {
172 if ( $type eq 'SCALAR' ) {
173 return defined( ${ *{$entry_ref}{SCALAR} } );
174 }
175 else {
176 return defined( *{$entry_ref}{$type} );
177 }
178 }
179 else {
180
181 # a symbol table entry can be -1 (stub), string (stub with prototype),
182 # or reference (constant)
183 return $type eq 'CODE';
184 }
185}
186
187sub get_package_symbol {
188 my ($self, $variable) = @_;
189
190 my ($name, $sigil, $type) = ref $variable eq 'HASH'
191 ? @{$variable}{qw[name sigil type]}
192 : $self->_deconstruct_variable_name($variable);
193
194 my $namespace = $self->namespace;
195
196 # FIXME
197 $self->add_package_symbol($variable)
198 unless exists $namespace->{$name};
199
200 my $entry_ref = \$namespace->{$name};
201
202 if ( ref($entry_ref) eq 'GLOB' ) {
203 return *{$entry_ref}{$type};
204 }
205 else {
206 if ( $type eq 'CODE' ) {
207 no strict 'refs';
208 return \&{ $self->name . '::' . $name };
209 }
210 else {
211 return undef;
212 }
213 }
a5e51f0b 214}
6d5355c3 215
a5e51f0b 216sub remove_package_symbol {
217 my ($self, $variable) = @_;
218
8b49a472 219 my ($name, $sigil, $type) = ref $variable eq 'HASH'
220 ? @{$variable}{qw[name sigil type]}
221 : $self->_deconstruct_variable_name($variable);
a5e51f0b 222
c46b802b 223 # FIXME:
224 # no doubt this is grossly inefficient and
225 # could be done much easier and faster in XS
226
8b49a472 227 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
228 { sigil => '$', type => 'SCALAR', name => $name },
229 { sigil => '@', type => 'ARRAY', name => $name },
230 { sigil => '%', type => 'HASH', name => $name },
231 { sigil => '&', type => 'CODE', name => $name },
232 );
233
c46b802b 234 my ($scalar, $array, $hash, $code);
a5e51f0b 235 if ($type eq 'SCALAR') {
8b49a472 236 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
237 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
238 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 239 }
240 elsif ($type eq 'ARRAY') {
8b49a472 241 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
242 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
243 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 244 }
245 elsif ($type eq 'HASH') {
8b49a472 246 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
247 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
248 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 249 }
250 elsif ($type eq 'CODE') {
8b49a472 251 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
252 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
253 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 254 }
255 else {
256 confess "This should never ever ever happen";
7f436b8c 257 }
c46b802b 258
259 $self->remove_package_glob($name);
260
8b49a472 261 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
262 $self->add_package_symbol($array_desc => $array) if defined $array;
263 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
264 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 265}
c0cbf4d9 266
9d6dce77 267sub list_all_package_symbols {
92330ee2 268 my ($self, $type_filter) = @_;
a38e4d1a 269
270 my $namespace = $self->namespace;
271 return keys %{$namespace} unless defined $type_filter;
272
91e0eb4a 273 # NOTE:
92330ee2 274 # or we can filter based on
275 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 276 if ( $type_filter eq 'CODE' ) {
277 return grep {
92af7fdf 278 (ref($namespace->{$_})
3609af79 279 ? (ref($namespace->{$_}) eq 'SCALAR')
280 : (ref(\$namespace->{$_}) eq 'GLOB'
281 && defined(*{$namespace->{$_}}{CODE})));
282 } keys %{$namespace};
283 } else {
284 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
285 }
6d5355c3 286}
287
2243a22b 2881;
289
290__END__
291
292=pod
293
294=head1 NAME
295
296Class::MOP::Package - Package Meta Object
297
2243a22b 298=head1 DESCRIPTION
299
116a9f45 300The Package Protocol provides an abstraction of a Perl 5 package. A
301package is basically namespace, and this module provides methods for
302looking at and changing that namespace's symbol table.
121991f6 303
2243a22b 304=head1 METHODS
305
306=over 4
307
116a9f45 308=item B<< Class::MOP::Package->initialize($package_name) >>
309
310This method creates a new C<Class::MOP::Package> instance which
311represents specified package. If an existing metaclass object exists
312for the package, that will be returned instead.
313
7975280a 314=item B<< Class::MOP::Package->reinitialize($package) >>
2243a22b 315
116a9f45 316This method forcibly removes any existing metaclass for the package
7975280a 317before calling C<initialize>. In contrast to C<initialize>, you may
318also pass an existing C<Class::MOP::Package> instance instead of just
319a package name as C<$package>.
127d39a7 320
116a9f45 321Do not call this unless you know what you are doing.
6d5355c3 322
116a9f45 323=item B<< $metapackage->name >>
127d39a7 324
116a9f45 325This is returns the package's name, as passed to the constructor.
a19fcb5b 326
116a9f45 327=item B<< $metapackage->namespace >>
a19fcb5b 328
116a9f45 329This returns a hash reference to the package's symbol table. The keys
330are symbol names and the values are typeglob references.
6d5355c3 331
116a9f45 332=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 333
116a9f45 334This method accepts a variable name and an optional initial value. The
335C<$variable_name> must contain a leading sigil.
a5e51f0b 336
116a9f45 337This method creates the variable in the package's symbol table, and
338sets it to the initial value if one was provided.
b9d9fc0b 339
116a9f45 340=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 341
116a9f45 342Given a variable name, this method returns the variable as a reference
343or undef if it does not exist. The C<$variable_name> must contain a
344leading sigil.
b9d9fc0b 345
116a9f45 346=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 347
116a9f45 348Returns true if there is a package variable defined for
349C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 350
116a9f45 351=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 352
116a9f45 353This will remove the package variable specified C<$variable_name>. The
354C<$variable_name> must contain a leading sigil.
6d5355c3 355
116a9f45 356=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 357
116a9f45 358Given the name of a glob, this will remove that glob from the
359package's symbol table. Glob names do not include a sigil. Removing
360the glob removes all variables and subroutines with the specified
361name.
b9d9fc0b 362
116a9f45 363=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 364
116a9f45 365This will list all the glob names associated with the current
366package. These names do not have leading sigils.
c46b802b 367
116a9f45 368You can provide an optional type filter, which should be one of
369'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 370
116a9f45 371=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 372
116a9f45 373This works much like C<list_all_package_symbols>, but it returns a
374hash reference. The keys are glob names and the values are references
375to the value for that name.
92330ee2 376
b1ff395f 377=back
378
379=head2 Method introspection and creation
380
381These methods allow you to introspect a class's methods, as well as
382add, remove, or change methods.
383
384Determining what is truly a method in a Perl 5 class requires some
385heuristics (aka guessing).
386
387Methods defined outside the package with a fully qualified name (C<sub
388Package::name { ... }>) will be included. Similarly, methods named
389with a fully qualified name using L<Sub::Name> are also included.
390
391However, we attempt to ignore imported functions.
392
393Ultimately, we are using heuristics to determine what truly is a
394method in a class, and these heuristics may get the wrong answer in
395some edge cases. However, for most "normal" cases the heuristics work
396correctly.
397
398=over 4
399
400=item B<< $metapackage->get_method($method_name) >>
401
402This will return a L<Class::MOP::Method> for the specified
403C<$method_name>. If the class does not have the specified method, it
404returns C<undef>
405
406=item B<< $metapackage->has_method($method_name) >>
407
408Returns a boolean indicating whether or not the class defines the
409named method. It does not include methods inherited from parent
410classes.
411
b1ff395f 412=item B<< $metapackage->get_method_list >>
413
414This will return a list of method I<names> for all methods defined in
415this class.
416
417=item B<< $metapackage->add_method($method_name, $method) >>
418
419This method takes a method name and a subroutine reference, and adds
420the method to the class.
421
422The subroutine reference can be a L<Class::MOP::Method>, and you are
423strongly encouraged to pass a meta method object instead of a code
424reference. If you do so, that object gets stored as part of the
425class's method map directly. If not, the meta information will have to
426be recreated later, and may be incorrect.
427
428If you provide a method object, this method will clone that object if
429the object's package name does not match the class name. This lets us
430track the original source of any methods added from other classes
431(notably Moose roles).
432
433=item B<< $metapackage->remove_method($method_name) >>
434
435Remove the named method from the class. This method returns the
436L<Class::MOP::Method> object for the method.
437
438=item B<< $metapackage->method_metaclass >>
439
440Returns the class name of the method metaclass, see
441L<Class::MOP::Method> for more information on the method metaclass.
442
443=item B<< $metapackage->wrapped_method_metaclass >>
444
445Returns the class name of the wrapped method metaclass, see
446L<Class::MOP::Method::Wrapped> for more information on the wrapped
447method metaclass.
448
116a9f45 449=item B<< Class::MOP::Package->meta >>
ae234dc6 450
116a9f45 451This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 452
2243a22b 453=back
454
1a09d9cc 455=head1 AUTHORS
2243a22b 456
457Stevan Little E<lt>stevan@iinteractive.comE<gt>
458
459=head1 COPYRIGHT AND LICENSE
460
070bb6c9 461Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 462
463L<http://www.iinteractive.com>
464
465This library is free software; you can redistribute it and/or modify
466it under the same terms as Perl itself.
467
92af7fdf 468=cut