various tweaks, and refactor _instantiate_module not to use eval STRING
[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
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;
ec9e38e5 61 return Class::MOP::Class->initialize($class)->new_object(@_)
62 if $class ne __PACKAGE__;
682655a3 63
ec9e38e5 64 my $params = @_ == 1 ? $_[0] : {@_};
65
66 return bless {
67 package => $params->{package},
68
69 # NOTE:
70 # because of issues with the Perl API
71 # to the typeglob in some versions, we
72 # need to just always grab a new
73 # reference to the hash in the accessor.
74 # Ideally we could just store a ref and
75 # it would Just Work, but oh well :\
76
77 namespace => \undef,
0bfc85b8 78
ec9e38e5 79 } => $class;
6d5355c3 80}
81
82# Attributes
83
84# NOTE:
85# all these attribute readers will be bootstrapped
86# away in the Class::MOP bootstrap section
87
56dcfc1a 88sub namespace {
89 # NOTE:
90 # because of issues with the Perl API
91 # to the typeglob in some versions, we
92 # need to just always grab a new
93 # reference to the hash here. Ideally
94 # we could just store a ref and it would
95 # Just Work, but oh well :\
96 no strict 'refs';
8683db0e 97 \%{$_[0]->{'package'} . '::'}
56dcfc1a 98}
6d5355c3 99
a5e51f0b 100# utility methods
6d5355c3 101
c0cbf4d9 102{
103 my %SIGIL_MAP = (
104 '$' => 'SCALAR',
105 '@' => 'ARRAY',
106 '%' => 'HASH',
107 '&' => 'CODE',
108 );
6d5355c3 109
a5e51f0b 110 sub _deconstruct_variable_name {
111 my ($self, $variable) = @_;
112
c0cbf4d9 113 (defined $variable)
114 || confess "You must pass a variable name";
a5e51f0b 115
f430cfa4 116 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 117
c0cbf4d9 118 (defined $sigil)
119 || confess "The variable name must include a sigil";
a5e51f0b 120
c0cbf4d9 121 (exists $SIGIL_MAP{$sigil})
a5e51f0b 122 || confess "I do not recognize that sigil '$sigil'";
123
f430cfa4 124 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 125 }
a5e51f0b 126}
6d5355c3 127
a5e51f0b 128# Class attributes
6d5355c3 129
c46b802b 130# ... these functions have to touch the symbol table itself,.. yuk
131
a5e51f0b 132sub add_package_symbol {
133 my ($self, $variable, $initial_value) = @_;
6d5355c3 134
8b49a472 135 my ($name, $sigil, $type) = ref $variable eq 'HASH'
136 ? @{$variable}{qw[name sigil type]}
26159d55 137 : $self->_deconstruct_variable_name($variable);
6d5355c3 138
8683db0e 139 my $pkg = $self->{'package'};
9a8bbfc9 140
a5e51f0b 141 no strict 'refs';
26159d55 142 no warnings 'redefine', 'misc', 'prototype';
143 *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 144}
145
146sub remove_package_glob {
147 my ($self, $name) = @_;
148 no strict 'refs';
149 delete ${$self->name . '::'}{$name};
a5e51f0b 150}
6d5355c3 151
c46b802b 152# ... these functions deal with stuff on the namespace level
153
a5e51f0b 154sub has_package_symbol {
155 my ($self, $variable) = @_;
156
8b49a472 157 my ($name, $sigil, $type) = ref $variable eq 'HASH'
158 ? @{$variable}{qw[name sigil type]}
159 : $self->_deconstruct_variable_name($variable);
56dcfc1a 160
ae234dc6 161 my $namespace = $self->namespace;
162
163 return 0 unless exists $namespace->{$name};
d852f4d2 164
55039f82 165 my $entry_ref = \$namespace->{$name};
166 if (ref($entry_ref) eq 'GLOB') {
167 if ($type eq 'SCALAR') {
168 return defined(${ *{$entry_ref}{SCALAR} });
169 }
170 else {
171 return defined(*{$entry_ref}{$type});
172 }
173 }
174 else {
175 # a symbol table entry can be -1 (stub), string (stub with prototype),
176 # or reference (constant)
177 return $type eq 'CODE';
d852f4d2 178 }
a5e51f0b 179}
180
181sub get_package_symbol {
182 my ($self, $variable) = @_;
183
8b49a472 184 my ($name, $sigil, $type) = ref $variable eq 'HASH'
185 ? @{$variable}{qw[name sigil type]}
186 : $self->_deconstruct_variable_name($variable);
a5e51f0b 187
ae234dc6 188 my $namespace = $self->namespace;
189
55039f82 190 # FIXME
c20522bd 191 $self->add_package_symbol($variable)
ae234dc6 192 unless exists $namespace->{$name};
92af7fdf 193
55039f82 194 my $entry_ref = \$namespace->{$name};
195
196 if (ref($entry_ref) eq 'GLOB') {
197 return *{$entry_ref}{$type};
198 }
199 else{
200 if($type eq 'CODE'){
92af7fdf 201 no strict 'refs';
55039f82 202 return \&{$self->name . '::' . $name};
92af7fdf 203 }
55039f82 204 else{
92af7fdf 205 return undef;
206 }
207 }
a5e51f0b 208}
209
210sub remove_package_symbol {
211 my ($self, $variable) = @_;
212
8b49a472 213 my ($name, $sigil, $type) = ref $variable eq 'HASH'
214 ? @{$variable}{qw[name sigil type]}
215 : $self->_deconstruct_variable_name($variable);
a5e51f0b 216
c46b802b 217 # FIXME:
218 # no doubt this is grossly inefficient and
219 # could be done much easier and faster in XS
220
8b49a472 221 my ($scalar_desc, $array_desc, $hash_desc, $code_desc) = (
222 { sigil => '$', type => 'SCALAR', name => $name },
223 { sigil => '@', type => 'ARRAY', name => $name },
224 { sigil => '%', type => 'HASH', name => $name },
225 { sigil => '&', type => 'CODE', name => $name },
226 );
227
c46b802b 228 my ($scalar, $array, $hash, $code);
a5e51f0b 229 if ($type eq 'SCALAR') {
8b49a472 230 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_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);
a5e51f0b 233 }
234 elsif ($type eq 'ARRAY') {
8b49a472 235 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
236 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
237 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 238 }
239 elsif ($type eq 'HASH') {
8b49a472 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 $code = $self->get_package_symbol($code_desc) if $self->has_package_symbol($code_desc);
a5e51f0b 243 }
244 elsif ($type eq 'CODE') {
8b49a472 245 $scalar = $self->get_package_symbol($scalar_desc) if $self->has_package_symbol($scalar_desc);
246 $array = $self->get_package_symbol($array_desc) if $self->has_package_symbol($array_desc);
247 $hash = $self->get_package_symbol($hash_desc) if $self->has_package_symbol($hash_desc);
a5e51f0b 248 }
249 else {
250 confess "This should never ever ever happen";
7f436b8c 251 }
c46b802b 252
253 $self->remove_package_glob($name);
254
8b49a472 255 $self->add_package_symbol($scalar_desc => $scalar) if defined $scalar;
256 $self->add_package_symbol($array_desc => $array) if defined $array;
257 $self->add_package_symbol($hash_desc => $hash) if defined $hash;
258 $self->add_package_symbol($code_desc => $code) if defined $code;
9d6dce77 259}
c0cbf4d9 260
9d6dce77 261sub list_all_package_symbols {
92330ee2 262 my ($self, $type_filter) = @_;
a38e4d1a 263
264 my $namespace = $self->namespace;
265 return keys %{$namespace} unless defined $type_filter;
266
91e0eb4a 267 # NOTE:
92330ee2 268 # or we can filter based on
269 # type (SCALAR|ARRAY|HASH|CODE)
3609af79 270 if ( $type_filter eq 'CODE' ) {
271 return grep {
92af7fdf 272 (ref($namespace->{$_})
3609af79 273 ? (ref($namespace->{$_}) eq 'SCALAR')
274 : (ref(\$namespace->{$_}) eq 'GLOB'
275 && defined(*{$namespace->{$_}}{CODE})));
276 } keys %{$namespace};
277 } else {
278 return grep { *{$namespace->{$_}}{$type_filter} } keys %{$namespace};
279 }
6d5355c3 280}
281
2243a22b 2821;
283
284__END__
285
286=pod
287
288=head1 NAME
289
290Class::MOP::Package - Package Meta Object
291
2243a22b 292=head1 DESCRIPTION
293
116a9f45 294The Package Protocol provides an abstraction of a Perl 5 package. A
295package is basically namespace, and this module provides methods for
296looking at and changing that namespace's symbol table.
121991f6 297
2243a22b 298=head1 METHODS
299
300=over 4
301
116a9f45 302=item B<< Class::MOP::Package->initialize($package_name) >>
303
304This method creates a new C<Class::MOP::Package> instance which
305represents specified package. If an existing metaclass object exists
306for the package, that will be returned instead.
307
308=item B<< Class::MOP::Package->reinitialize($package_name) >>
2243a22b 309
116a9f45 310This method forcibly removes any existing metaclass for the package
311before calling C<initialize>
127d39a7 312
116a9f45 313Do not call this unless you know what you are doing.
6d5355c3 314
116a9f45 315=item B<< $metapackage->name >>
127d39a7 316
116a9f45 317This is returns the package's name, as passed to the constructor.
a19fcb5b 318
116a9f45 319=item B<< $metapackage->namespace >>
a19fcb5b 320
116a9f45 321This returns a hash reference to the package's symbol table. The keys
322are symbol names and the values are typeglob references.
6d5355c3 323
116a9f45 324=item B<< $metapackage->add_package_symbol($variable_name, $initial_value) >>
b9d9fc0b 325
116a9f45 326This method accepts a variable name and an optional initial value. The
327C<$variable_name> must contain a leading sigil.
a5e51f0b 328
116a9f45 329This method creates the variable in the package's symbol table, and
330sets it to the initial value if one was provided.
b9d9fc0b 331
116a9f45 332=item B<< $metapackage->get_package_symbol($variable_name) >>
b9d9fc0b 333
116a9f45 334Given a variable name, this method returns the variable as a reference
335or undef if it does not exist. The C<$variable_name> must contain a
336leading sigil.
b9d9fc0b 337
116a9f45 338=item B<< $metapackage->has_package_symbol($variable_name) >>
6d5355c3 339
116a9f45 340Returns true if there is a package variable defined for
341C<$variable_name>. The C<$variable_name> must contain a leading sigil.
6d5355c3 342
116a9f45 343=item B<< $metapackage->remove_package_symbol($variable_name) >>
6d5355c3 344
116a9f45 345This will remove the package variable specified C<$variable_name>. The
346C<$variable_name> must contain a leading sigil.
6d5355c3 347
116a9f45 348=item B<< $metapackage->remove_package_glob($glob_name) >>
b9d9fc0b 349
116a9f45 350Given the name of a glob, this will remove that glob from the
351package's symbol table. Glob names do not include a sigil. Removing
352the glob removes all variables and subroutines with the specified
353name.
b9d9fc0b 354
116a9f45 355=item B<< $metapackage->list_all_package_symbols($type_filter) >>
b9d9fc0b 356
116a9f45 357This will list all the glob names associated with the current
358package. These names do not have leading sigils.
c46b802b 359
116a9f45 360You can provide an optional type filter, which should be one of
361'SCALAR', 'ARRAY', 'HASH', or 'CODE'.
9d6dce77 362
116a9f45 363=item B<< $metapackage->get_all_package_symbols($type_filter) >>
b9d9fc0b 364
116a9f45 365This works much like C<list_all_package_symbols>, but it returns a
366hash reference. The keys are glob names and the values are references
367to the value for that name.
92330ee2 368
116a9f45 369=item B<< Class::MOP::Package->meta >>
ae234dc6 370
116a9f45 371This will return a L<Class::MOP::Class> instance for this class.
ae234dc6 372
2243a22b 373=back
374
1a09d9cc 375=head1 AUTHORS
2243a22b 376
377Stevan Little E<lt>stevan@iinteractive.comE<gt>
378
379=head1 COPYRIGHT AND LICENSE
380
070bb6c9 381Copyright 2006-2009 by Infinity Interactive, Inc.
2243a22b 382
383L<http://www.iinteractive.com>
384
385This library is free software; you can redistribute it and/or modify
386it under the same terms as Perl itself.
387
92af7fdf 388=cut