more misc cleanup
[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
f0480c45 10our $VERSION = '0.02';
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,
32 '%:namespace' => \%{$package_name . '::'},
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
a5e51f0b 42sub name { $_[0]->{'$:package'} }
43sub namespace { $_[0]->{'%:namespace'} }
6d5355c3 44
a5e51f0b 45# utility methods
6d5355c3 46
c0cbf4d9 47{
48 my %SIGIL_MAP = (
49 '$' => 'SCALAR',
50 '@' => 'ARRAY',
51 '%' => 'HASH',
52 '&' => 'CODE',
53 );
6d5355c3 54
a5e51f0b 55 sub _deconstruct_variable_name {
56 my ($self, $variable) = @_;
57
c0cbf4d9 58 (defined $variable)
59 || confess "You must pass a variable name";
a5e51f0b 60
c0cbf4d9 61 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
a5e51f0b 62
c0cbf4d9 63 (defined $sigil)
64 || confess "The variable name must include a sigil";
a5e51f0b 65
c0cbf4d9 66 (exists $SIGIL_MAP{$sigil})
a5e51f0b 67 || confess "I do not recognize that sigil '$sigil'";
68
69 return ($name, $sigil, $SIGIL_MAP{$sigil});
c0cbf4d9 70 }
a5e51f0b 71}
6d5355c3 72
a5e51f0b 73# Class attributes
6d5355c3 74
c46b802b 75# ... these functions have to touch the symbol table itself,.. yuk
76
a5e51f0b 77sub add_package_symbol {
78 my ($self, $variable, $initial_value) = @_;
6d5355c3 79
a5e51f0b 80 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
6d5355c3 81
a5e51f0b 82 no strict 'refs';
c20522bd 83 no warnings 'redefine', 'misc';
c46b802b 84 *{$self->name . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
85}
86
87sub remove_package_glob {
88 my ($self, $name) = @_;
89 no strict 'refs';
90 delete ${$self->name . '::'}{$name};
a5e51f0b 91}
6d5355c3 92
c46b802b 93# ... these functions deal with stuff on the namespace level
94
a5e51f0b 95sub has_package_symbol {
96 my ($self, $variable) = @_;
97
98 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
99
c20522bd 100 return 0 unless exists $self->namespace->{$name};
d852f4d2 101
102 # FIXME:
103 # For some really stupid reason
104 # a typeglob will have a default
105 # value of \undef in the SCALAR
106 # slot, so we need to work around
107 # this. Which of course means that
108 # if you put \undef in your scalar
109 # then this is broken.
110
111 if ($type eq 'SCALAR') {
112 my $val = *{$self->namespace->{$name}}{$type};
113 defined $$val ? 1 : 0;
114 }
115 else {
116 defined *{$self->namespace->{$name}}{$type} ? 1 : 0;
117 }
a5e51f0b 118}
119
120sub get_package_symbol {
121 my ($self, $variable) = @_;
122
123 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
124
c20522bd 125 $self->add_package_symbol($variable)
126 unless exists $self->namespace->{$name};
127 return *{$self->namespace->{$name}}{$type};
a5e51f0b 128}
129
130sub remove_package_symbol {
131 my ($self, $variable) = @_;
132
133 my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable);
134
c46b802b 135 # FIXME:
136 # no doubt this is grossly inefficient and
137 # could be done much easier and faster in XS
138
139 my ($scalar, $array, $hash, $code);
a5e51f0b 140 if ($type eq 'SCALAR') {
c46b802b 141 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
142 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
143 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 144 }
145 elsif ($type eq 'ARRAY') {
c46b802b 146 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
147 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
148 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 149 }
150 elsif ($type eq 'HASH') {
c46b802b 151 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
152 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
153 $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name);
a5e51f0b 154 }
155 elsif ($type eq 'CODE') {
c46b802b 156 $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name);
157 $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name);
158 $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name);
a5e51f0b 159 }
160 else {
161 confess "This should never ever ever happen";
7f436b8c 162 }
c46b802b 163
164 $self->remove_package_glob($name);
165
166 $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar;
167 $self->add_package_symbol(('@' . $name) => $array) if defined $array;
168 $self->add_package_symbol(('%' . $name) => $hash) if defined $hash;
169 $self->add_package_symbol(('&' . $name) => $code) if defined $code;
9d6dce77 170}
c0cbf4d9 171
9d6dce77 172sub list_all_package_symbols {
173 my ($self) = @_;
a5e51f0b 174 return keys %{$self->namespace};
6d5355c3 175}
176
2243a22b 1771;
178
179__END__
180
181=pod
182
183=head1 NAME
184
185Class::MOP::Package - Package Meta Object
186
187=head1 SYNOPSIS
188
189=head1 DESCRIPTION
190
191=head1 METHODS
192
193=over 4
194
195=item B<meta>
196
b9d9fc0b 197=item B<initialize ($package_name)>
6d5355c3 198
199=item B<name>
200
b9d9fc0b 201This is a read-only attribute which returns the package name for the
202given instance.
203
a5e51f0b 204=item B<namespace>
205
b9d9fc0b 206This returns a HASH reference to the symbol table. The keys of the
207HASH are the symbol names, and the values are typeglob references.
208
209=item B<add_package_symbol ($variable_name, ?$initial_value)>
210
211Given a C<$variable_name>, which must contain a leading sigil, this
212method will create that variable within the package which houses the
213class. It also takes an optional C<$initial_value>, which must be a
214reference of the same type as the sigil of the C<$variable_name>
215implies.
216
217=item B<get_package_symbol ($variable_name)>
6d5355c3 218
b9d9fc0b 219This will return a reference to the package variable in
220C<$variable_name>.
6d5355c3 221
b9d9fc0b 222=item B<has_package_symbol ($variable_name)>
6d5355c3 223
b9d9fc0b 224Returns true (C<1>) if there is a package variable defined for
225C<$variable_name>, and false (C<0>) otherwise.
6d5355c3 226
b9d9fc0b 227=item B<remove_package_symbol ($variable_name)>
228
229This will attempt to remove the package variable at C<$variable_name>.
230
231=item B<remove_package_glob ($glob_name)>
232
233This will attempt to remove the entire typeglob associated with
234C<$glob_name> from the package.
c46b802b 235
9d6dce77 236=item B<list_all_package_symbols>
237
b9d9fc0b 238This will list all the glob names associated with the current package.
239By inspecting the globs returned you can discern all the variables in
240the package.
241
2243a22b 242=back
243
1a09d9cc 244=head1 AUTHORS
2243a22b 245
246Stevan Little E<lt>stevan@iinteractive.comE<gt>
247
1a09d9cc 248Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
249
2243a22b 250=head1 COPYRIGHT AND LICENSE
251
252Copyright 2006 by Infinity Interactive, Inc.
253
254L<http://www.iinteractive.com>
255
256This library is free software; you can redistribute it and/or modify
257it under the same terms as Perl itself.
258
259=cut