bump version to 0.65 and update changes for stable release
[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';
2243a22b 9
94278c1b 10our $VERSION = '0.65';
d519662a 11$VERSION = eval $VERSION;
f0480c45 12our $AUTHORITY = 'cpan:STEVAN';
2243a22b 13
6e57504d 14use base 'Class::MOP::Object';
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) ) {
30 return $meta;
31 } else {
3be6bc1c 32 my $meta = ( ref $class || $class )->_new({
a19fcb5b 33 'package' => $package_name,
34 });
35
36 Class::MOP::store_metaclass_by_name($package_name, $meta);
37
38 return $meta;
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
a19fcb5b 50 (defined $package_name && $package_name && !blessed($package_name))
51 || confess "You must pass a package name and it cannot be blessed";
3be6bc1c 52
a19fcb5b 53 Class::MOP::remove_metaclass_by_name($package_name);
3be6bc1c 54
3eda22f8 55 $class->initialize($package_name, %options); # call with first arg form for compat
682655a3 56}
57
58sub _new {
0bfc85b8 59 my $class = shift;
60 my $options = @_ == 1 ? $_[0] : {@_};
682655a3 61
0bfc85b8 62 # NOTE:
63 # because of issues with the Perl API
64 # to the typeglob in some versions, we
65 # need to just always grab a new
66 # reference to the hash in the accessor.
67 # Ideally we could just store a ref and
68 # it would Just Work, but oh well :\
69 $options->{namespace} ||= \undef;
70
71 bless $options, $class;
6d5355c3 72}
73
74# Attributes
75
76# NOTE:
77# all these attribute readers will be bootstrapped
78# away in the Class::MOP bootstrap section
79
8683db0e 80sub name { $_[0]->{'package'} }
56dcfc1a 81sub namespace {
82 # NOTE:
83 # because of issues with the Perl API
84 # to the typeglob in some versions, we
85 # need to just always grab a new
86 # reference to the hash here. Ideally
87 # we could just store a ref and it would
88 # Just Work, but oh well :\
89 no strict 'refs';
8683db0e 90 \%{$_[0]->{'package'} . '::'}
56dcfc1a 91}
6d5355c3 92
a5e51f0b 93# utility methods
6d5355c3 94
c0cbf4d9 95{
96 my %SIGIL_MAP = (
97 '$' => 'SCALAR',
98 '@' => 'ARRAY',
99 '%' => 'HASH',
100 '&' => 'CODE',
101 );
6d5355c3 102
a5e51f0b 103 sub _deconstruct_variable_name {
104 my ($self, $variable) = @_;
105
c0cbf4d9 106 (defined $variable)
107 || confess "You must pass a variable name";
a5e51f0b 108
f430cfa4 109 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 110
c0cbf4d9 111 (defined $sigil)
112 || confess "The variable name must include a sigil";
a5e51f0b 113
c0cbf4d9 114 (exists $SIGIL_MAP{$sigil})
a5e51f0b 115 || confess "I do not recognize that sigil '$sigil'";
116
f430cfa4 117 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 118 }
a5e51f0b 119}
6d5355c3 120
a5e51f0b 121# Class attributes
6d5355c3 122
c46b802b 123# ... these functions have to touch the symbol table itself,.. yuk
124
a5e51f0b 125sub add_package_symbol {
126 my ($self, $variable, $initial_value) = @_;
6d5355c3 127
8b49a472 128 my ($name, $sigil, $type) = ref $variable eq 'HASH'
129 ? @{$variable}{qw[name sigil type]}
130 : $self->_deconstruct_variable_name($variable);
6d5355c3 131
8683db0e 132 my $pkg = $self->{'package'};
9a8bbfc9 133
a5e51f0b 134 no strict 'refs';
56dcfc1a 135 no warnings 'redefine', 'misc';
9a8bbfc9 136 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 137}
138
139sub remove_package_glob {
140 my ($self, $name) = @_;
141 no strict 'refs';
142 delete ${$self->name . '::'}{$name};
a5e51f0b 143}
6d5355c3 144
c46b802b 145# ... these functions deal with stuff on the namespace level
146
a5e51f0b 147sub has_package_symbol {
148 my ($self, $variable) = @_;
149
8b49a472 150 my ($name, $sigil, $type) = ref $variable eq 'HASH'
151 ? @{$variable}{qw[name sigil type]}
152 : $self->_deconstruct_variable_name($variable);
56dcfc1a 153
ae234dc6 154 my $namespace = $self->namespace;
155
156 return 0 unless exists $namespace->{$name};
d852f4d2 157
158 # FIXME:
159 # For some really stupid reason
160 # a typeglob will have a default
161 # value of \undef in the SCALAR
162 # slot, so we need to work around
163 # this. Which of course means that
164 # if you put \undef in your scalar
165 # then this is broken.
92af7fdf 166
ae234dc6 167 if (ref($namespace->{$name}) eq 'SCALAR') {
b3fa93c7 168 return ($type eq 'CODE');
92af7fdf 169 }
170 elsif ($type eq 'SCALAR') {
ae234dc6 171 my $val = *{$namespace->{$name}}{$type};
b3fa93c7 172 return defined(${$val});
d852f4d2 173 }
174 else {
b3fa93c7 175 defined(*{$namespace->{$name}}{$type});
d852f4d2 176 }
a5e51f0b 177}
178
179sub get_package_symbol {
180 my ($self, $variable) = @_;
181
8b49a472 182 my ($name, $sigil, $type) = ref $variable eq 'HASH'
183 ? @{$variable}{qw[name sigil type]}
184 : $self->_deconstruct_variable_name($variable);
a5e51f0b 185
ae234dc6 186 my $namespace = $self->namespace;
187
c20522bd 188 $self->add_package_symbol($variable)
ae234dc6 189 unless exists $namespace->{$name};
92af7fdf 190
ae234dc6 191 if (ref($namespace->{$name}) eq 'SCALAR') {
92af7fdf 192 if ($type eq 'CODE') {
193 no strict 'refs';
194 return \&{$self->name.'::'.$name};
195 }
196 else {
197 return undef;
198 }
199 }
200 else {
ae234dc6 201 return *{$namespace->{$name}}{$type};
92af7fdf 202 }
a5e51f0b 203}
204
205sub remove_package_symbol {
206 my ($self, $variable) = @_;
207
8b49a472 208 my ($name, $sigil, $type) = ref $variable eq 'HASH'
209 ? @{$variable}{qw[name sigil type]}
210 : $self->_deconstruct_variable_name($variable);
a5e51f0b 211
c46b802b 212 # FIXME:
213 # no doubt this is grossly inefficient and
214 # could be done much easier and faster in XS
215
8b49a472 216 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
217 { sigil => '$', type => 'SCALAR', name => $name },
218 { sigil => '@', type => 'ARRAY', name => $name },
219 { sigil => '%', type => 'HASH', name => $name },
220 { sigil => '&', type => 'CODE', name => $name },
221 );
222
c46b802b 223 my ($scalar, $array, $hash, $code);
a5e51f0b 224 if ($type eq 'SCALAR') {
8b49a472 225 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
226 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
227 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 228 }
229 elsif ($type eq 'ARRAY') {
8b49a472 230 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
231 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
232 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 233 }
234 elsif ($type eq 'HASH') {
8b49a472 235 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
236 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
237 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 238 }
239 elsif ($type eq 'CODE') {
8b49a472 240 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
241 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
242 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 243 }
244 else {
245 confess "This should never ever ever happen";
7f436b8c 246 }
c46b802b 247
248 $self->remove_package_glob($name);
249
8b49a472 250 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
251 $self->add_package_symbol($array_desc => $array) if defined $array;
252 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
253 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 254}
c0cbf4d9 255
9d6dce77 256sub list_all_package_symbols {
92330ee2 257 my ($self, $type_filter) = @_;
a38e4d1a 258
259 my $namespace = $self->namespace;
260 return keys %{$namespace} unless defined $type_filter;
261
91e0eb4a 262 # NOTE:
92330ee2 263 # or we can filter based on
264 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 265 if ( $type_filter eq 'CODE' ) {
266 return grep {
92af7fdf 267 (ref($namespace->{$_})
3609af79 268 ? (ref($namespace->{$_}) eq 'SCALAR')
269 : (ref(\$namespace->{$_}) eq 'GLOB'
270 && defined(*{$namespace->{$_}}{CODE})));
271 } keys %{$namespace};
272 } else {
273 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
274 }
6d5355c3 275}
276
0531f510 277sub get_all_package_symbols {
278 my ($self, $type_filter) = @_;
87b69f58 279
280 die "Cannot call get_all_package_symbols as a class method"
281 unless ref $self;
282
0531f510 283 my $namespace = $self->namespace;
15273f3c 284
0531f510 285 return %$namespace unless defined $type_filter;
286
e5ebdca9 287 # for some reason this nasty impl is orders of magnitude faster than a clean version
0531f510 288 if ( $type_filter eq 'CODE' ) {
289 my $pkg;
290 no strict 'refs';
291 return map {
292 (ref($namespace->{$_})
293 ? ( $_ => \&{$pkg ||= $self->name . "::$_"} )
33f5d8ec 294 : ( (*{$namespace->{$_}}{CODE}) # the extra parents prevent breakage on 5.8.2
295 ? ( $_ => *{$namespace->{$_}}{CODE} )
296 : () ) )
0531f510 297 } keys %$namespace;
298 } else {
299 return map {
300 $_ => *{$namespace->{$_}}{$type_filter}
301 } grep {
302 !ref($namespace->{$_}) && *{$namespace->{$_}}{$type_filter}
303 } keys %$namespace;
304 }
ae234dc6 305}
306
2243a22b 3071;
308
309__END__
310
311=pod
312
313=head1 NAME
314
315Class::MOP::Package - Package Meta Object
316
2243a22b 317=head1 DESCRIPTION
318
127d39a7 319This is an abstraction of a Perl 5 package, it is a superclass of
320L<Class::MOP::Class> and provides all of the symbol table
321introspection methods.
322
2243a22b 323=head1 METHODS
324
325=over 4
326
327=item B<meta>
328
127d39a7 329Returns a metaclass for this package.
330
b9d9fc0b 331=item B<initialize ($package_name)>
6d5355c3 332
127d39a7 333This will initialize a Class::MOP::Package instance which represents
334the package of C<$package_name>.
335
a19fcb5b 336=item B<reinitialize ($package_name, %options)>
337
338This removes the old metaclass, and creates a new one in it's place.
339Do B<not> use this unless you really know what you are doing, it could
340very easily make a very large mess of your program.
341
6d5355c3 342=item B<name>
343
b9d9fc0b 344This is a read-only attribute which returns the package name for the
345given instance.
346
a5e51f0b 347=item B<namespace>
348
b9d9fc0b 349This returns a HASH reference to the symbol table. The keys of the
350HASH are the symbol names, and the values are typeglob references.
351
352=item B<add_package_symbol ($variable_name, ?$initial_value)>
353
354Given a C<$variable_name>, which must contain a leading sigil, this
355method will create that variable within the package which houses the
356class. It also takes an optional C<$initial_value>, which must be a
357reference of the same type as the sigil of the C<$variable_name>
358implies.
359
360=item B<get_package_symbol ($variable_name)>
6d5355c3 361
b9d9fc0b 362This will return a reference to the package variable in
363C<$variable_name>.
6d5355c3 364
b9d9fc0b 365=item B<has_package_symbol ($variable_name)>
6d5355c3 366
b9d9fc0b 367Returns true (C<1>) if there is a package variable defined for
368C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 369
b9d9fc0b 370=item B<remove_package_symbol ($variable_name)>
371
372This will attempt to remove the package variable at C<$variable_name>.
373
374=item B<remove_package_glob ($glob_name)>
375
376This will attempt to remove the entire typeglob associated with
377C<$glob_name> from the package.
c46b802b 378
92330ee2 379=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 380
b9d9fc0b 381This will list all the glob names associated with the current package.
382By inspecting the globs returned you can discern all the variables in
383the package.
384
92330ee2 385By passing a C<$type_filter>, you can limit the list to only those
386which match the filter (either SCALAR, ARRAY, HASH or CODE).
387
ae234dc6 388=item B<get_all_package_symbols (?$type_filter)>
389
390Works exactly like C<list_all_package_symbols> but returns a HASH of
391name => thing mapping instead of just an ARRAY of names.
392
2243a22b 393=back
394
1a09d9cc 395=head1 AUTHORS
2243a22b 396
397Stevan Little E<lt>stevan@iinteractive.comE<gt>
398
399=head1 COPYRIGHT AND LICENSE
400
69e3ab0a 401Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 402
403L<http://www.iinteractive.com>
404
405This library is free software; you can redistribute it and/or modify
406it under the same terms as Perl itself.
407
92af7fdf 408=cut