fix MOP.xs for 5.8
[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) = @_;
a38e4d1a 205
206 my $namespace = $self->namespace;
207 return keys %{$namespace} unless defined $type_filter;
208
91e0eb4a 209 # NOTE:
92330ee2 210 # or we can filter based on
211 # type (SCALAR|ARRAY|HASH|CODE)
91e0eb4a 212 return grep {
92af7fdf 213 (ref($namespace->{$_})
214 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
215 : (ref(\$namespace->{$_}) eq 'GLOB'
216 && defined(*{$namespace->{$_}}{$type_filter})));
91e0eb4a 217 } keys %{$namespace};
6d5355c3 218}
219
ae234dc6 220sub get_all_package_symbols {
221 my ($self, $type_filter) = @_;
a38e4d1a 222 my $namespace = $self->namespace;
223 return %{$namespace} unless defined $type_filter;
224
ae234dc6 225 # NOTE:
226 # or we can filter based on
227 # type (SCALAR|ARRAY|HASH|CODE)
ae234dc6 228 no strict 'refs';
229 return map {
230 $_ => (ref($namespace->{$_}) eq 'SCALAR'
231 ? ($type_filter eq 'CODE' ? \&{$self->name . '::' . $_} : undef)
232 : *{$namespace->{$_}}{$type_filter})
233 } grep {
234 (ref($namespace->{$_})
235 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
236 : (ref(\$namespace->{$_}) eq 'GLOB'
237 && defined(*{$namespace->{$_}}{$type_filter})));
238 } keys %{$namespace};
239}
240
2243a22b 2411;
242
243__END__
244
245=pod
246
247=head1 NAME
248
249Class::MOP::Package - Package Meta Object
250
2243a22b 251=head1 DESCRIPTION
252
127d39a7 253This is an abstraction of a Perl 5 package, it is a superclass of
254L<Class::MOP::Class> and provides all of the symbol table
255introspection methods.
256
2243a22b 257=head1 METHODS
258
259=over 4
260
261=item B<meta>
262
127d39a7 263Returns a metaclass for this package.
264
b9d9fc0b 265=item B<initialize ($package_name)>
6d5355c3 266
127d39a7 267This will initialize a Class::MOP::Package instance which represents
268the package of C<$package_name>.
269
6d5355c3 270=item B<name>
271
b9d9fc0b 272This is a read-only attribute which returns the package name for the
273given instance.
274
a5e51f0b 275=item B<namespace>
276
b9d9fc0b 277This returns a HASH reference to the symbol table. The keys of the
278HASH are the symbol names, and the values are typeglob references.
279
280=item B<add_package_symbol ($variable_name, ?$initial_value)>
281
282Given a C<$variable_name>, which must contain a leading sigil, this
283method will create that variable within the package which houses the
284class. It also takes an optional C<$initial_value>, which must be a
285reference of the same type as the sigil of the C<$variable_name>
286implies.
287
288=item B<get_package_symbol ($variable_name)>
6d5355c3 289
b9d9fc0b 290This will return a reference to the package variable in
291C<$variable_name>.
6d5355c3 292
b9d9fc0b 293=item B<has_package_symbol ($variable_name)>
6d5355c3 294
b9d9fc0b 295Returns true (C<1>) if there is a package variable defined for
296C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 297
b9d9fc0b 298=item B<remove_package_symbol ($variable_name)>
299
300This will attempt to remove the package variable at C<$variable_name>.
301
302=item B<remove_package_glob ($glob_name)>
303
304This will attempt to remove the entire typeglob associated with
305C<$glob_name> from the package.
c46b802b 306
92330ee2 307=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 308
b9d9fc0b 309This will list all the glob names associated with the current package.
310By inspecting the globs returned you can discern all the variables in
311the package.
312
92330ee2 313By passing a C<$type_filter>, you can limit the list to only those
314which match the filter (either SCALAR, ARRAY, HASH or CODE).
315
ae234dc6 316=item B<get_all_package_symbols (?$type_filter)>
317
318Works exactly like C<list_all_package_symbols> but returns a HASH of
319name => thing mapping instead of just an ARRAY of names.
320
2243a22b 321=back
322
1a09d9cc 323=head1 AUTHORS
2243a22b 324
325Stevan Little E<lt>stevan@iinteractive.comE<gt>
326
327=head1 COPYRIGHT AND LICENSE
328
69e3ab0a 329Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 330
331L<http://www.iinteractive.com>
332
333This library is free software; you can redistribute it and/or modify
334it under the same terms as Perl itself.
335
92af7fdf 336=cut