X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP.pm;h=4af79009dab71cc0dbc8c1decd6df50c8228d86b;hb=87715d2e8c8d3998753e6e792ea32be41dd2fafa;hp=c789d06a3c0cf8738ddb7a83a6b710f04a003db6;hpb=f430cfa43be4ce7885da32f8ac5dfe13076cd841;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP.pm b/lib/Class/MOP.pm index c789d06..4af7900 100644 --- a/lib/Class/MOP.pm +++ b/lib/Class/MOP.pm @@ -4,8 +4,10 @@ package Class::MOP; use strict; use warnings; -use Carp 'confess'; -use Scalar::Util 'weaken'; +use MRO::Compat; + +use Carp 'confess'; +use Scalar::Util 'weaken'; use Class::MOP::Class; use Class::MOP::Attribute; @@ -14,15 +16,78 @@ use Class::MOP::Method; use Class::MOP::Immutable; BEGIN { - our $VERSION = '0.49'; + + our $VERSION = '0.65'; our $AUTHORITY = 'cpan:STEVAN'; - use XSLoader; - XSLoader::load( 'Class::MOP', $VERSION ); + *IS_RUNNING_ON_5_10 = ($] < 5.009_005) + ? sub () { 0 } + : sub () { 1 }; + + *HAVE_ISAREV = defined(&mro::get_isarev) + ? sub () { 1 } + : sub () { 1 }; + + # NOTE: + # we may not use this yet, but once + # the get_code_info XS gets merged + # upstream to it, we will always use + # it. But for now it is just kinda + # extra overhead. + # - SL + require Sub::Identify; + + # stash these for a sec, and see how things go + my $_PP_subname = sub { $_[1] }; + my $_PP_get_code_info = \&Sub::Identify::get_code_info; - unless ($] < 5.009_005) { - no warnings 'redefine', 'prototype'; - *check_package_cache_flag = \&mro::get_pkg_gen; + if ($ENV{CLASS_MOP_NO_XS}) { + # NOTE: + # this is if you really want things + # to be slow, then you can force the + # no-XS rule this way, otherwise we + # make an effort to load as much of + # the XS as possible. + # - SL + no warnings 'prototype', 'redefine'; + + # this is either part of core or set up appropriately by MRO::Compat + *check_package_cache_flag = \&mro::get_pkg_gen; + + # our own version of Sub::Name + *subname = $_PP_subname; + # and the Sub::Identify version of the get_code_info + *get_code_info = $_PP_get_code_info; + } + else { + # now try our best to get as much + # of the XS loaded as possible + { + local $@; + eval { + require XSLoader; + XSLoader::load( 'Class::MOP', $VERSION ); + }; + die $@ if $@ && $@ !~ /object version|loadable object/; + + # okay, so the XS failed to load, so + # use the pure perl one instead. + *get_code_info = $_PP_get_code_info if $@; + } + + # get it from MRO::Compat + *check_package_cache_flag = \&mro::get_pkg_gen; + + # now try and load the Sub::Name + # module and use that as a means + # for naming our CVs, if not, we + # use the workaround instead. + if ( eval { require Sub::Name } ) { + *subname = \&Sub::Name::subname; + } + else { + *subname = $_PP_subname; + } } } @@ -53,30 +118,66 @@ BEGIN { sub load_class { my $class = shift; - # see if this is already - # loaded in the symbol table - return 1 if is_class_loaded($class); - # otherwise require it ... - my $file = $class . '.pm'; - $file =~ s{::}{/}g; - eval { CORE::require($file) }; - confess "Could not load class ($class) because : $@" if $@; + + if (ref($class) || !defined($class) || !length($class)) { + my $display = defined($class) ? $class : 'undef'; + confess "Invalid class name ($display)"; + } + + # if the class is not already loaded in the symbol table.. + unless (is_class_loaded($class)) { + # require it + my $file = $class . '.pm'; + $file =~ s{::}{/}g; + eval { CORE::require($file) }; + confess "Could not load class ($class) because : $@" if $@; + } + + # initialize a metaclass if necessary unless (does_metaclass_exist($class)) { eval { Class::MOP::Class->initialize($class) }; confess "Could not initialize class ($class) because : $@" if $@; } - 1; # return true if it worked + + return get_metaclass_by_name($class); } sub is_class_loaded { - my $class = shift; - no strict 'refs'; - return 1 if defined ${"${class}::VERSION"} || defined @{"${class}::ISA"}; - foreach (keys %{"${class}::"}) { - next if substr($_, -2, 2) eq '::'; - return 1 if defined &{"${class}::$_"}; + my $class = shift; + + return 0 if ref($class) || !defined($class) || !length($class); + + # walk the symbol table tree to avoid autovififying + # \*{${main::}{"Foo::"}} == \*main::Foo:: + + my $pack = \*::; + foreach my $part (split('::', $class)) { + return 0 unless exists ${$$pack}{"${part}::"}; + $pack = \*{${$$pack}{"${part}::"}}; + } + + # check for $VERSION or @ISA + return 1 if exists ${$$pack}{VERSION} + && defined *{${$$pack}{VERSION}}{SCALAR}; + return 1 if exists ${$$pack}{ISA} + && defined *{${$$pack}{ISA}}{ARRAY}; + + # check for any method + foreach ( keys %{$$pack} ) { + next if substr($_, -2, 2) eq '::'; + + my $glob = ${$$pack}{$_} || next; + + # constant subs + if ( IS_RUNNING_ON_5_10 ) { + return 1 if ref $glob eq 'SCALAR'; } - return 0; + + return 1 if defined *{$glob}{CODE}; + } + + # fail + return 0; } @@ -108,7 +209,7 @@ sub is_class_loaded { ## Class::MOP::Package Class::MOP::Package->meta->add_attribute( - Class::MOP::Attribute->new('$!package' => ( + Class::MOP::Attribute->new('package' => ( reader => { # NOTE: we need to do this in order # for the instance meta-object to @@ -123,16 +224,14 @@ Class::MOP::Package->meta->add_attribute( ); Class::MOP::Package->meta->add_attribute( - Class::MOP::Attribute->new('%!namespace' => ( + Class::MOP::Attribute->new('namespace' => ( reader => { # NOTE: # we just alias the original method # rather than re-produce it here 'namespace' => \&Class::MOP::Package::namespace }, - # NOTE: - # protect this from silliness - init_arg => '!............( DO NOT DO THIS )............!', + init_arg => undef, default => sub { \undef } )) ); @@ -160,16 +259,14 @@ Class::MOP::Package->meta->add_method('initialize' => sub { # the metaclass, isn't abstraction great :) Class::MOP::Module->meta->add_attribute( - Class::MOP::Attribute->new('$!version' => ( + Class::MOP::Attribute->new('version' => ( reader => { # NOTE: # we just alias the original method # rather than re-produce it here 'version' => \&Class::MOP::Module::version }, - # NOTE: - # protect this from silliness - init_arg => '!............( DO NOT DO THIS )............!', + init_arg => undef, default => sub { \undef } )) ); @@ -181,16 +278,14 @@ Class::MOP::Module->meta->add_attribute( # well. Class::MOP::Module->meta->add_attribute( - Class::MOP::Attribute->new('$!authority' => ( + Class::MOP::Attribute->new('authority' => ( reader => { # NOTE: # we just alias the original method # rather than re-produce it here 'authority' => \&Class::MOP::Module::authority }, - # NOTE: - # protect this from silliness - init_arg => '!............( DO NOT DO THIS )............!', + init_arg => undef, default => sub { \undef } )) ); @@ -199,7 +294,7 @@ Class::MOP::Module->meta->add_attribute( ## Class::MOP::Class Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('%!attributes' => ( + Class::MOP::Attribute->new('attributes' => ( reader => { # NOTE: we need to do this in order # for the instance meta-object to @@ -215,7 +310,7 @@ Class::MOP::Class->meta->add_attribute( ); Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('%!methods' => ( + Class::MOP::Attribute->new('methods' => ( init_arg => 'methods', reader => { # NOTE: @@ -228,22 +323,20 @@ Class::MOP::Class->meta->add_attribute( ); Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('@!superclasses' => ( + Class::MOP::Attribute->new('superclasses' => ( accessor => { # NOTE: # we just alias the original method # rather than re-produce it here 'superclasses' => \&Class::MOP::Class::superclasses }, - # NOTE: - # protect this from silliness - init_arg => '!............( DO NOT DO THIS )............!', + init_arg => undef, default => sub { \undef } )) ); Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('$!attribute_metaclass' => ( + Class::MOP::Attribute->new('attribute_metaclass' => ( reader => { # NOTE: # we just alias the original method @@ -256,7 +349,7 @@ Class::MOP::Class->meta->add_attribute( ); Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('$!method_metaclass' => ( + Class::MOP::Attribute->new('method_metaclass' => ( reader => { # NOTE: # we just alias the original method @@ -269,7 +362,7 @@ Class::MOP::Class->meta->add_attribute( ); Class::MOP::Class->meta->add_attribute( - Class::MOP::Attribute->new('$!instance_metaclass' => ( + Class::MOP::Attribute->new('instance_metaclass' => ( reader => { # NOTE: we need to do this in order # for the instance meta-object to @@ -294,7 +387,7 @@ Class::MOP::Class->meta->add_attribute( ## Class::MOP::Attribute Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!name' => ( + Class::MOP::Attribute->new('name' => ( init_arg => 'name', reader => { # NOTE: we need to do this in order @@ -309,7 +402,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!associated_class' => ( + Class::MOP::Attribute->new('associated_class' => ( init_arg => 'associated_class', reader => { # NOTE: we need to do this in order @@ -324,7 +417,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!accessor' => ( + Class::MOP::Attribute->new('accessor' => ( init_arg => 'accessor', reader => { 'accessor' => \&Class::MOP::Attribute::accessor }, predicate => { 'has_accessor' => \&Class::MOP::Attribute::has_accessor }, @@ -332,7 +425,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!reader' => ( + Class::MOP::Attribute->new('reader' => ( init_arg => 'reader', reader => { 'reader' => \&Class::MOP::Attribute::reader }, predicate => { 'has_reader' => \&Class::MOP::Attribute::has_reader }, @@ -340,7 +433,15 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!writer' => ( + Class::MOP::Attribute->new('initializer' => ( + init_arg => 'initializer', + reader => { 'initializer' => \&Class::MOP::Attribute::initializer }, + predicate => { 'has_initializer' => \&Class::MOP::Attribute::has_initializer }, + )) +); + +Class::MOP::Attribute->meta->add_attribute( + Class::MOP::Attribute->new('writer' => ( init_arg => 'writer', reader => { 'writer' => \&Class::MOP::Attribute::writer }, predicate => { 'has_writer' => \&Class::MOP::Attribute::has_writer }, @@ -348,7 +449,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!predicate' => ( + Class::MOP::Attribute->new('predicate' => ( init_arg => 'predicate', reader => { 'predicate' => \&Class::MOP::Attribute::predicate }, predicate => { 'has_predicate' => \&Class::MOP::Attribute::has_predicate }, @@ -356,7 +457,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!clearer' => ( + Class::MOP::Attribute->new('clearer' => ( init_arg => 'clearer', reader => { 'clearer' => \&Class::MOP::Attribute::clearer }, predicate => { 'has_clearer' => \&Class::MOP::Attribute::has_clearer }, @@ -364,7 +465,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!builder' => ( + Class::MOP::Attribute->new('builder' => ( init_arg => 'builder', reader => { 'builder' => \&Class::MOP::Attribute::builder }, predicate => { 'has_builder' => \&Class::MOP::Attribute::has_builder }, @@ -372,7 +473,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!init_arg' => ( + Class::MOP::Attribute->new('init_arg' => ( init_arg => 'init_arg', reader => { 'init_arg' => \&Class::MOP::Attribute::init_arg }, predicate => { 'has_init_arg' => \&Class::MOP::Attribute::has_init_arg }, @@ -380,7 +481,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('$!default' => ( + Class::MOP::Attribute->new('default' => ( init_arg => 'default', # default has a custom 'reader' method ... predicate => { 'has_default' => \&Class::MOP::Attribute::has_default }, @@ -388,7 +489,7 @@ Class::MOP::Attribute->meta->add_attribute( ); Class::MOP::Attribute->meta->add_attribute( - Class::MOP::Attribute->new('@!associated_methods' => ( + Class::MOP::Attribute->new('associated_methods' => ( init_arg => 'associated_methods', reader => { 'associated_methods' => \&Class::MOP::Attribute::associated_methods }, default => sub { [] } @@ -401,9 +502,12 @@ Class::MOP::Attribute->meta->add_attribute( # so that it uses the attributes meta-objects # to construct itself. Class::MOP::Attribute->meta->add_method('new' => sub { - my $class = shift; - my $name = shift; - my %options = @_; + my ( $class, @args ) = @_; + + unshift @args, "name" if @args % 2 == 1; + my %options = @args; + + my $name = $options{name}; (defined $name && $name) || confess "You must provide a name for the attribute"; @@ -418,11 +522,12 @@ Class::MOP::Attribute->meta->add_method('new' => sub { } else { (Class::MOP::Attribute::is_default_a_coderef(\%options)) || confess("References are not allowed as default values, you must ". - "wrap then in a CODE reference (ex: sub { [] } and not [])") + "wrap the default of '$name' in a CODE reference (ex: sub { [] } and not [])") if exists $options{default} && ref $options{default}; } + # return the new object - $class->meta->new_object(name => $name, %options); + $class->meta->new_object(%options); }); Class::MOP::Attribute->meta->add_method('clone' => sub { @@ -432,14 +537,50 @@ Class::MOP::Attribute->meta->add_method('clone' => sub { ## -------------------------------------------------------- ## Class::MOP::Method - Class::MOP::Method->meta->add_attribute( - Class::MOP::Attribute->new('&!body' => ( + Class::MOP::Attribute->new('body' => ( init_arg => 'body', reader => { 'body' => \&Class::MOP::Method::body }, )) ); +Class::MOP::Method->meta->add_attribute( + Class::MOP::Attribute->new('package_name' => ( + init_arg => 'package_name', + reader => { 'package_name' => \&Class::MOP::Method::package_name }, + )) +); + +Class::MOP::Method->meta->add_attribute( + Class::MOP::Attribute->new('name' => ( + init_arg => 'name', + reader => { 'name' => \&Class::MOP::Method::name }, + )) +); + +Class::MOP::Method->meta->add_method('wrap' => sub { + my ( $class, @args ) = @_; + + unshift @args, 'body' if @args % 2 == 1; + + my %options = @args; + my $code = $options{body}; + + ('CODE' eq ref($code)) + || confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")"; + + ($options{package_name} && $options{name}) + || confess "You must supply the package_name and name parameters"; + + # return the new object + $class->meta->new_object(%options); +}); + +Class::MOP::Method->meta->add_method('clone' => sub { + my $self = shift; + $self->meta->clone_object($self, @_); +}); + ## -------------------------------------------------------- ## Class::MOP::Method::Wrapped @@ -449,24 +590,34 @@ Class::MOP::Method->meta->add_attribute( # practices of attributes, but we put # it here for completeness Class::MOP::Method::Wrapped->meta->add_attribute( - Class::MOP::Attribute->new('%!modifier_table') + Class::MOP::Attribute->new('modifier_table') ); ## -------------------------------------------------------- ## Class::MOP::Method::Generated Class::MOP::Method::Generated->meta->add_attribute( - Class::MOP::Attribute->new('$!is_inline' => ( + Class::MOP::Attribute->new('is_inline' => ( init_arg => 'is_inline', reader => { 'is_inline' => \&Class::MOP::Method::Generated::is_inline }, + default => 0, )) ); +Class::MOP::Method::Generated->meta->add_method('new' => sub { + my ($class, %options) = @_; + ($options{package_name} && $options{name}) + || confess "You must supply the package_name and name parameters"; + my $self = $class->meta->new_object(%options); + $self->initialize_body; + $self; +}); + ## -------------------------------------------------------- ## Class::MOP::Method::Accessor Class::MOP::Method::Accessor->meta->add_attribute( - Class::MOP::Attribute->new('$!attribute' => ( + Class::MOP::Attribute->new('attribute' => ( init_arg => 'attribute', reader => { 'associated_attribute' => \&Class::MOP::Method::Accessor::associated_attribute @@ -475,27 +626,57 @@ Class::MOP::Method::Accessor->meta->add_attribute( ); Class::MOP::Method::Accessor->meta->add_attribute( - Class::MOP::Attribute->new('$!accessor_type' => ( + Class::MOP::Attribute->new('accessor_type' => ( init_arg => 'accessor_type', reader => { 'accessor_type' => \&Class::MOP::Method::Accessor::accessor_type }, )) ); +Class::MOP::Method::Accessor->meta->add_method('new' => sub { + my $class = shift; + my %options = @_; + + (exists $options{attribute}) + || confess "You must supply an attribute to construct with"; + + (exists $options{accessor_type}) + || confess "You must supply an accessor_type to construct with"; + + (Scalar::Util::blessed($options{attribute}) && $options{attribute}->isa('Class::MOP::Attribute')) + || confess "You must supply an attribute which is a 'Class::MOP::Attribute' instance"; + + ($options{package_name} && $options{name}) + || confess "You must supply the package_name and name parameters"; + + # return the new object + my $self = $class->meta->new_object(%options); + + # we don't want this creating + # a cycle in the code, if not + # needed + Scalar::Util::weaken($self->{'attribute'}); + + $self->initialize_body; + + $self; +}); + ## -------------------------------------------------------- ## Class::MOP::Method::Constructor Class::MOP::Method::Constructor->meta->add_attribute( - Class::MOP::Attribute->new('%!options' => ( + Class::MOP::Attribute->new('options' => ( init_arg => 'options', reader => { 'options' => \&Class::MOP::Method::Constructor::options }, + default => sub { +{} } )) ); Class::MOP::Method::Constructor->meta->add_attribute( - Class::MOP::Attribute->new('$!associated_metaclass' => ( + Class::MOP::Attribute->new('associated_metaclass' => ( init_arg => 'metaclass', reader => { 'associated_metaclass' => \&Class::MOP::Method::Constructor::associated_metaclass @@ -503,6 +684,30 @@ Class::MOP::Method::Constructor->meta->add_attribute( )) ); +Class::MOP::Method::Constructor->meta->add_method('new' => sub { + my $class = shift; + my %options = @_; + + (Scalar::Util::blessed $options{metaclass} && $options{metaclass}->isa('Class::MOP::Class')) + || confess "You must pass a metaclass instance if you want to inline" + if $options{is_inline}; + + ($options{package_name} && $options{name}) + || confess "You must supply the package_name and name parameters"; + + # return the new object + my $self = $class->meta->new_object(%options); + + # we don't want this creating + # a cycle in the code, if not + # needed + Scalar::Util::weaken($self->{'associated_metaclass'}); + + $self->initialize_body; + + $self; +}); + ## -------------------------------------------------------- ## Class::MOP::Instance @@ -511,13 +716,40 @@ Class::MOP::Method::Constructor->meta->add_attribute( # included for completeness Class::MOP::Instance->meta->add_attribute( - Class::MOP::Attribute->new('$!meta') + Class::MOP::Attribute->new('associated_metaclass') ); Class::MOP::Instance->meta->add_attribute( - Class::MOP::Attribute->new('@!slots') + Class::MOP::Attribute->new('attributes') ); +Class::MOP::Instance->meta->add_attribute( + Class::MOP::Attribute->new('slots') +); + +Class::MOP::Instance->meta->add_attribute( + Class::MOP::Attribute->new('slot_hash') +); + + +# we need the meta instance of the meta instance to be created now, in order +# for the constructor to be able to use it +Class::MOP::Instance->meta->get_meta_instance; + +Class::MOP::Instance->meta->add_method('new' => sub { + my $class = shift; + my $options = $class->BUILDARGS(@_); + + my $self = $class->meta->new_object(%$options); + + Scalar::Util::weaken($self->{'associated_metaclass'}); + + $self; +}); + +# pretend the add_method never happenned. it hasn't yet affected anything +undef Class::MOP::Instance->meta->{_package_cache_flag}; + ## -------------------------------------------------------- ## Now close all the Class::MOP::* classes @@ -561,7 +793,7 @@ Class::MOP - A Meta Object Protocol for Perl 5 =head1 DESCRIPTON -This module is an attempt to create a meta object protocol for the +This module is a fully functioning meta object protocol for the Perl 5 object system. It makes no attempt to change the behavior or characteristics of the Perl 5 object system, only to create a protocol for its manipulation and introspection. @@ -689,7 +921,7 @@ programming. So in other words, don't worry about it. =head1 PROTOCOLS -The protocol is divided into 3 main sub-protocols: +The protocol is divided into 4 main sub-protocols: =over 4 @@ -705,7 +937,7 @@ See L for more details. This provides a consistent represenation for an attribute of a Perl 5 class. Since there are so many ways to create and handle -atttributes in Perl 5 OO, this attempts to provide as much of a +attributes in Perl 5 OO, this attempts to provide as much of a unified approach as possible, while giving the freedom and flexibility to subclass for specialization. @@ -720,10 +952,37 @@ making it possible to extend the system in many ways. See L for more details. +=item The Instance protocol + +This provides a layer of abstraction for creating object instances. +Since the other layers use this protocol, it is relatively easy to +change the type of your instances from the default HASH ref to other +types of references. Several examples are provided in the F +directory included in this distribution. + +See L for more details. + =back =head1 FUNCTIONS +=head2 Constants + +=over 4 + +=item I + +We set this constant depending on what version perl we are on, this +allows us to take advantage of new 5.10 features and stay backwards +compat. + +=item I + +Whether or not C provides C, a much faster way to get all the +subclasses of a certain class. + +=back + =head2 Utility functions =over 4 @@ -732,6 +991,8 @@ See L for more details. This will load a given C<$class_name> and if it does not have an already initialized metaclass, then it will intialize one for it. +This function can be used in place of tricks like +C or using C. =item B @@ -744,8 +1005,27 @@ is probably correct about 99% of the time. =item B +This will return an integer that is managed by C +to determine if a module's symbol table has been altered. + +In Perl 5.10 or greater, this flag is package specific. However in +versions prior to 5.10, this will use the C variable +which is not package specific. + =item B +This function returns two values, the name of the package the C<$code> +is from and the name of the C<$code> itself. This is used by several +elements of the MOP to detemine where a given C<$code> reference is from. + +=item B + +B + +If possible, we will load the L module and this will function +as C does, otherwise it will just return the C<$code> +argument. + =back =head2 Metaclass cache functions @@ -774,14 +1054,28 @@ been cached by B. =item B +This will return a cached B instance of nothing +if no metaclass exist by that C<$name>. + =item B +This will store a metaclass in the cache at the supplied C<$key>. + =item B +In rare cases it is desireable to store a weakened reference in +the metaclass cache. This function will weaken the reference to +the metaclass stored in C<$name>. + =item B +This will return true of there exists a metaclass stored in the +C<$name> key and return false otherwise. + =item B +This will remove a the metaclass stored in the C<$name> key. + =back =head1 SEE ALSO @@ -899,7 +1193,7 @@ Scott (konobi) McWhirter =head1 COPYRIGHT AND LICENSE -Copyright 2006, 2007 by Infinity Interactive, Inc. +Copyright 2006-2008 by Infinity Interactive, Inc. L