Bump the version # and updates Changes for 0.64_03
[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
df7077cd 10our $VERSION = '0.64_03';
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) = @_;
279 my $namespace = $self->namespace;
15273f3c 280
0531f510 281 return %$namespace unless defined $type_filter;
282
283 # for some reason this nasty impl is orders of magnitude aster than a clean version
284 if ( $type_filter eq 'CODE' ) {
285 my $pkg;
286 no strict 'refs';
287 return map {
288 (ref($namespace->{$_})
289 ? ( $_ => \&{$pkg ||= $self->name . "::$_"} )
33f5d8ec 290 : ( (*{$namespace->{$_}}{CODE}) # the extra parents prevent breakage on 5.8.2
291 ? ( $_ => *{$namespace->{$_}}{CODE} )
292 : () ) )
0531f510 293 } keys %$namespace;
294 } else {
295 return map {
296 $_ => *{$namespace->{$_}}{$type_filter}
297 } grep {
298 !ref($namespace->{$_}) && *{$namespace->{$_}}{$type_filter}
299 } keys %$namespace;
300 }
ae234dc6 301}
302
2243a22b 3031;
304
305__END__
306
307=pod
308
309=head1 NAME
310
311Class::MOP::Package - Package Meta Object
312
2243a22b 313=head1 DESCRIPTION
314
127d39a7 315This is an abstraction of a Perl 5 package, it is a superclass of
316L<Class::MOP::Class> and provides all of the symbol table
317introspection methods.
318
2243a22b 319=head1 METHODS
320
321=over 4
322
323=item B<meta>
324
127d39a7 325Returns a metaclass for this package.
326
b9d9fc0b 327=item B<initialize ($package_name)>
6d5355c3 328
127d39a7 329This will initialize a Class::MOP::Package instance which represents
330the package of C<$package_name>.
331
a19fcb5b 332=item B<reinitialize ($package_name, %options)>
333
334This removes the old metaclass, and creates a new one in it's place.
335Do B<not> use this unless you really know what you are doing, it could
336very easily make a very large mess of your program.
337
6d5355c3 338=item B<name>
339
b9d9fc0b 340This is a read-only attribute which returns the package name for the
341given instance.
342
a5e51f0b 343=item B<namespace>
344
b9d9fc0b 345This returns a HASH reference to the symbol table. The keys of the
346HASH are the symbol names, and the values are typeglob references.
347
348=item B<add_package_symbol ($variable_name, ?$initial_value)>
349
350Given a C<$variable_name>, which must contain a leading sigil, this
351method will create that variable within the package which houses the
352class. It also takes an optional C<$initial_value>, which must be a
353reference of the same type as the sigil of the C<$variable_name>
354implies.
355
356=item B<get_package_symbol ($variable_name)>
6d5355c3 357
b9d9fc0b 358This will return a reference to the package variable in
359C<$variable_name>.
6d5355c3 360
b9d9fc0b 361=item B<has_package_symbol ($variable_name)>
6d5355c3 362
b9d9fc0b 363Returns true (C<1>) if there is a package variable defined for
364C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 365
b9d9fc0b 366=item B<remove_package_symbol ($variable_name)>
367
368This will attempt to remove the package variable at C<$variable_name>.
369
370=item B<remove_package_glob ($glob_name)>
371
372This will attempt to remove the entire typeglob associated with
373C<$glob_name> from the package.
c46b802b 374
92330ee2 375=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 376
b9d9fc0b 377This will list all the glob names associated with the current package.
378By inspecting the globs returned you can discern all the variables in
379the package.
380
92330ee2 381By passing a C<$type_filter>, you can limit the list to only those
382which match the filter (either SCALAR, ARRAY, HASH or CODE).
383
ae234dc6 384=item B<get_all_package_symbols (?$type_filter)>
385
386Works exactly like C<list_all_package_symbols> but returns a HASH of
387name => thing mapping instead of just an ARRAY of names.
388
2243a22b 389=back
390
1a09d9cc 391=head1 AUTHORS
2243a22b 392
393Stevan Little E<lt>stevan@iinteractive.comE<gt>
394
395=head1 COPYRIGHT AND LICENSE
396
69e3ab0a 397Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 398
399L<http://www.iinteractive.com>
400
401This library is free software; you can redistribute it and/or modify
402it under the same terms as Perl itself.
403
92af7fdf 404=cut