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