2 package Class::MOP::Package;
7 use Scalar::Util 'blessed';
10 our $VERSION = '0.65';
11 our $AUTHORITY = 'cpan:STEVAN';
13 use base 'Class::MOP::Object';
19 my $package_name = shift;
20 # we hand-construct the class
21 # until we can bootstrap it
22 return Class::MOP::get_metaclass_by_name($package_name) ||
24 'package' => $package_name,
30 my $options = @_ == 1 ? $_[0] : {@_};
33 # because of issues with the Perl API
34 # to the typeglob in some versions, we
35 # need to just always grab a new
36 # reference to the hash in the accessor.
37 # Ideally we could just store a ref and
38 # it would Just Work, but oh well :\
39 $options->{namespace} ||= \undef;
41 bless $options, $class;
47 # all these attribute readers will be bootstrapped
48 # away in the Class::MOP bootstrap section
50 sub name { $_[0]->{'package'} }
53 # because of issues with the Perl API
54 # to the typeglob in some versions, we
55 # need to just always grab a new
56 # reference to the hash here. Ideally
57 # we could just store a ref and it would
58 # Just Work, but oh well :\
60 \%{$_[0]->{'package'} . '::'}
73 sub _deconstruct_variable_name {
74 my ($self, $variable) = @_;
77 || confess "You must pass a variable name";
79 my $sigil = substr($variable, 0, 1, '');
82 || confess "The variable name must include a sigil";
84 (exists $SIGIL_MAP{$sigil})
85 || confess "I do not recognize that sigil '$sigil'";
87 return ($variable, $sigil, $SIGIL_MAP{$sigil});
93 # ... these functions have to touch the symbol table itself,.. yuk
95 sub add_package_symbol {
96 my ($self, $variable, $initial_value) = @_;
98 my ($name, $sigil, $type) = ref $variable eq 'HASH'
99 ? @{$variable}{qw[name sigil type]}
100 : $self->_deconstruct_variable_name($variable);
102 my $pkg = $self->{'package'};
105 no warnings 'redefine', 'misc';
106 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
109 sub remove_package_glob {
110 my ($self, $name) = @_;
112 delete ${$self->name . '::'}{$name};
115 # ... these functions deal with stuff on the namespace level
117 sub has_package_symbol {
118 my ($self, $variable) = @_;
120 my ($name, $sigil, $type) = ref $variable eq 'HASH'
121 ? @{$variable}{qw[name sigil type]}
122 : $self->_deconstruct_variable_name($variable);
124 my $namespace = $self->namespace;
126 return 0 unless exists $namespace->{$name};
129 # For some really stupid reason
130 # a typeglob will have a default
131 # value of \undef in the SCALAR
132 # slot, so we need to work around
133 # this. Which of course means that
134 # if you put \undef in your scalar
135 # then this is broken.
137 if (ref($namespace->{$name}) eq 'SCALAR') {
138 return ($type eq 'CODE');
140 elsif ($type eq 'SCALAR') {
141 my $val = *{$namespace->{$name}}{$type};
142 return defined(${$val});
145 defined(*{$namespace->{$name}}{$type});
149 sub get_package_symbol {
150 my ($self, $variable) = @_;
152 my ($name, $sigil, $type) = ref $variable eq 'HASH'
153 ? @{$variable}{qw[name sigil type]}
154 : $self->_deconstruct_variable_name($variable);
156 my $namespace = $self->namespace;
158 $self->add_package_symbol($variable)
159 unless exists $namespace->{$name};
161 if (ref($namespace->{$name}) eq 'SCALAR') {
162 if ($type eq 'CODE') {
164 return \&{$self->name.'::'.$name};
171 return *{$namespace->{$name}}{$type};
175 sub remove_package_symbol {
176 my ($self, $variable) = @_;
178 my ($name, $sigil, $type) = ref $variable eq 'HASH'
179 ? @{$variable}{qw[name sigil type]}
180 : $self->_deconstruct_variable_name($variable);
183 # no doubt this is grossly inefficient and
184 # could be done much easier and faster in XS
186 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
187 { sigil => '$', type => 'SCALAR', name => $name },
188 { sigil => '@', type => 'ARRAY', name => $name },
189 { sigil => '%', type => 'HASH', name => $name },
190 { sigil => '&', type => 'CODE', name => $name },
193 my ($scalar, $array, $hash, $code);
194 if ($type eq 'SCALAR') {
195 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
196 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
197 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
199 elsif ($type eq 'ARRAY') {
200 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
201 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
202 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
204 elsif ($type eq 'HASH') {
205 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
206 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
207 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
209 elsif ($type eq 'CODE') {
210 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
211 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
212 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
215 confess "This should never ever ever happen";
218 $self->remove_package_glob($name);
220 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
221 $self->add_package_symbol($array_desc => $array) if defined $array;
222 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
223 $self->add_package_symbol($code_desc => $code) if defined $code;
226 sub list_all_package_symbols {
227 my ($self, $type_filter) = @_;
229 my $namespace = $self->namespace;
230 return keys %{$namespace} unless defined $type_filter;
233 # or we can filter based on
234 # type (SCALAR|ARRAY|HASH|CODE)
235 if ( $type_filter eq 'CODE' ) {
237 (ref($namespace->{$_})
238 ? (ref($namespace->{$_}) eq 'SCALAR')
239 : (ref(\$namespace->{$_}) eq 'GLOB'
240 && defined(*{$namespace->{$_}}{CODE})));
241 } keys %{$namespace};
243 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
247 sub get_all_package_symbols {
248 my ($self, $type_filter) = @_;
249 my $namespace = $self->namespace;
251 return %$namespace unless defined $type_filter;
253 # for some reason this nasty impl is orders of magnitude aster than a clean version
254 if ( $type_filter eq 'CODE' ) {
258 (ref($namespace->{$_})
259 ? ( $_ => \&{$pkg ||= $self->name . "::$_"} )
260 : ( *{$namespace->{$_}}{CODE}
261 ? ( $_ => *{$namespace->{$_}}{$type_filter} )
266 $_ => *{$namespace->{$_}}{$type_filter}
268 !ref($namespace->{$_}) && *{$namespace->{$_}}{$type_filter}
281 Class::MOP::Package - Package Meta Object
285 This is an abstraction of a Perl 5 package, it is a superclass of
286 L<Class::MOP::Class> and provides all of the symbol table
287 introspection methods.
295 Returns a metaclass for this package.
297 =item B<initialize ($package_name)>
299 This will initialize a Class::MOP::Package instance which represents
300 the package of C<$package_name>.
304 This is a read-only attribute which returns the package name for the
309 This returns a HASH reference to the symbol table. The keys of the
310 HASH are the symbol names, and the values are typeglob references.
312 =item B<add_package_symbol ($variable_name, ?$initial_value)>
314 Given a C<$variable_name>, which must contain a leading sigil, this
315 method will create that variable within the package which houses the
316 class. It also takes an optional C<$initial_value>, which must be a
317 reference of the same type as the sigil of the C<$variable_name>
320 =item B<get_package_symbol ($variable_name)>
322 This will return a reference to the package variable in
325 =item B<has_package_symbol ($variable_name)>
327 Returns true (C<1>) if there is a package variable defined for
328 C<$variable_name>, and false (C<0>) otherwise.
330 =item B<remove_package_symbol ($variable_name)>
332 This will attempt to remove the package variable at C<$variable_name>.
334 =item B<remove_package_glob ($glob_name)>
336 This will attempt to remove the entire typeglob associated with
337 C<$glob_name> from the package.
339 =item B<list_all_package_symbols (?$type_filter)>
341 This will list all the glob names associated with the current package.
342 By inspecting the globs returned you can discern all the variables in
345 By passing a C<$type_filter>, you can limit the list to only those
346 which match the filter (either SCALAR, ARRAY, HASH or CODE).
348 =item B<get_all_package_symbols (?$type_filter)>
350 Works exactly like C<list_all_package_symbols> but returns a HASH of
351 name => thing mapping instead of just an ARRAY of names.
357 Stevan Little E<lt>stevan@iinteractive.comE<gt>
359 =head1 COPYRIGHT AND LICENSE
361 Copyright 2006-2008 by Infinity Interactive, Inc.
363 L<http://www.iinteractive.com>
365 This library is free software; you can redistribute it and/or modify
366 it under the same terms as Perl itself.