bunch of doc fixes
[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
9195ddff 10our $VERSION = '0.07';
f0480c45 11our $AUTHORITY = 'cpan:STEVAN';
2243a22b 12
6e57504d 13use base 'Class::MOP::Object';
14
2243a22b 15# introspection
16
17sub meta {
18 require Class::MOP::Class;
19 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
20}
21
6d5355c3 22# creation ...
23
24sub initialize {
9d6dce77 25 my $class = shift;
26 my $package_name = shift;
27 # we hand-construct the class
28 # until we can bootstrap it
a5e51f0b 29 no strict 'refs';
30 return bless {
c23184fc 31 '$!package' => $package_name,
56dcfc1a 32 # NOTE:
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 :\
c23184fc 39 '%!namespace' => \undef,
a5e51f0b 40 } => $class;
6d5355c3 41}
42
43# Attributes
44
45# NOTE:
46# all these attribute readers will be bootstrapped
47# away in the Class::MOP bootstrap section
48
c23184fc 49sub name { $_[0]->{'$!package'} }
56dcfc1a 50sub namespace {
51 # NOTE:
52 # because of issues with the Perl API
53 # to the typeglob in some versions, we
54 # need to just always grab a new
55 # reference to the hash here. Ideally
56 # we could just store a ref and it would
57 # Just Work, but oh well :\
58 no strict 'refs';
59 \%{$_[0]->name . '::'}
60}
6d5355c3 61
a5e51f0b 62# utility methods
6d5355c3 63
c0cbf4d9 64{
65 my %SIGIL_MAP = (
66 '$' => 'SCALAR',
67 '@' => 'ARRAY',
68 '%' => 'HASH',
69 '&' => 'CODE',
70 );
6d5355c3 71
a5e51f0b 72 sub _deconstruct_variable_name {
73 my ($self, $variable) = @_;
74
c0cbf4d9 75 (defined $variable)
76 || confess "You must pass a variable name";
a5e51f0b 77
f430cfa4 78 my $sigil = substr($variable, 0, 1, '');
a5e51f0b 79
c0cbf4d9 80 (defined $sigil)
81 || confess "The variable name must include a sigil";
a5e51f0b 82
c0cbf4d9 83 (exists $SIGIL_MAP{$sigil})
a5e51f0b 84 || confess "I do not recognize that sigil '$sigil'";
85
f430cfa4 86 return ($variable, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 87 }
a5e51f0b 88}
6d5355c3 89
a5e51f0b 90# Class attributes
6d5355c3 91
c46b802b 92# ... these functions have to touch the symbol table itself,.. yuk
93
a5e51f0b 94sub add_package_symbol {
95 my ($self, $variable, $initial_value) = @_;
6d5355c3 96
a5e51f0b 97 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
6d5355c3 98
a5e51f0b 99 no strict 'refs';
56dcfc1a 100 no warnings 'redefine', 'misc';
101 *{$self->name . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
c46b802b 102}
103
104sub remove_package_glob {
105 my ($self, $name) = @_;
106 no strict 'refs';
107 delete ${$self->name . '::'}{$name};
a5e51f0b 108}
6d5355c3 109
c46b802b 110# ... these functions deal with stuff on the namespace level
111
a5e51f0b 112sub has_package_symbol {
113 my ($self, $variable) = @_;
114
115 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
56dcfc1a 116
c20522bd 117 return 0 unless exists $self->namespace->{$name};
d852f4d2 118
119 # FIXME:
120 # For some really stupid reason
121 # a typeglob will have a default
122 # value of \undef in the SCALAR
123 # slot, so we need to work around
124 # this. Which of course means that
125 # if you put \undef in your scalar
126 # then this is broken.
92af7fdf 127
128 if (ref($self->namespace->{$name}) eq 'SCALAR') {
129 return ($type eq 'CODE' ? 1 : 0);
130 }
131 elsif ($type eq 'SCALAR') {
d852f4d2 132 my $val = *{$self->namespace->{$name}}{$type};
92af7fdf 133 return defined(${$val}) ? 1 : 0;
d852f4d2 134 }
135 else {
56dcfc1a 136 defined(*{$self->namespace->{$name}}{$type}) ? 1 : 0;
d852f4d2 137 }
a5e51f0b 138}
139
140sub get_package_symbol {
141 my ($self, $variable) = @_;
142
143 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
144
c20522bd 145 $self->add_package_symbol($variable)
146 unless exists $self->namespace->{$name};
92af7fdf 147
148 if (ref($self->namespace->{$name}) eq 'SCALAR') {
149 if ($type eq 'CODE') {
150 no strict 'refs';
151 return \&{$self->name.'::'.$name};
152 }
153 else {
154 return undef;
155 }
156 }
157 else {
158 return *{$self->namespace->{$name}}{$type};
159 }
a5e51f0b 160}
161
162sub remove_package_symbol {
163 my ($self, $variable) = @_;
164
165 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
166
c46b802b 167 # FIXME:
168 # no doubt this is grossly inefficient and
169 # could be done much easier and faster in XS
170
171 my ($scalar, $array, $hash, $code);
a5e51f0b 172 if ($type eq 'SCALAR') {
c46b802b 173 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
174 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
175 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 176 }
177 elsif ($type eq 'ARRAY') {
c46b802b 178 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
179 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
180 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 181 }
182 elsif ($type eq 'HASH') {
c46b802b 183 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
184 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
185 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 186 }
187 elsif ($type eq 'CODE') {
c46b802b 188 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
189 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
190 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
a5e51f0b 191 }
192 else {
193 confess "This should never ever ever happen";
7f436b8c 194 }
c46b802b 195
196 $self->remove_package_glob($name);
197
198 $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar;
199 $self->add_package_symbol(('@' . $name) => $array) if defined $array;
200 $self->add_package_symbol(('%' . $name) => $hash) if defined $hash;
201 $self->add_package_symbol(('&' . $name) => $code) if defined $code;
9d6dce77 202}
c0cbf4d9 203
9d6dce77 204sub list_all_package_symbols {
92330ee2 205 my ($self, $type_filter) = @_;
206 return keys %{$self->namespace} unless defined $type_filter;
91e0eb4a 207 # NOTE:
92330ee2 208 # or we can filter based on
209 # type (SCALAR|ARRAY|HASH|CODE)
210 my $namespace = $self->namespace;
91e0eb4a 211 return grep {
92af7fdf 212 (ref($namespace->{$_})
213 ? (ref($namespace->{$_}) eq 'SCALAR' && $type_filter eq 'CODE')
214 : (ref(\$namespace->{$_}) eq 'GLOB'
215 && defined(*{$namespace->{$_}}{$type_filter})));
91e0eb4a 216 } keys %{$namespace};
6d5355c3 217}
218
2243a22b 2191;
220
221__END__
222
223=pod
224
225=head1 NAME
226
227Class::MOP::Package - Package Meta Object
228
2243a22b 229=head1 DESCRIPTION
230
127d39a7 231This is an abstraction of a Perl 5 package, it is a superclass of
232L<Class::MOP::Class> and provides all of the symbol table
233introspection methods.
234
2243a22b 235=head1 METHODS
236
237=over 4
238
239=item B<meta>
240
127d39a7 241Returns a metaclass for this package.
242
b9d9fc0b 243=item B<initialize ($package_name)>
6d5355c3 244
127d39a7 245This will initialize a Class::MOP::Package instance which represents
246the package of C<$package_name>.
247
6d5355c3 248=item B<name>
249
b9d9fc0b 250This is a read-only attribute which returns the package name for the
251given instance.
252
a5e51f0b 253=item B<namespace>
254
b9d9fc0b 255This returns a HASH reference to the symbol table. The keys of the
256HASH are the symbol names, and the values are typeglob references.
257
258=item B<add_package_symbol ($variable_name, ?$initial_value)>
259
260Given a C<$variable_name>, which must contain a leading sigil, this
261method will create that variable within the package which houses the
262class. It also takes an optional C<$initial_value>, which must be a
263reference of the same type as the sigil of the C<$variable_name>
264implies.
265
266=item B<get_package_symbol ($variable_name)>
6d5355c3 267
b9d9fc0b 268This will return a reference to the package variable in
269C<$variable_name>.
6d5355c3 270
b9d9fc0b 271=item B<has_package_symbol ($variable_name)>
6d5355c3 272
b9d9fc0b 273Returns true (C<1>) if there is a package variable defined for
274C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 275
b9d9fc0b 276=item B<remove_package_symbol ($variable_name)>
277
278This will attempt to remove the package variable at C<$variable_name>.
279
280=item B<remove_package_glob ($glob_name)>
281
282This will attempt to remove the entire typeglob associated with
283C<$glob_name> from the package.
c46b802b 284
92330ee2 285=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 286
b9d9fc0b 287This will list all the glob names associated with the current package.
288By inspecting the globs returned you can discern all the variables in
289the package.
290
92330ee2 291By passing a C<$type_filter>, you can limit the list to only those
292which match the filter (either SCALAR, ARRAY, HASH or CODE).
293
2243a22b 294=back
295
1a09d9cc 296=head1 AUTHORS
2243a22b 297
298Stevan Little E<lt>stevan@iinteractive.comE<gt>
299
300=head1 COPYRIGHT AND LICENSE
301
69e3ab0a 302Copyright 2006-2008 by Infinity Interactive, Inc.
2243a22b 303
304L<http://www.iinteractive.com>
305
306This library is free software; you can redistribute it and/or modify
307it under the same terms as Perl itself.
308
92af7fdf 309=cut