make sure to clear the stash when anon classes are removed explicitly
[gitmo/Moose.git] / lib / Class / MOP / Package.pm
index bc5c6ca..079d28a 100644 (file)
@@ -22,8 +22,7 @@ sub initialize {
     my $package_name = delete $options{package};
 
 
-    # we hand-construct the class 
-    # until we can bootstrap it
+    # we hand-construct the class until we can bootstrap it
     if ( my $meta = Class::MOP::get_metaclass_by_name($package_name) ) {
         return $meta;
     } else {
@@ -89,21 +88,26 @@ sub create {
         my $self = shift;
         no warnings 'uninitialized';
         my $prefix = $self->_anon_package_prefix;
-        $self->name =~ /^$prefix/;
+        $self->name =~ /^\Q$prefix/;
     }
 
     sub create_anon {
         my ($class, %options) = @_;
 
         my $cache_ok = delete $options{cache};
+        $options{weaken} = !$cache_ok unless exists $options{weaken};
 
-        my $cache_key = $class->_anon_cache_key(%options);
-
-        if ($cache_ok && defined $ANON_PACKAGE_CACHE{$cache_key}) {
-            return $ANON_PACKAGE_CACHE{$cache_key};
+        my $cache_key;
+        if ($cache_ok) {
+            $cache_key = $class->_anon_cache_key(%options);
+            undef $cache_ok if !defined($cache_key);
         }
 
-        $options{weaken} = !$cache_ok unless exists $options{weaken};
+        if ($cache_ok) {
+            if (defined $ANON_PACKAGE_CACHE{$cache_key}) {
+                return $ANON_PACKAGE_CACHE{$cache_key};
+            }
+        }
 
         my $package_name = $class->_anon_package_prefix . ++$ANON_SERIAL;
 
@@ -136,10 +140,18 @@ sub create {
         # class when fixing metaclass incompatibility. In that case,
         # we don't want to clean out the namespace now. We can detect
         # that because Moose will explicitly update the singleton
-        # cache in Class::MOP.
-        no warnings 'uninitialized';
+        # cache in Class::MOP using store_metaclass_by_name, which
+        # means that the new metaclass will already exist in the cache
+        # by this point.
+        # The other options here are that $current_meta can be undef if
+        # remove_metaclass_by_name is called explicitly (since the hash
+        # entry is removed first, and then this destructor is called),
+        # or that $current_meta can be the same as $self, which happens
+        # when the metaclass goes out of scope (since the weak reference
+        # in the metaclass cache won't be freed until after this
+        # destructor runs).
         my $current_meta = Class::MOP::get_metaclass_by_name($name);
-        return if $current_meta ne $self;
+        return if defined($current_meta) && $current_meta ne $self;
 
         my ($first_fragments, $last_fragment) = ($name =~ /^(.*)::(.*)$/);
 
@@ -182,7 +194,7 @@ sub _new {
 # Attributes
 
 # NOTE:
-# all these attribute readers will be bootstrapped 
+# all these attribute readers will be bootstrapped
 # away in the Class::MOP bootstrap section
 
 sub _package_stash {
@@ -256,13 +268,14 @@ looking at and changing that namespace's symbol table.
 
 =over 4
 
-=item B<< Class::MOP::Package->initialize($package_name) >>
+=item B<< Class::MOP::Package->initialize($package_name, %options) >>
 
 This method creates a new C<Class::MOP::Package> instance which
 represents specified package. If an existing metaclass object exists
-for the package, that will be returned instead.
+for the package, that will be returned instead. No options are valid at the
+package level.
 
-=item B<< Class::MOP::Package->reinitialize($package) >>
+=item B<< Class::MOP::Package->reinitialize($package, %options) >>
 
 This method forcibly removes any existing metaclass for the package
 before calling C<initialize>. In contrast to C<initialize>, you may
@@ -271,6 +284,31 @@ a package name as C<$package>.
 
 Do not call this unless you know what you are doing.
 
+=item B<< Class::MOP::Package->create($package, %options) >>
+
+Creates a new C<Class::MOP::Package> instance which represents the specified
+package, and also does some initialization of that package. Currently, this
+just does the same thing as C<initialize>, but is overridden in subclasses,
+such as C<Class::MOP::Class>.
+
+=item B<< Class::MOP::Package->create_anon(%options) >>
+
+Creates a new anonymous package. Valid keys for C<%options> are:
+
+=over 4
+
+=item C<weaken>
+
+If this is true (the default), the instance stored in C<Class::MOP>'s metaclass
+cache will be weakened, so that the anonymous package will be garbage collected
+when the returned instance goes out of scope.
+
+=back
+
+=item B<< $metapackage->is_anon >>
+
+Returns true if the package is an anonymous package.
+
 =item B<< $metapackage->name >>
 
 This is returns the package's name, as passed to the constructor.