Remove a "no strict 'refs'" statement
[gitmo/Class-MOP.git] / lib / Class / MOP / Package.pm
CommitLineData
2243a22b 1
2package Class::MOP::Package;
3
4use strict;
5use warnings;
6
812d58f9 7use Scalar::Util 'blessed', 'reftype';
6d5355c3 8use Carp 'confess';
2243a22b 9
074ec38f 10our $VERSION = '0.89';
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) ) {
973de492 30 return $meta;
a19fcb5b 31 } else {
973de492 32 my $meta = ( ref $class || $class )->_new({
33 'package' => $package_name,
11ac821d 34 %options,
973de492 35 });
a19fcb5b 36
973de492 37 Class::MOP::store_metaclass_by_name($package_name, $meta);
a19fcb5b 38
973de492 39 return $meta;
a19fcb5b 40 }
41}
42
43sub reinitialize {
3be6bc1c 44 my ( $class, @args ) = @_;
45
46 unshift @args, "package" if @args % 2;
47
48 my %options = @args;
3eda22f8 49 my $package_name = delete $options{package};
3be6bc1c 50
a19fcb5b 51 (defined $package_name && $package_name && !blessed($package_name))
52 || confess "You must pass a package name and it cannot be blessed";
3be6bc1c 53
a19fcb5b 54 Class::MOP::remove_metaclass_by_name($package_name);
3be6bc1c 55
3eda22f8 56 $class->initialize($package_name, %options); # call with first arg form for compat
682655a3 57}
58
59sub _new {
0bfc85b8 60 my $class = shift;
812d58f9 61
ec9e38e5 62 return Class::MOP::Class->initialize($class)->new_object(@_)
812d58f9 63 if $class ne __PACKAGE__;
682655a3 64
ec9e38e5 65 my $params = @_ == 1 ? $_[0] : {@_};
66
67 return bless {
68 package => $params->{package},
69
70 # NOTE:
71 # because of issues with the Perl API
72 # to the typeglob in some versions, we
73 # need to just always grab a new
74 # reference to the hash in the accessor.
75 # Ideally we could just store a ref and
76 # it would Just Work, but oh well :\
77
78 namespace => \undef,
0bfc85b8 79
ec9e38e5 80 } => $class;
6d5355c3 81}
82
83# Attributes
84
85# NOTE:
86# all these attribute readers will be bootstrapped
87# away in the Class::MOP bootstrap section
88
56dcfc1a 89sub namespace {
90 # NOTE:
91 # because of issues with the Perl API
92 # to the typeglob in some versions, we
93 # need to just always grab a new
94 # reference to the hash here. Ideally
95 # we could just store a ref and it would
96 # Just Work, but oh well :\
97 no strict 'refs';
8683db0e 98 \%{$_[0]->{'package'} . '::'}
56dcfc1a 99}
6d5355c3 100
a5e51f0b 101# utility methods
6d5355c3 102
c0cbf4d9 103{
104 my %SIGIL_MAP = (
105 '$' => 'SCALAR',
106 '@' => 'ARRAY',
107 '%' => 'HASH',
108 '&' => 'CODE',
109 );
6d5355c3 110
a5e51f0b 111 sub _deconstruct_variable_name {
112 my ($self, $variable) = @_;
113
c0cbf4d9 114 (defined $variable)
115 || confess "You must pass a variable name";
a5e51f0b 116
f430cfa4 117 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 118
c0cbf4d9 119 (defined $sigil)
120 || confess "The variable name must include a sigil";
a5e51f0b 121
c0cbf4d9 122 (exists $SIGIL_MAP{$sigil})
a5e51f0b 123 || confess "I do not recognize that sigil '$sigil'";
124
f430cfa4 125 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 126 }
a5e51f0b 127}
6d5355c3 128
a5e51f0b 129# Class attributes
6d5355c3 130
c46b802b 131# ... these functions have to touch the symbol table itself,.. yuk
132
c46b802b 133sub remove_package_glob {
134 my ($self, $name) = @_;
ef2ed956 135 delete $self->namespace->{$name};
a5e51f0b 136}
6d5355c3 137
a5e51f0b 138sub remove_package_symbol {
139 my ($self, $variable) = @_;
140
8b49a472 141 my ($name, $sigil, $type) = ref $variable eq 'HASH'
142 ? @{$variable}{qw[name sigil type]}
143 : $self->_deconstruct_variable_name($variable);
a5e51f0b 144
c46b802b 145 # FIXME:
146 # no doubt this is grossly inefficient and
147 # could be done much easier and faster in XS
148
8b49a472 149 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
150 { sigil => '$', type => 'SCALAR', name => $name },
151 { sigil => '@', type => 'ARRAY', name => $name },
152 { sigil => '%', type => 'HASH', name => $name },
153 { sigil => '&', type => 'CODE', name => $name },
154 );
155
c46b802b 156 my ($scalar, $array, $hash, $code);
a5e51f0b 157 if ($type eq 'SCALAR') {
8b49a472 158 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
159 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
160 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 161 }
162 elsif ($type eq 'ARRAY') {
8b49a472 163 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
164 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
165 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 166 }
167 elsif ($type eq 'HASH') {
8b49a472 168 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
169 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
170 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 171 }
172 elsif ($type eq 'CODE') {
8b49a472 173 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
174 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
175 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 176 }
177 else {
178 confess "This should never ever ever happen";
7f436b8c 179 }
c46b802b 180
181 $self->remove_package_glob($name);
182
8b49a472 183 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
184 $self->add_package_symbol($array_desc => $array) if defined $array;
185 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
186 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 187}
c0cbf4d9 188
9d6dce77 189sub list_all_package_symbols {
92330ee2 190 my ($self, $type_filter) = @_;
a38e4d1a 191
192 my $namespace = $self->namespace;
193 return keys %{$namespace} unless defined $type_filter;
194
91e0eb4a 195 # NOTE:
92330ee2 196 # or we can filter based on
197 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 198 if ( $type_filter eq 'CODE' ) {
199 return grep {
92af7fdf 200 (ref($namespace->{$_})
3609af79 201 ? (ref($namespace->{$_}) eq 'SCALAR')
202 : (ref(\$namespace->{$_}) eq 'GLOB'
203 && defined(*{$namespace->{$_}}{CODE})));
204 } keys %{$namespace};
205 } else {
206 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
207 }
6d5355c3 208}
209
2243a22b 2101;
211
212__END__
213
214=pod
215
216=head1 NAME
217
218Class::MOP::Package - Package Meta Object
219
2243a22b 220=head1 DESCRIPTION
221
116a9f45 222The Package Protocol provides an abstraction of a Perl 5 package. A
223package is basically namespace, and this module provides methods for
224looking at and changing that namespace's symbol table.
121991f6 225
2243a22b 226=head1 METHODS
227
228=over 4
229
116a9f45 230=item B<< Class::MOP::Package->initialize($package_name) >>
231
232This method creates a new C<Class::MOP::Package> instance which
233represents specified package. If an existing metaclass object exists
234for the package, that will be returned instead.
235
236=item B<< Class::MOP::Package->reinitialize($package_name) >>
2243a22b 237
116a9f45 238This method forcibly removes any existing metaclass for the package
239before calling C<initialize>
127d39a7 240
116a9f45 241Do not call this unless you know what you are doing.
6d5355c3 242
116a9f45 243=item B<< $metapackage->name >>
127d39a7 244
116a9f45 245This is returns the package's name, as passed to the constructor.
a19fcb5b 246
116a9f45 247=item B<< $metapackage->namespace >>
a19fcb5b 248
116a9f45 249This returns a hash reference to the package's symbol table. The keys
250are symbol names and the values are typeglob references.
6d5355c3 251
116a9f45 252=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 253
116a9f45 254This method accepts a variable name and an optional initial value. The
255C<$variable_name> must contain a leading sigil.
a5e51f0b 256
116a9f45 257This method creates the variable in the package's symbol table, and
258sets it to the initial value if one was provided.
b9d9fc0b 259
116a9f45 260=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 261
116a9f45 262Given a variable name, this method returns the variable as a reference
263or undef if it does not exist. The C<$variable_name> must contain a
264leading sigil.
b9d9fc0b 265
116a9f45 266=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 267
116a9f45 268Returns true if there is a package variable defined for
269C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 270
116a9f45 271=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 272
116a9f45 273This will remove the package variable specified C<$variable_name>. The
274C<$variable_name> must contain a leading sigil.
6d5355c3 275
116a9f45 276=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 277
116a9f45 278Given the name of a glob, this will remove that glob from the
279package's symbol table. Glob names do not include a sigil. Removing
280the glob removes all variables and subroutines with the specified
281name.
b9d9fc0b 282
116a9f45 283=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 284
116a9f45 285This will list all the glob names associated with the current
286package. These names do not have leading sigils.
c46b802b 287
116a9f45 288You can provide an optional type filter, which should be one of
289'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 290
116a9f45 291=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 292
116a9f45 293This works much like C<list_all_package_symbols>, but it returns a
294hash reference. The keys are glob names and the values are references
295to the value for that name.
92330ee2 296
116a9f45 297=item B<< Class::MOP::Package->meta >>
ae234dc6 298
116a9f45 299This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 300
2243a22b 301=back
302
1a09d9cc 303=head1 AUTHORS
2243a22b 304
305Stevan Little E<lt>stevan@iinteractive.comE<gt>
306
307=head1 COPYRIGHT AND LICENSE
308
070bb6c9 309Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 310
311L<http://www.iinteractive.com>
312
313This library is free software; you can redistribute it and/or modify
314it under the same terms as Perl itself.
315
92af7fdf 316=cut