foo
[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
b1897d4d 10our $VERSION = '0.05';
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 {
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 :\
c4260b45 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
a5e51f0b 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
c0cbf4d9 78 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
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
86 return ($name, $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.
127
128 if ($type eq 'SCALAR') {
129 my $val = *{$self->namespace->{$name}}{$type};
56dcfc1a 130 defined(${$val}) ? 1 : 0;
d852f4d2 131 }
132 else {
56dcfc1a 133 defined(*{$self->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
c20522bd 142 $self->add_package_symbol($variable)
143 unless exists $self->namespace->{$name};
144 return *{$self->namespace->{$name}}{$type};
a5e51f0b 145}
146
147sub remove_package_symbol {
148 my ($self, $variable) = @_;
149
150 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
151
c46b802b 152 # FIXME:
153 # no doubt this is grossly inefficient and
154 # could be done much easier and faster in XS
155
156 my ($scalar, $array, $hash, $code);
a5e51f0b 157 if ($type eq 'SCALAR') {
c46b802b 158 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
159 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
160 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 161 }
162 elsif ($type eq 'ARRAY') {
c46b802b 163 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
164 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
165 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 166 }
167 elsif ($type eq 'HASH') {
c46b802b 168 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
169 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
170 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 171 }
172 elsif ($type eq 'CODE') {
c46b802b 173 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
174 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
175 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
a5e51f0b 176 }
177 else {
178 confess "This should never ever ever happen";
7f436b8c 179 }
c46b802b 180
181 $self->remove_package_glob($name);
182
183 $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar;
184 $self->add_package_symbol(('@' . $name) => $array) if defined $array;
185 $self->add_package_symbol(('%' . $name) => $hash) if defined $hash;
186 $self->add_package_symbol(('&' . $name) => $code) if defined $code;
9d6dce77 187}
c0cbf4d9 188
9d6dce77 189sub list_all_package_symbols {
92330ee2 190 my ($self, $type_filter) = @_;
191 return keys %{$self->namespace} unless defined $type_filter;
91e0eb4a 192 # NOTE:
92330ee2 193 # or we can filter based on
194 # type (SCALAR|ARRAY|HASH|CODE)
195 my $namespace = $self->namespace;
91e0eb4a 196 return grep {
197 defined(*{$namespace->{$_}}{$type_filter})
198 } keys %{$namespace};
6d5355c3 199}
200
2243a22b 2011;
202
203__END__
204
205=pod
206
207=head1 NAME
208
209Class::MOP::Package - Package Meta Object
210
211=head1 SYNOPSIS
212
213=head1 DESCRIPTION
214
215=head1 METHODS
216
217=over 4
218
219=item B<meta>
220
b9d9fc0b 221=item B<initialize ($package_name)>
6d5355c3 222
223=item B<name>
224
b9d9fc0b 225This is a read-only attribute which returns the package name for the
226given instance.
227
a5e51f0b 228=item B<namespace>
229
b9d9fc0b 230This returns a HASH reference to the symbol table. The keys of the
231HASH are the symbol names, and the values are typeglob references.
232
233=item B<add_package_symbol ($variable_name, ?$initial_value)>
234
235Given a C<$variable_name>, which must contain a leading sigil, this
236method will create that variable within the package which houses the
237class. It also takes an optional C<$initial_value>, which must be a
238reference of the same type as the sigil of the C<$variable_name>
239implies.
240
241=item B<get_package_symbol ($variable_name)>
6d5355c3 242
b9d9fc0b 243This will return a reference to the package variable in
244C<$variable_name>.
6d5355c3 245
b9d9fc0b 246=item B<has_package_symbol ($variable_name)>
6d5355c3 247
b9d9fc0b 248Returns true (C<1>) if there is a package variable defined for
249C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 250
b9d9fc0b 251=item B<remove_package_symbol ($variable_name)>
252
253This will attempt to remove the package variable at C<$variable_name>.
254
255=item B<remove_package_glob ($glob_name)>
256
257This will attempt to remove the entire typeglob associated with
258C<$glob_name> from the package.
c46b802b 259
92330ee2 260=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 261
b9d9fc0b 262This will list all the glob names associated with the current package.
263By inspecting the globs returned you can discern all the variables in
264the package.
265
92330ee2 266By passing a C<$type_filter>, you can limit the list to only those
267which match the filter (either SCALAR, ARRAY, HASH or CODE).
268
2243a22b 269=back
270
1a09d9cc 271=head1 AUTHORS
2243a22b 272
273Stevan Little E<lt>stevan@iinteractive.comE<gt>
274
1a09d9cc 275Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
276
2243a22b 277=head1 COPYRIGHT AND LICENSE
278
279Copyright 2006 by Infinity Interactive, Inc.
280
281L<http://www.iinteractive.com>
282
283This library is free software; you can redistribute it and/or modify
284it under the same terms as Perl itself.
285
286=cut