I think this fixed the bleadperl issue
[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
823a5d31 10our $VERSION = '0.06';
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
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})
823a5d31 198 } grep {
199 ref(\$namespace->{$_}) eq 'GLOB'
91e0eb4a 200 } keys %{$namespace};
6d5355c3 201}
202
2243a22b 2031;
204
205__END__
206
207=pod
208
209=head1 NAME
210
211Class::MOP::Package - Package Meta Object
212
213=head1 SYNOPSIS
214
215=head1 DESCRIPTION
216
217=head1 METHODS
218
219=over 4
220
221=item B<meta>
222
b9d9fc0b 223=item B<initialize ($package_name)>
6d5355c3 224
225=item B<name>
226
b9d9fc0b 227This is a read-only attribute which returns the package name for the
228given instance.
229
a5e51f0b 230=item B<namespace>
231
b9d9fc0b 232This returns a HASH reference to the symbol table. The keys of the
233HASH are the symbol names, and the values are typeglob references.
234
235=item B<add_package_symbol ($variable_name, ?$initial_value)>
236
237Given a C<$variable_name>, which must contain a leading sigil, this
238method will create that variable within the package which houses the
239class. It also takes an optional C<$initial_value>, which must be a
240reference of the same type as the sigil of the C<$variable_name>
241implies.
242
243=item B<get_package_symbol ($variable_name)>
6d5355c3 244
b9d9fc0b 245This will return a reference to the package variable in
246C<$variable_name>.
6d5355c3 247
b9d9fc0b 248=item B<has_package_symbol ($variable_name)>
6d5355c3 249
b9d9fc0b 250Returns true (C<1>) if there is a package variable defined for
251C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 252
b9d9fc0b 253=item B<remove_package_symbol ($variable_name)>
254
255This will attempt to remove the package variable at C<$variable_name>.
256
257=item B<remove_package_glob ($glob_name)>
258
259This will attempt to remove the entire typeglob associated with
260C<$glob_name> from the package.
c46b802b 261
92330ee2 262=item B<list_all_package_symbols (?$type_filter)>
9d6dce77 263
b9d9fc0b 264This will list all the glob names associated with the current package.
265By inspecting the globs returned you can discern all the variables in
266the package.
267
92330ee2 268By passing a C<$type_filter>, you can limit the list to only those
269which match the filter (either SCALAR, ARRAY, HASH or CODE).
270
2243a22b 271=back
272
1a09d9cc 273=head1 AUTHORS
2243a22b 274
275Stevan Little E<lt>stevan@iinteractive.comE<gt>
276
1a09d9cc 277Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
278
2243a22b 279=head1 COPYRIGHT AND LICENSE
280
2367814a 281Copyright 2006, 2007 by Infinity Interactive, Inc.
2243a22b 282
283L<http://www.iinteractive.com>
284
285This library is free software; you can redistribute it and/or modify
286it under the same terms as Perl itself.
287
288=cut