fixing the destructor, so it wont be created unless needed
[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
cc05f61c 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';
cc05f61c 52 \%{$_[0]->{'$!package'} . '::'}
56dcfc1a 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
9a8bbfc9 92 my $pkg = $self->{'$!package'};
93
a5e51f0b 94 no strict 'refs';
56dcfc1a 95 no warnings 'redefine', 'misc';
9a8bbfc9 96 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 97}
98
99sub remove_package_glob {
100 my ($self, $name) = @_;
101 no strict 'refs';
102 delete ${$self->name . '::'}{$name};
a5e51f0b 103}
6d5355c3 104
c46b802b 105# ... these functions deal with stuff on the namespace level
106
a5e51f0b 107sub has_package_symbol {
108 my ($self, $variable) = @_;
109
110 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
56dcfc1a 111
ae234dc6 112 my $namespace = $self->namespace;
113
114 return 0 unless exists $namespace->{$name};
d852f4d2 115
116 # FIXME:
117 # For some really stupid reason
118 # a typeglob will have a default
119 # value of \undef in the SCALAR
120 # slot, so we need to work around
121 # this. Which of course means that
122 # if you put \undef in your scalar
123 # then this is broken.
92af7fdf 124
ae234dc6 125 if (ref($namespace->{$name}) eq 'SCALAR') {
92af7fdf 126 return ($type eq 'CODE' ? 1 : 0);
127 }
128 elsif ($type eq 'SCALAR') {
ae234dc6 129 my $val = *{$namespace->{$name}}{$type};
92af7fdf 130 return defined(${$val}) ? 1 : 0;
d852f4d2 131 }
132 else {
ae234dc6 133 defined(*{$namespace->{$name}}{$type}) ? 1 : 0;
d852f4d2 134 }
a5e51f0b 135}
136
137sub get_package_symbol {
138 my ($self, $variable) = @_;
139
140 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
141
ae234dc6 142 my $namespace = $self->namespace;
143
c20522bd 144 $self->add_package_symbol($variable)
ae234dc6 145 unless exists $namespace->{$name};
92af7fdf 146
ae234dc6 147 if (ref($namespace->{$name}) eq 'SCALAR') {
92af7fdf 148 if ($type eq 'CODE') {
149 no strict 'refs';
150 return \&{$self->name.'::'.$name};
151 }
152 else {
153 return undef;
154 }
155 }
156 else {
ae234dc6 157 return *{$namespace->{$name}}{$type};
92af7fdf 158 }
a5e51f0b 159}
160
161sub remove_package_symbol {
162 my ($self, $variable) = @_;
163
164 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
165
c46b802b 166 # FIXME:
167 # no doubt this is grossly inefficient and
168 # could be done much easier and faster in XS
169
170 my ($scalar, $array, $hash, $code);
a5e51f0b 171 if ($type eq 'SCALAR') {
c46b802b 172 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
173 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
174 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 175 }
176 elsif ($type eq 'ARRAY') {
c46b802b 177 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
178 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
179 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 180 }
181 elsif ($type eq 'HASH') {
c46b802b 182 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
183 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
184 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 185 }
186 elsif ($type eq 'CODE') {
c46b802b 187 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
188 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
189 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
a5e51f0b 190 }
191 else {
192 confess "This should never ever ever happen";
7f436b8c 193 }
c46b802b 194
195 $self->remove_package_glob($name);
196
197 $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar;
198 $self->add_package_symbol(('@' . $name) => $array) if defined $array;
199 $self->add_package_symbol(('%' . $name) => $hash) if defined $hash;
200 $self->add_package_symbol(('&' . $name) => $code) if defined $code;
9d6dce77 201}
c0cbf4d9 202
9d6dce77 203sub list_all_package_symbols {
92330ee2 204 my ($self, $type_filter) = @_;
205 return keys %{$self->namespace} unless defined $type_filter;
91e0eb4a 206 # NOTE:
92330ee2 207 # or we can filter based on
208 # type (SCALAR|ARRAY|HASH|CODE)
209 my $namespace = $self->namespace;
91e0eb4a 210 return grep {
92af7fdf 211 (ref($namespace->{$_})
212 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
213 : (ref(\$namespace->{$_}) eq 'GLOB'
214 && defined(*{$namespace->{$_}}{$type_filter})));
91e0eb4a 215 } keys %{$namespace};
6d5355c3 216}
217
ae234dc6 218sub get_all_package_symbols {
219 my ($self, $type_filter) = @_;
220 return %{$self->namespace} unless defined $type_filter;
221 # NOTE:
222 # or we can filter based on
223 # type (SCALAR|ARRAY|HASH|CODE)
224 my $namespace = $self->namespace;
225 no strict 'refs';
226 return map {
227 $_ => (ref($namespace->{$_}) eq 'SCALAR'
228 ? ($type_filter eq 'CODE' ? \&{$self->name . '::' . $_} : undef)
229 : *{$namespace->{$_}}{$type_filter})
230 } grep {
231 (ref($namespace->{$_})
232 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
233 : (ref(\$namespace->{$_}) eq 'GLOB'
234 && defined(*{$namespace->{$_}}{$type_filter})));
235 } keys %{$namespace};
236}
237
2243a22b 2381;
239
240__END__
241
242=pod
243
244=head1 NAME
245
246Class::MOP::Package - Package Meta Object
247
2243a22b 248=head1 DESCRIPTION
249
127d39a7 250This is an abstraction of a Perl 5 package, it is a superclass of
251L<Class::MOP::Class> and provides all of the symbol table
252introspection methods.
253
2243a22b 254=head1 METHODS
255
256=over 4
257
258=item B<meta>
259
127d39a7 260Returns a metaclass for this package.
261
b9d9fc0b 262=item B<initialize ($package_name)>
6d5355c3 263
127d39a7 264This will initialize a Class::MOP::Package instance which represents
265the package of C<$package_name>.
266
6d5355c3 267=item B<name>
268
b9d9fc0b 269This is a read-only attribute which returns the package name for the
270given instance.
271
a5e51f0b 272=item B<namespace>
273
b9d9fc0b 274This returns a HASH reference to the symbol table. The keys of the
275HASH are the symbol names, and the values are typeglob references.
276
277=item B<add_package_symbol ($variable_name, ?$initial_value)>
278
279Given a C<$variable_name>, which must contain a leading sigil, this
280method will create that variable within the package which houses the
281class. It also takes an optional C<$initial_value>, which must be a
282reference of the same type as the sigil of the C<$variable_name>
283implies.
284
285=item B<get_package_symbol ($variable_name)>
6d5355c3 286
b9d9fc0b 287This will return a reference to the package variable in
288C<$variable_name>.
6d5355c3 289
b9d9fc0b 290=item B<has_package_symbol ($variable_name)>
6d5355c3 291
b9d9fc0b 292Returns true (C<1>) if there is a package variable defined for
293C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 294
b9d9fc0b 295=item B<remove_package_symbol ($variable_name)>
296
297This will attempt to remove the package variable at C<$variable_name>.
298
299=item B<remove_package_glob ($glob_name)>
300
301This will attempt to remove the entire typeglob associated with
302C<$glob_name> from the package.
c46b802b 303
92330ee2 304=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 305
b9d9fc0b 306This will list all the glob names associated with the current package.
307By inspecting the globs returned you can discern all the variables in
308the package.
309
92330ee2 310By passing a C<$type_filter>, you can limit the list to only those
311which match the filter (either SCALAR, ARRAY, HASH or CODE).
312
ae234dc6 313=item B<get_all_package_symbols (?$type_filter)>
314
315Works exactly like C<list_all_package_symbols> but returns a HASH of
316name => thing mapping instead of just an ARRAY of names.
317
2243a22b 318=back
319
1a09d9cc 320=head1 AUTHORS
2243a22b 321
322Stevan Little E<lt>stevan@iinteractive.comE<gt>
323
324=head1 COPYRIGHT AND LICENSE
325
69e3ab0a 326Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 327
328L<http://www.iinteractive.com>
329
330This library is free software; you can redistribute it and/or modify
331it under the same terms as Perl itself.
332
92af7fdf 333=cut