initialize cleanup
[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
ae234dc6 10our $VERSION = '0.09';
f0480c45 11our $AUTHORITY = 'cpan:STEVAN';
2243a22b 12
6e57504d 13use base 'Class::MOP::Object';
14
6d5355c3 15# creation ...
16
17sub initialize {
9d6dce77 18 my $class = shift;
19 my $package_name = shift;
20 # we hand-construct the class
21 # until we can bootstrap it
a5e51f0b 22 no strict 'refs';
23 return bless {
c23184fc 24 '$!package' => $package_name,
56dcfc1a 25 # NOTE:
26 # because of issues with the Perl API
27 # to the typeglob in some versions, we
28 # need to just always grab a new
29 # reference to the hash in the accessor.
30 # Ideally we could just store a ref and
31 # it would Just Work, but oh well :\
c23184fc 32 '%!namespace' => \undef,
a5e51f0b 33 } => $class;
6d5355c3 34}
35
36# Attributes
37
38# NOTE:
39# all these attribute readers will be bootstrapped
40# away in the Class::MOP bootstrap section
41
c23184fc 42sub name { $_[0]->{'$!package'} }
56dcfc1a 43sub namespace {
44 # NOTE:
45 # because of issues with the Perl API
46 # to the typeglob in some versions, we
47 # need to just always grab a new
48 # reference to the hash here. Ideally
49 # we could just store a ref and it would
50 # Just Work, but oh well :\
51 no strict 'refs';
52 \%{$_[0]->name . '::'}
53}
6d5355c3 54
a5e51f0b 55# utility methods
6d5355c3 56
c0cbf4d9 57{
58 my %SIGIL_MAP = (
59 '$' => 'SCALAR',
60 '@' => 'ARRAY',
61 '%' => 'HASH',
62 '&' => 'CODE',
63 );
6d5355c3 64
a5e51f0b 65 sub _deconstruct_variable_name {
66 my ($self, $variable) = @_;
67
c0cbf4d9 68 (defined $variable)
69 || confess "You must pass a variable name";
a5e51f0b 70
f430cfa4 71 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 72
c0cbf4d9 73 (defined $sigil)
74 || confess "The variable name must include a sigil";
a5e51f0b 75
c0cbf4d9 76 (exists $SIGIL_MAP{$sigil})
a5e51f0b 77 || confess "I do not recognize that sigil '$sigil'";
78
f430cfa4 79 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 80 }
a5e51f0b 81}
6d5355c3 82
a5e51f0b 83# Class attributes
6d5355c3 84
c46b802b 85# ... these functions have to touch the symbol table itself,.. yuk
86
a5e51f0b 87sub add_package_symbol {
88 my ($self, $variable, $initial_value) = @_;
6d5355c3 89
a5e51f0b 90 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
6d5355c3 91
a5e51f0b 92 no strict 'refs';
56dcfc1a 93 no warnings 'redefine', 'misc';
94 *{$self->name . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 95}
96
97sub remove_package_glob {
98 my ($self, $name) = @_;
99 no strict 'refs';
100 delete ${$self->name . '::'}{$name};
a5e51f0b 101}
6d5355c3 102
c46b802b 103# ... these functions deal with stuff on the namespace level
104
a5e51f0b 105sub has_package_symbol {
106 my ($self, $variable) = @_;
107
108 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
56dcfc1a 109
ae234dc6 110 my $namespace = $self->namespace;
111
112 return 0 unless exists $namespace->{$name};
d852f4d2 113
114 # FIXME:
115 # For some really stupid reason
116 # a typeglob will have a default
117 # value of \undef in the SCALAR
118 # slot, so we need to work around
119 # this. Which of course means that
120 # if you put \undef in your scalar
121 # then this is broken.
92af7fdf 122
ae234dc6 123 if (ref($namespace->{$name}) eq 'SCALAR') {
92af7fdf 124 return ($type eq 'CODE' ? 1 : 0);
125 }
126 elsif ($type eq 'SCALAR') {
ae234dc6 127 my $val = *{$namespace->{$name}}{$type};
92af7fdf 128 return defined(${$val}) ? 1 : 0;
d852f4d2 129 }
130 else {
ae234dc6 131 defined(*{$namespace->{$name}}{$type}) ? 1 : 0;
d852f4d2 132 }
a5e51f0b 133}
134
135sub get_package_symbol {
136 my ($self, $variable) = @_;
137
138 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
139
ae234dc6 140 my $namespace = $self->namespace;
141
c20522bd 142 $self->add_package_symbol($variable)
ae234dc6 143 unless exists $namespace->{$name};
92af7fdf 144
ae234dc6 145 if (ref($namespace->{$name}) eq 'SCALAR') {
92af7fdf 146 if ($type eq 'CODE') {
147 no strict 'refs';
148 return \&{$self->name.'::'.$name};
149 }
150 else {
151 return undef;
152 }
153 }
154 else {
ae234dc6 155 return *{$namespace->{$name}}{$type};
92af7fdf 156 }
a5e51f0b 157}
158
159sub remove_package_symbol {
160 my ($self, $variable) = @_;
161
162 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
163
c46b802b 164 # FIXME:
165 # no doubt this is grossly inefficient and
166 # could be done much easier and faster in XS
167
168 my ($scalar, $array, $hash, $code);
a5e51f0b 169 if ($type eq 'SCALAR') {
c46b802b 170 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
171 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
172 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 173 }
174 elsif ($type eq 'ARRAY') {
c46b802b 175 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
176 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
177 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 178 }
179 elsif ($type eq 'HASH') {
c46b802b 180 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
181 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
182 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 183 }
184 elsif ($type eq 'CODE') {
c46b802b 185 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
186 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
187 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
a5e51f0b 188 }
189 else {
190 confess "This should never ever ever happen";
7f436b8c 191 }
c46b802b 192
193 $self->remove_package_glob($name);
194
195 $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar;
196 $self->add_package_symbol(('@' . $name) => $array) if defined $array;
197 $self->add_package_symbol(('%' . $name) => $hash) if defined $hash;
198 $self->add_package_symbol(('&' . $name) => $code) if defined $code;
9d6dce77 199}
c0cbf4d9 200
9d6dce77 201sub list_all_package_symbols {
92330ee2 202 my ($self, $type_filter) = @_;
203 return keys %{$self->namespace} unless defined $type_filter;
91e0eb4a 204 # NOTE:
92330ee2 205 # or we can filter based on
206 # type (SCALAR|ARRAY|HASH|CODE)
207 my $namespace = $self->namespace;
91e0eb4a 208 return grep {
92af7fdf 209 (ref($namespace->{$_})
210 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
211 : (ref(\$namespace->{$_}) eq 'GLOB'
212 && defined(*{$namespace->{$_}}{$type_filter})));
91e0eb4a 213 } keys %{$namespace};
6d5355c3 214}
215
ae234dc6 216sub get_all_package_symbols {
217 my ($self, $type_filter) = @_;
218 return %{$self->namespace} unless defined $type_filter;
219 # NOTE:
220 # or we can filter based on
221 # type (SCALAR|ARRAY|HASH|CODE)
222 my $namespace = $self->namespace;
223 no strict 'refs';
224 return map {
225 $_ => (ref($namespace->{$_}) eq 'SCALAR'
226 ? ($type_filter eq 'CODE' ? \&{$self->name . '::' . $_} : undef)
227 : *{$namespace->{$_}}{$type_filter})
228 } grep {
229 (ref($namespace->{$_})
230 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
231 : (ref(\$namespace->{$_}) eq 'GLOB'
232 && defined(*{$namespace->{$_}}{$type_filter})));
233 } keys %{$namespace};
234}
235
2243a22b 2361;
237
238__END__
239
240=pod
241
242=head1 NAME
243
244Class::MOP::Package - Package Meta Object
245
2243a22b 246=head1 DESCRIPTION
247
127d39a7 248This is an abstraction of a Perl 5 package, it is a superclass of
249L<Class::MOP::Class> and provides all of the symbol table
250introspection methods.
251
2243a22b 252=head1 METHODS
253
254=over 4
255
256=item B<meta>
257
127d39a7 258Returns a metaclass for this package.
259
b9d9fc0b 260=item B<initialize ($package_name)>
6d5355c3 261
127d39a7 262This will initialize a Class::MOP::Package instance which represents
263the package of C<$package_name>.
264
6d5355c3 265=item B<name>
266
b9d9fc0b 267This is a read-only attribute which returns the package name for the
268given instance.
269
a5e51f0b 270=item B<namespace>
271
b9d9fc0b 272This returns a HASH reference to the symbol table. The keys of the
273HASH are the symbol names, and the values are typeglob references.
274
275=item B<add_package_symbol ($variable_name, ?$initial_value)>
276
277Given a C<$variable_name>, which must contain a leading sigil, this
278method will create that variable within the package which houses the
279class. It also takes an optional C<$initial_value>, which must be a
280reference of the same type as the sigil of the C<$variable_name>
281implies.
282
283=item B<get_package_symbol ($variable_name)>
6d5355c3 284
b9d9fc0b 285This will return a reference to the package variable in
286C<$variable_name>.
6d5355c3 287
b9d9fc0b 288=item B<has_package_symbol ($variable_name)>
6d5355c3 289
b9d9fc0b 290Returns true (C<1>) if there is a package variable defined for
291C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 292
b9d9fc0b 293=item B<remove_package_symbol ($variable_name)>
294
295This will attempt to remove the package variable at C<$variable_name>.
296
297=item B<remove_package_glob ($glob_name)>
298
299This will attempt to remove the entire typeglob associated with
300C<$glob_name> from the package.
c46b802b 301
92330ee2 302=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 303
b9d9fc0b 304This will list all the glob names associated with the current package.
305By inspecting the globs returned you can discern all the variables in
306the package.
307
92330ee2 308By passing a C<$type_filter>, you can limit the list to only those
309which match the filter (either SCALAR, ARRAY, HASH or CODE).
310
ae234dc6 311=item B<get_all_package_symbols (?$type_filter)>
312
313Works exactly like C<list_all_package_symbols> but returns a HASH of
314name => thing mapping instead of just an ARRAY of names.
315
2243a22b 316=back
317
1a09d9cc 318=head1 AUTHORS
2243a22b 319
320Stevan Little E<lt>stevan@iinteractive.comE<gt>
321
322=head1 COPYRIGHT AND LICENSE
323
69e3ab0a 324Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 325
326L<http://www.iinteractive.com>
327
328This library is free software; you can redistribute it and/or modify
329it under the same terms as Perl itself.
330
92af7fdf 331=cut