- refactoring attributes
[gitmo/Class-MOP.git] / lib / Class / MOP / Class.pm
CommitLineData
8b978dd5 1
2package Class::MOP::Class;
3
4use strict;
5use warnings;
6
7use Carp 'confess';
0882828e 8use Scalar::Util 'blessed', 'reftype';
8b978dd5 9use Sub::Name 'subname';
10use B 'svref_2object';
11
12our $VERSION = '0.01';
13
2eb717d5 14# Self-introspection
15
16sub meta { $_[0]->initialize($_[0]) }
17
8b978dd5 18# Creation
19
bfe4d0fc 20{
21 # Metaclasses are singletons, so we cache them here.
22 # there is no need to worry about destruction though
23 # because they should die only when the program dies.
24 # After all, do package definitions even get reaped?
25 my %METAS;
26 sub initialize {
27 my ($class, $package_name) = @_;
28 (defined $package_name && $package_name)
727919c5 29 || confess "You must pass a package name";
30 return $METAS{$package_name} if exists $METAS{$package_name};
31 $METAS{$package_name} = $class->construct_class_instance($package_name);
32 }
33
34 # NOTE: (meta-circularity)
35 # this is a special form of &construct_instance
36 # (see below), which is used to construct class
1a7ebbb3 37 # meta-object instances for any Class::MOP::*
38 # class. All other classes will use the more
39 # normal &construct_instance.
727919c5 40 sub construct_class_instance {
41 my ($class, $package_name) = @_;
42 (defined $package_name && $package_name)
1a7ebbb3 43 || confess "You must pass a package name";
44 $class = blessed($class) || $class;
45 if ($class =~ /^Class::MOP::/) {
46 bless {
47 '$:pkg' => $package_name,
48 '%:attrs' => {}
49 } => $class;
50 }
51 else {
52 bless $class->meta->construct_instance(':pkg' => $package_name) => $class
53 }
bfe4d0fc 54 }
8b978dd5 55}
56
57sub create {
58 my ($class, $package_name, $package_version, %options) = @_;
bfe4d0fc 59 (defined $package_name && $package_name)
8b978dd5 60 || confess "You must pass a package name";
61 my $code = "package $package_name;";
62 $code .= "\$$package_name\:\:VERSION = '$package_version';"
63 if defined $package_version;
64 eval $code;
65 confess "creation of $package_name failed : $@" if $@;
bfe4d0fc 66 my $meta = $class->initialize($package_name);
8b978dd5 67 $meta->superclasses(@{$options{superclasses}})
68 if exists $options{superclasses};
2eb717d5 69 # NOTE:
70 # process attributes first, so that they can
71 # install accessors, but locally defined methods
72 # can then overwrite them. It is maybe a little odd, but
73 # I think this should be the order of things.
74 if (exists $options{attributes}) {
cbd9f942 75 foreach my $attr (@{$options{attributes}}) {
76 $meta->add_attribute($attr);
2eb717d5 77 }
78 }
bfe4d0fc 79 if (exists $options{methods}) {
80 foreach my $method_name (keys %{$options{methods}}) {
81 $meta->add_method($method_name, $options{methods}->{$method_name});
82 }
2eb717d5 83 }
8b978dd5 84 return $meta;
85}
86
e16da3e6 87# Instance Construction
88
89sub construct_instance {
cbd9f942 90 my ($class, %params) = @_;
91 my $instance = {};
92 foreach my $attr (map { $_->{attribute} } $class->compute_all_applicable_attributes()) {
93 # if the attr has an init_arg, use that, otherwise,
94 # use the attributes name itself as the init_arg
95 my $init_arg = $attr->has_init_arg() ? $attr->init_arg() : $attr->name;
96 # try to fetch the init arg from the %params ...
97 my $val;
98 $val = $params{$init_arg} if exists $params{$init_arg};
99 # if nothing was in the %params, we can use the
100 # attribute's default value (if it has one)
c50c603e 101 $val ||= $attr->default($instance) if $attr->has_default();
cbd9f942 102 # now add this to the instance structure
103 $instance->{$attr->name} = $val;
104 }
105 return $instance;
e16da3e6 106}
107
8b978dd5 108# Informational
109
e16da3e6 110sub name { $_[0]->{'$:pkg'} }
8b978dd5 111
112sub version {
113 my $self = shift;
114 no strict 'refs';
115 ${$self->name . '::VERSION'};
116}
117
118# Inheritance
119
120sub superclasses {
121 my $self = shift;
122 no strict 'refs';
123 if (@_) {
124 my @supers = @_;
125 @{$self->name . '::ISA'} = @supers;
126 }
127 @{$self->name . '::ISA'};
128}
129
130sub class_precedence_list {
131 my $self = shift;
bfe4d0fc 132 # NOTE:
133 # We need to check for ciruclar inheirtance here.
134 # This will do nothing if all is well, and blow
135 # up otherwise. Yes, it's an ugly hack, better
136 # suggestions are welcome.
137 { $self->name->isa('This is a test for circular inheritance') }
138 # ... and no back to our regularly scheduled program
8b978dd5 139 (
140 $self->name,
141 map {
bfe4d0fc 142 $self->initialize($_)->class_precedence_list()
8b978dd5 143 } $self->superclasses()
144 );
145}
146
0882828e 147## Methods
148
149sub add_method {
150 my ($self, $method_name, $method) = @_;
151 (defined $method_name && $method_name)
152 || confess "You must define a method name";
a5eca695 153 # use reftype here to allow for blessed subs ...
0882828e 154 (reftype($method) && reftype($method) eq 'CODE')
155 || confess "Your code block must be a CODE reference";
156 my $full_method_name = ($self->name . '::' . $method_name);
157
158 no strict 'refs';
c9b8b7f9 159 no warnings 'redefine';
0882828e 160 *{$full_method_name} = subname $full_method_name => $method;
161}
162
bfe4d0fc 163{
164
165 ## private utility functions for has_method
2eb717d5 166 my $_find_subroutine_package_name = sub { eval { svref_2object($_[0])->GV->STASH->NAME } || '' };
167 my $_find_subroutine_name = sub { eval { svref_2object($_[0])->GV->NAME } || '' };
bfe4d0fc 168
169 sub has_method {
c9b8b7f9 170 my ($self, $method_name) = @_;
bfe4d0fc 171 (defined $method_name && $method_name)
172 || confess "You must define a method name";
0882828e 173
bfe4d0fc 174 my $sub_name = ($self->name . '::' . $method_name);
0882828e 175
bfe4d0fc 176 no strict 'refs';
177 return 0 if !defined(&{$sub_name});
178 return 0 if $_find_subroutine_package_name->(\&{$sub_name}) ne $self->name &&
179 $_find_subroutine_name->(\&{$sub_name}) ne '__ANON__';
180 return 1;
181 }
182
0882828e 183}
184
185sub get_method {
c9b8b7f9 186 my ($self, $method_name) = @_;
0882828e 187 (defined $method_name && $method_name)
188 || confess "You must define a method name";
189
190 no strict 'refs';
191 return \&{$self->name . '::' . $method_name}
bfe4d0fc 192 if $self->has_method($method_name);
c9b8b7f9 193 return; # <- make sure to return undef
194}
195
196sub remove_method {
197 my ($self, $method_name) = @_;
198 (defined $method_name && $method_name)
199 || confess "You must define a method name";
200
201 my $removed_method = $self->get_method($method_name);
202
203 no strict 'refs';
204 delete ${$self->name . '::'}{$method_name}
205 if defined $removed_method;
206
207 return $removed_method;
208}
209
210sub get_method_list {
211 my $self = shift;
212 no strict 'refs';
a5eca695 213 grep { $self->has_method($_) } %{$self->name . '::'};
214}
215
216sub compute_all_applicable_methods {
217 my $self = shift;
218 my @methods;
219 # keep a record of what we have seen
220 # here, this will handle all the
221 # inheritence issues because we are
222 # using the &class_precedence_list
223 my (%seen_class, %seen_method);
224 foreach my $class ($self->class_precedence_list()) {
225 next if $seen_class{$class};
226 $seen_class{$class}++;
227 # fetch the meta-class ...
228 my $meta = $self->initialize($class);
229 foreach my $method_name ($meta->get_method_list()) {
230 next if exists $seen_method{$method_name};
231 $seen_method{$method_name}++;
232 push @methods => {
233 name => $method_name,
234 class => $class,
235 code => $meta->get_method($method_name)
236 };
237 }
238 }
239 return @methods;
240}
241
a5eca695 242sub find_all_methods_by_name {
243 my ($self, $method_name) = @_;
244 (defined $method_name && $method_name)
245 || confess "You must define a method name to find";
246 my @methods;
247 # keep a record of what we have seen
248 # here, this will handle all the
249 # inheritence issues because we are
250 # using the &class_precedence_list
251 my %seen_class;
252 foreach my $class ($self->class_precedence_list()) {
253 next if $seen_class{$class};
254 $seen_class{$class}++;
255 # fetch the meta-class ...
256 my $meta = $self->initialize($class);
257 push @methods => {
258 name => $method_name,
259 class => $class,
260 code => $meta->get_method($method_name)
261 } if $meta->has_method($method_name);
262 }
263 return @methods;
264
8b978dd5 265}
266
552e3d24 267## Attributes
268
e16da3e6 269sub add_attribute {
2eb717d5 270 my ($self,$attribute) = @_;
e16da3e6 271 (blessed($attribute) && $attribute->isa('Class::MOP::Attribute'))
272 || confess "Your attribute must be an instance of Class::MOP::Attribute (or a subclass)";
9ec169fe 273 $attribute->attach_to_class($self);
274 $attribute->install_accessors();
2eb717d5 275 $self->{'%:attrs'}->{$attribute->name} = $attribute;
e16da3e6 276}
277
278sub has_attribute {
279 my ($self, $attribute_name) = @_;
280 (defined $attribute_name && $attribute_name)
281 || confess "You must define an attribute name";
282 exists $self->{'%:attrs'}->{$attribute_name} ? 1 : 0;
283}
284
285sub get_attribute {
286 my ($self, $attribute_name) = @_;
287 (defined $attribute_name && $attribute_name)
288 || confess "You must define an attribute name";
289 return $self->{'%:attrs'}->{$attribute_name}
290 if $self->has_attribute($attribute_name);
291}
292
293sub remove_attribute {
294 my ($self, $attribute_name) = @_;
295 (defined $attribute_name && $attribute_name)
296 || confess "You must define an attribute name";
297 my $removed_attribute = $self->{'%:attrs'}->{$attribute_name};
298 delete $self->{'%:attrs'}->{$attribute_name}
9ec169fe 299 if defined $removed_attribute;
300 $removed_attribute->remove_accessors();
301 $removed_attribute->detach_from_class();
e16da3e6 302 return $removed_attribute;
303}
304
305sub get_attribute_list {
306 my $self = shift;
307 keys %{$self->{'%:attrs'}};
308}
309
310sub compute_all_applicable_attributes {
311 my $self = shift;
312 my @attrs;
313 # keep a record of what we have seen
314 # here, this will handle all the
315 # inheritence issues because we are
316 # using the &class_precedence_list
317 my (%seen_class, %seen_attr);
318 foreach my $class ($self->class_precedence_list()) {
319 next if $seen_class{$class};
320 $seen_class{$class}++;
321 # fetch the meta-class ...
322 my $meta = $self->initialize($class);
323 foreach my $attr_name ($meta->get_attribute_list()) {
324 next if exists $seen_attr{$attr_name};
325 $seen_attr{$attr_name}++;
326 push @attrs => {
327 name => $attr_name,
328 class => $class,
329 attribute => $meta->get_attribute($attr_name)
330 };
331 }
332 }
333 return @attrs;
334}
2eb717d5 335
52e8a34c 336# Class attributes
337
338sub add_package_variable {
339 my ($self, $variable, $initial_value) = @_;
340 (defined $variable && $variable =~ /^[\$\@\%]/)
341 || confess "variable name does not have a sigil";
342
343 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
344 if (defined $initial_value) {
345 no strict 'refs';
346 *{$self->name . '::' . $name} = $initial_value;
347 }
348 else {
349 eval $sigil . $self->name . '::' . $name;
350 confess "Could not create package variable ($variable) because : $@" if $@;
351 }
352}
353
354sub has_package_variable {
355 my ($self, $variable) = @_;
356 (defined $variable && $variable =~ /^[\$\@\%]/)
357 || confess "variable name does not have a sigil";
358 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
359 no strict 'refs';
360 defined ${$self->name . '::'}{$name} ? 1 : 0;
361}
362
363sub get_package_variable {
364 my ($self, $variable) = @_;
365 (defined $variable && $variable =~ /^[\$\@\%]/)
366 || confess "variable name does not have a sigil";
367 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
368 no strict 'refs';
369 # try to fetch it first,.. see what happens
370 eval '\\' . $sigil . $self->name . '::' . $name;
371 confess "Could not get the package variable ($variable) because : $@" if $@;
372 # if we didn't die, then we can return it
373 # NOTE:
374 # this is not ideal, better suggestions are welcome
375 eval '\\' . $sigil . $self->name . '::' . $name;
376}
377
378sub remove_package_variable {
379 my ($self, $variable) = @_;
380 (defined $variable && $variable =~ /^[\$\@\%]/)
381 || confess "variable name does not have a sigil";
382 my ($sigil, $name) = ($variable =~ /^(.)(.*)$/);
383 no strict 'refs';
384 delete ${$self->name . '::'}{$name};
385}
386
8b978dd5 3871;
388
389__END__
390
391=pod
392
393=head1 NAME
394
395Class::MOP::Class - Class Meta Object
396
397=head1 SYNOPSIS
398
fe122940 399 # use this for introspection ...
400
401 package Foo;
402 sub meta { Class::MOP::Class->initialize(__PACKAGE__) }
403
404 # elsewhere in the code ...
405
406 # add a method to Foo ...
407 Foo->meta->add_method('bar' => sub { ... })
408
409 # get a list of all the classes searched
410 # the method dispatcher in the correct order
411 Foo->meta->class_precedence_list()
412
413 # remove a method from Foo
414 Foo->meta->remove_method('bar');
415
416 # or use this to actually create classes ...
417
418 Class::MOP::Class->create('Bar' => '0.01' => (
419 superclasses => [ 'Foo' ],
420 attributes => [
421 Class::MOP:::Attribute->new('$bar'),
422 Class::MOP:::Attribute->new('$baz'),
423 ],
424 methods => {
425 calculate_bar => sub { ... },
426 construct_baz => sub { ... }
427 }
428 ));
429
8b978dd5 430=head1 DESCRIPTION
431
fe122940 432This is the largest and currently most complex part of the Perl 5
433meta-object protocol. It controls the introspection and
434manipulation of Perl 5 classes (and it can create them too). The
435best way to understand what this module can do, is to read the
436documentation for each of it's methods.
437
552e3d24 438=head1 METHODS
439
2eb717d5 440=head2 Self Introspection
441
442=over 4
443
444=item B<meta>
445
fe122940 446This will return a B<Class::MOP::Class> instance which is related
447to this class. Thereby allowing B<Class::MOP::Class> to actually
448introspect itself.
449
450As with B<Class::MOP::Attribute>, B<Class::MOP> will actually
451bootstrap this module by installing a number of attribute meta-objects
452into it's metaclass. This will allow this class to reap all the benifits
453of the MOP when subclassing it.
2eb717d5 454
455=back
456
552e3d24 457=head2 Class construction
458
a2e85e6c 459These methods will handle creating B<Class::MOP::Class> objects,
460which can be used to both create new classes, and analyze
461pre-existing classes.
552e3d24 462
463This module will internally store references to all the instances
464you create with these methods, so that they do not need to be
465created any more than nessecary. Basically, they are singletons.
466
467=over 4
468
469=item B<create ($package_name, ?$package_version,
a2e85e6c 470 superclasses =E<gt> ?@superclasses,
471 methods =E<gt> ?%methods,
472 attributes =E<gt> ?%attributes)>
552e3d24 473
a2e85e6c 474This returns a B<Class::MOP::Class> object, bringing the specified
552e3d24 475C<$package_name> into existence and adding any of the
476C<$package_version>, C<@superclasses>, C<%methods> and C<%attributes>
477to it.
478
479=item B<initialize ($package_name)>
480
a2e85e6c 481This initializes and returns returns a B<Class::MOP::Class> object
482for a given a C<$package_name>.
483
484=item B<construct_class_instance ($package_name)>
485
486This will construct an instance of B<Class::MOP::Class>, it is
487here so that we can actually "tie the knot" for B<Class::MOP::Class>
488to use C<construct_instance> once all the bootstrapping is done. This
489method is used internally by C<initialize> and should never be called
490from outside of that method really.
552e3d24 491
492=back
493
a2e85e6c 494=head2 Object instance construction
495
496This method is used to construct an instace structure suitable for
497C<bless>-ing into your package of choice. It works in conjunction
498with the Attribute protocol to collect all applicable attributes.
499
500This method is B<entirely optional>, it is up to you whether you want
501to use it or not.
552e3d24 502
503=over 4
504
cbd9f942 505=item B<construct_instance (%params)>
552e3d24 506
cbd9f942 507This will construct and instance using a HASH ref as storage
552e3d24 508(currently only HASH references are supported). This will collect all
a2e85e6c 509the applicable attributes and layout out the fields in the HASH ref,
510it will then initialize them using either use the corresponding key
511in C<%params> or any default value or initializer found in the
512attribute meta-object.
727919c5 513
552e3d24 514=back
515
516=head2 Informational
517
518=over 4
519
520=item B<name>
521
a2e85e6c 522This is a read-only attribute which returns the package name for the
523given B<Class::MOP::Class> instance.
552e3d24 524
525=item B<version>
526
527This is a read-only attribute which returns the C<$VERSION> of the
a2e85e6c 528package for the given B<Class::MOP::Class> instance.
552e3d24 529
530=back
531
532=head2 Inheritance Relationships
533
534=over 4
535
536=item B<superclasses (?@superclasses)>
537
538This is a read-write attribute which represents the superclass
a2e85e6c 539relationships of the class the B<Class::MOP::Class> instance is
540associated with. Basically, it can get and set the C<@ISA> for you.
552e3d24 541
542=item B<class_precedence_list>
543
a2e85e6c 544This computes the a list of all the class's ancestors in the same order
545in which method dispatch will be done. This is similair to
546what B<Class::ISA::super_path> does, but we don't remove duplicate names.
552e3d24 547
548=back
549
550=head2 Methods
551
552=over 4
553
554=item B<add_method ($method_name, $method)>
555
556This will take a C<$method_name> and CODE reference to that
a2e85e6c 557C<$method> and install it into the class's package.
552e3d24 558
a2e85e6c 559B<NOTE>:
560This does absolutely nothing special to C<$method>
552e3d24 561other than use B<Sub::Name> to make sure it is tagged with the
562correct name, and therefore show up correctly in stack traces and
563such.
564
565=item B<has_method ($method_name)>
566
a2e85e6c 567This just provides a simple way to check if the class implements
552e3d24 568a specific C<$method_name>. It will I<not> however, attempt to check
a2e85e6c 569if the class inherits the method (use C<UNIVERSAL::can> for that).
552e3d24 570
571This will correctly handle functions defined outside of the package
572that use a fully qualified name (C<sub Package::name { ... }>).
573
574This will correctly handle functions renamed with B<Sub::Name> and
575installed using the symbol tables. However, if you are naming the
576subroutine outside of the package scope, you must use the fully
577qualified name, including the package name, for C<has_method> to
578correctly identify it.
579
580This will attempt to correctly ignore functions imported from other
581packages using B<Exporter>. It breaks down if the function imported
582is an C<__ANON__> sub (such as with C<use constant>), which very well
583may be a valid method being applied to the class.
584
585In short, this method cannot always be trusted to determine if the
586C<$method_name> is actually a method. However, it will DWIM about
a2e85e6c 58790% of the time, so it's a small trade off I think.
552e3d24 588
589=item B<get_method ($method_name)>
590
591This will return a CODE reference of the specified C<$method_name>,
592or return undef if that method does not exist.
593
594=item B<remove_method ($method_name)>
595
a2e85e6c 596This will attempt to remove a given C<$method_name> from the class.
552e3d24 597It will return the CODE reference that it has removed, and will
598attempt to use B<Sub::Name> to clear the methods associated name.
599
600=item B<get_method_list>
601
602This will return a list of method names for all I<locally> defined
603methods. It does B<not> provide a list of all applicable methods,
604including any inherited ones. If you want a list of all applicable
605methods, use the C<compute_all_applicable_methods> method.
606
607=item B<compute_all_applicable_methods>
608
a2e85e6c 609This will return a list of all the methods names this class will
610respond to, taking into account inheritance. The list will be a list of
552e3d24 611HASH references, each one containing the following information; method
612name, the name of the class in which the method lives and a CODE
613reference for the actual method.
614
615=item B<find_all_methods_by_name ($method_name)>
616
617This will traverse the inheritence hierarchy and locate all methods
618with a given C<$method_name>. Similar to
619C<compute_all_applicable_methods> it returns a list of HASH references
620with the following information; method name (which will always be the
621same as C<$method_name>), the name of the class in which the method
622lives and a CODE reference for the actual method.
623
624The list of methods produced is a distinct list, meaning there are no
625duplicates in it. This is especially useful for things like object
626initialization and destruction where you only want the method called
627once, and in the correct order.
628
629=back
630
631=head2 Attributes
632
633It should be noted that since there is no one consistent way to define
634the attributes of a class in Perl 5. These methods can only work with
635the information given, and can not easily discover information on
a2e85e6c 636their own. See L<Class::MOP::Attribute> for more details.
552e3d24 637
638=over 4
639
640=item B<add_attribute ($attribute_name, $attribute_meta_object)>
641
a2e85e6c 642This stores a C<$attribute_meta_object> in the B<Class::MOP::Class>
643instance associated with the given class, and associates it with
644the C<$attribute_name>. Unlike methods, attributes within the MOP
645are stored as meta-information only. They will be used later to
646construct instances from (see C<construct_instance> above).
552e3d24 647More details about the attribute meta-objects can be found in the
a2e85e6c 648L<Class::MOP::Attribute> or the L<Class::MOP/The Attribute protocol>
649section.
650
651It should be noted that any accessor, reader/writer or predicate
652methods which the C<$attribute_meta_object> has will be installed
653into the class at this time.
552e3d24 654
655=item B<has_attribute ($attribute_name)>
656
a2e85e6c 657Checks to see if this class has an attribute by the name of
552e3d24 658C<$attribute_name> and returns a boolean.
659
660=item B<get_attribute ($attribute_name)>
661
662Returns the attribute meta-object associated with C<$attribute_name>,
663if none is found, it will return undef.
664
665=item B<remove_attribute ($attribute_name)>
666
667This will remove the attribute meta-object stored at
668C<$attribute_name>, then return the removed attribute meta-object.
669
a2e85e6c 670B<NOTE:>
671Removing an attribute will only affect future instances of
552e3d24 672the class, it will not make any attempt to remove the attribute from
673any existing instances of the class.
674
a2e85e6c 675It should be noted that any accessor, reader/writer or predicate
676methods which the attribute meta-object stored at C<$attribute_name>
677has will be removed from the class at this time. This B<will> make
678these attributes somewhat inaccessable in previously created
679instances. But if you are crazy enough to do this at runtime, then
680you are crazy enough to deal with something like this :).
681
552e3d24 682=item B<get_attribute_list>
683
684This returns a list of attribute names which are defined in the local
685class. If you want a list of all applicable attributes for a class,
686use the C<compute_all_applicable_attributes> method.
687
688=item B<compute_all_applicable_attributes>
689
690This will traverse the inheritance heirachy and return a list of HASH
691references for all the applicable attributes for this class. The HASH
692references will contain the following information; the attribute name,
693the class which the attribute is associated with and the actual
2eb717d5 694attribute meta-object.
552e3d24 695
696=back
697
52e8a34c 698=head2 Package Variables
699
700Since Perl's classes are built atop the Perl package system, it is
701fairly common to use package scoped variables for things like static
702class variables. The following methods are convience methods for
703the creation and inspection of package scoped variables.
704
705=over 4
706
707=item B<add_package_variable ($variable_name, ?$initial_value)>
708
709Given a C<$variable_name>, which must contain a leading sigil, this
710method will create that variable within the package which houses the
711class. It also takes an optional C<$initial_value>, which must be a
712reference of the same type as the sigil of the C<$variable_name>
713implies.
714
715=item B<get_package_variable ($variable_name)>
716
717This will return a reference to the package variable in
718C<$variable_name>.
719
720=item B<has_package_variable ($variable_name)>
721
722Returns true (C<1>) if there is a package variable defined for
723C<$variable_name>, and false (C<0>) otherwise.
724
725=item B<remove_package_variable ($variable_name)>
726
727This will attempt to remove the package variable at C<$variable_name>.
728
729=back
730
8b978dd5 731=head1 AUTHOR
732
a2e85e6c 733Stevan Little E<lt>stevan@iinteractive.comE<gt>
8b978dd5 734
735=head1 COPYRIGHT AND LICENSE
736
737Copyright 2006 by Infinity Interactive, Inc.
738
739L<http://www.iinteractive.com>
740
741This library is free software; you can redistribute it and/or modify
742it under the same terms as Perl itself.
743
744=cut