2 package Class::MOP::Package;
7 use Scalar::Util 'blessed';
10 our $VERSION = '0.89';
11 $VERSION = eval $VERSION;
12 our $AUTHORITY = 'cpan:STEVAN';
14 use base 'Class::MOP::Object';
19 my ( $class, @args ) = @_;
21 unshift @args, "package" if @args % 2;
24 my $package_name = $options{package};
27 # we hand-construct the class
28 # until we can bootstrap it
29 if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
32 my $meta = ( ref $class || $class )->_new({
33 'package' => $package_name,
37 Class::MOP::store_metaclass_by_name($package_name, $meta);
44 my ( $class, @args ) = @_;
46 unshift @args, "package" if @args % 2;
49 my $package_name = delete $options{package};
51 (defined $package_name && $package_name && !blessed($package_name))
52 || confess "You must pass a package name and it cannot be blessed";
54 Class::MOP::remove_metaclass_by_name($package_name);
56 $class->initialize($package_name, %options); # call with first arg form for compat
61 my $options = @_ == 1 ? $_[0] : {@_};
64 # because of issues with the Perl API
65 # to the typeglob in some versions, we
66 # need to just always grab a new
67 # reference to the hash in the accessor.
68 # Ideally we could just store a ref and
69 # it would Just Work, but oh well :\
70 $options->{namespace} ||= \undef;
72 bless $options, $class;
78 # all these attribute readers will be bootstrapped
79 # away in the Class::MOP bootstrap section
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 :\
90 \%{$_[0]->{'package'} . '::'}
103 sub _deconstruct_variable_name {
104 my ($self, $variable) = @_;
107 || confess "You must pass a variable name";
109 my $sigil = substr($variable, 0, 1, '');
112 || confess "The variable name must include a sigil";
114 (exists $SIGIL_MAP{$sigil})
115 || confess "I do not recognize that sigil '$sigil'";
117 return ($variable, $sigil, $SIGIL_MAP{$sigil});
123 # ... these functions have to touch the symbol table itself,.. yuk
125 sub add_package_symbol {
126 my ($self, $variable, $initial_value) = @_;
128 my ($name, $sigil, $type) = ref $variable eq 'HASH'
129 ? @{$variable}{qw[name sigil type]}
130 : $self->_deconstruct_variable_name($variable);
132 my $pkg = $self->{'package'};
135 no warnings 'redefine', 'misc', 'prototype';
136 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
139 sub remove_package_glob {
140 my ($self, $name) = @_;
142 delete ${$self->name . '::'}{$name};
145 # ... these functions deal with stuff on the namespace level
147 sub has_package_symbol {
148 my ($self, $variable) = @_;
150 my ($name, $sigil, $type) = ref $variable eq 'HASH'
151 ? @{$variable}{qw[name sigil type]}
152 : $self->_deconstruct_variable_name($variable);
154 my $namespace = $self->namespace;
156 return 0 unless exists $namespace->{$name};
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.
167 if (ref($namespace->{$name}) eq 'SCALAR') {
168 return ($type eq 'CODE');
170 elsif ($type eq 'SCALAR') {
171 my $val = *{$namespace->{$name}}{$type};
172 return defined(${$val});
175 defined(*{$namespace->{$name}}{$type});
179 sub get_package_symbol {
180 my ($self, $variable) = @_;
182 my ($name, $sigil, $type) = ref $variable eq 'HASH'
183 ? @{$variable}{qw[name sigil type]}
184 : $self->_deconstruct_variable_name($variable);
186 my $namespace = $self->namespace;
188 $self->add_package_symbol($variable)
189 unless exists $namespace->{$name};
191 if (ref($namespace->{$name}) eq 'SCALAR') {
192 if ($type eq 'CODE') {
194 return \&{$self->name.'::'.$name};
201 return *{$namespace->{$name}}{$type};
205 sub remove_package_symbol {
206 my ($self, $variable) = @_;
208 my ($name, $sigil, $type) = ref $variable eq 'HASH'
209 ? @{$variable}{qw[name sigil type]}
210 : $self->_deconstruct_variable_name($variable);
213 # no doubt this is grossly inefficient and
214 # could be done much easier and faster in XS
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 },
223 my ($scalar, $array, $hash, $code);
224 if ($type eq 'SCALAR') {
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);
229 elsif ($type eq 'ARRAY') {
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);
234 elsif ($type eq 'HASH') {
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);
239 elsif ($type eq 'CODE') {
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);
245 confess "This should never ever ever happen";
248 $self->remove_package_glob($name);
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;
256 sub list_all_package_symbols {
257 my ($self, $type_filter) = @_;
259 my $namespace = $self->namespace;
260 return keys %{$namespace} unless defined $type_filter;
263 # or we can filter based on
264 # type (SCALAR|ARRAY|HASH|CODE)
265 if ( $type_filter eq 'CODE' ) {
267 (ref($namespace->{$_})
268 ? (ref($namespace->{$_}) eq 'SCALAR')
269 : (ref(\$namespace->{$_}) eq 'GLOB'
270 && defined(*{$namespace->{$_}}{CODE})));
271 } keys %{$namespace};
273 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
285 Class::MOP::Package - Package Meta Object
289 The Package Protocol provides an abstraction of a Perl 5 package. A
290 package is basically namespace, and this module provides methods for
291 looking at and changing that namespace's symbol table.
297 =item B<< Class::MOP::Package->initialize($package_name) >>
299 This method creates a new C<Class::MOP::Package> instance which
300 represents specified package. If an existing metaclass object exists
301 for the package, that will be returned instead.
303 =item B<< Class::MOP::Package->reinitialize($package_name) >>
305 This method forcibly removes any existing metaclass for the package
306 before calling C<initialize>
308 Do not call this unless you know what you are doing.
310 =item B<< $metapackage->name >>
312 This is returns the package's name, as passed to the constructor.
314 =item B<< $metapackage->namespace >>
316 This returns a hash reference to the package's symbol table. The keys
317 are symbol names and the values are typeglob references.
319 =item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
321 This method accepts a variable name and an optional initial value. The
322 C<$variable_name> must contain a leading sigil.
324 This method creates the variable in the package's symbol table, and
325 sets it to the initial value if one was provided.
327 =item B<< $metapackage->get_package_symbol($variable_name) >>
329 Given a variable name, this method returns the variable as a reference
330 or undef if it does not exist. The C<$variable_name> must contain a
333 =item B<< $metapackage->has_package_symbol($variable_name) >>
335 Returns true if there is a package variable defined for
336 C<$variable_name>. The C<$variable_name> must contain a leading sigil.
338 =item B<< $metapackage->remove_package_symbol($variable_name) >>
340 This will remove the package variable specified C<$variable_name>. The
341 C<$variable_name> must contain a leading sigil.
343 =item B<< $metapackage->remove_package_glob($glob_name) >>
345 Given the name of a glob, this will remove that glob from the
346 package's symbol table. Glob names do not include a sigil. Removing
347 the glob removes all variables and subroutines with the specified
350 =item B<< $metapackage->list_all_package_symbols($type_filter) >>
352 This will list all the glob names associated with the current
353 package. These names do not have leading sigils.
355 You can provide an optional type filter, which should be one of
356 'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
358 =item B<< $metapackage->get_all_package_symbols($type_filter) >>
360 This works much like C<list_all_package_symbols>, but it returns a
361 hash reference. The keys are glob names and the values are references
362 to the value for that name.
364 =item B<< Class::MOP::Package->meta >>
366 This will return a L<Class::MOP::Class> instance for this class.
372 Stevan Little E<lt>stevan@iinteractive.comE<gt>
374 =head1 COPYRIGHT AND LICENSE
376 Copyright 2006-2009 by Infinity Interactive, Inc.
378 L<http://www.iinteractive.com>
380 This library is free software; you can redistribute it and/or modify
381 it under the same terms as Perl itself.