bump version and update Changes for a release
[gitmo/Class-MOP.git] / lib / Class / MOP.pm
index becce3e..fd4afd5 100644 (file)
@@ -9,26 +9,9 @@ use 5.008;
 use MRO::Compat;
 
 use Carp          'confess';
-use Scalar::Util  'weaken';
-
-BEGIN {
-    local $@;
-    eval {
-        require Sub::Name;
-        Sub::Name->import(qw(subname));
-        1
-    } or eval 'sub subname { $_[1] }';
-
-    # this is either part of core or set up appropriately by MRO::Compat
-    *check_package_cache_flag = \&mro::get_pkg_gen;
-
-    eval {
-        require Devel::GlobalDestruction;
-        Devel::GlobalDestruction->import("in_global_destruction");
-        1;
-    } or *in_global_destruction = sub () { !1 };
-}
-
+use Devel::GlobalDestruction qw( in_global_destruction );
+use Scalar::Util  'weaken', 'reftype';
+use Sub::Name qw( subname );
 
 use Class::MOP::Class;
 use Class::MOP::Attribute;
@@ -44,41 +27,18 @@ BEGIN {
     *HAVE_ISAREV = defined(&mro::get_isarev)
         ? sub () { 1 }
         : sub () { 1 };
+
+    # this is either part of core or set up appropriately by MRO::Compat
+    *check_package_cache_flag = \&mro::get_pkg_gen;
 }
 
-our $VERSION   = '0.65';
+our $VERSION   = '0.78';
 our $XS_VERSION = $VERSION;
 $VERSION = eval $VERSION;
 our $AUTHORITY = 'cpan:STEVAN';    
-    
-# after that everything is loaded, if we're allowed try to load faster XS
-# versions of various things
-_try_load_xs() or _load_pure_perl();
 
-sub _try_load_xs {
-    return if $ENV{CLASS_MOP_NO_XS};
-
-    my $e = do {
-        local $@;
-        eval {
-            require XSLoader;
-            # just doing this - no warnings 'redefine' - doesn't work
-            # for some reason
-            local $^W = 0;
-            __PACKAGE__->XSLoader::load($XS_VERSION);
-        };
-        $@;
-    };
-
-    die $e if $e && $e !~ /object version|loadable object/;
-
-    return $e ? 0 : 1;
-}
-
-sub _load_pure_perl {
-    require Sub::Identify;
-    Sub::Identify->import('get_code_info');
-}
+require XSLoader;
+XSLoader::load( __PACKAGE__, $XS_VERSION );
 
 
 {
@@ -106,75 +66,76 @@ sub _load_pure_perl {
     # because I don't yet see a good reason to do so.
 }
 
-sub load_class {
-    my $class = shift;
+sub load_first_existing_class {
+    my @classes = @_
+        or return;
 
-    unless ( _is_valid_class_name($class) ) {
-        my $display = defined($class) ? $class : 'undef';
-        confess "Invalid class name ($display)";
+    foreach my $class (@classes) {
+        unless ( _is_valid_class_name($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 $e = do { local $@; eval "require $class"; $@ };
-        confess "Could not load class ($class) because : $e" if $e;
+    my $found;
+    my %exceptions;
+    for my $class (@classes) {
+        my $e = _try_load_one_class($class);
+
+        if ($e) {
+            $exceptions{$class} = $e;
+        }
+        else {
+            $found = $class;
+            last;
+        }
     }
 
-    get_metaclass_by_name($class) || $class if defined wantarray;
+    return $found if $found;
+
+    confess join(
+        "\n",
+        map {
+            sprintf(
+                "Could not load class (%s) because : %s", $_,
+                $exceptions{$_}
+                )
+            } @classes
+    );
 }
 
-sub _is_valid_class_name {
+sub _try_load_one_class {
     my $class = shift;
 
-    return 0 if ref($class);
-    return 0 unless defined($class);
-    return 0 unless length($class);
+    return if is_class_loaded($class);
 
-    return 1 if $class =~ /^\w+(?:::\w+)*$/;
+    my $file = $class . '.pm';
+    $file =~ s{::}{/}g;
 
-    return 0;
+    return do {
+        local $@;
+        eval { require($file) };
+        $@;
+    };
 }
 
-sub is_class_loaded {
-    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 '::';
+sub load_class {
+    my $class = load_first_existing_class($_[0]);
+    return get_metaclass_by_name($class) || $class;
+}
 
-        my $glob = ${$$pack}{$_} || next;
+sub _is_valid_class_name {
+    my $class = shift;
 
-        # constant subs
-        if ( IS_RUNNING_ON_5_10 ) {
-            return 1 if ref $glob eq 'SCALAR';
-        }
+    return 0 if ref($class);
+    return 0 unless defined($class);
+    return 0 unless length($class);
 
-        return 1 if defined *{$glob}{CODE};
-    }
+    return 1 if $class =~ /^\w+(?:::\w+)*$/;
 
-    # fail
     return 0;
 }
 
-
 ## ----------------------------------------------------------------------------
 ## Setting up our environment ...
 ## ----------------------------------------------------------------------------
@@ -342,6 +303,18 @@ Class::MOP::Class->meta->add_attribute(
 );
 
 Class::MOP::Class->meta->add_attribute(
+    Class::MOP::Attribute->new('wrapped_method_metaclass' => (
+        reader   => {
+            # NOTE:
+            # we just alias the original method
+            # rather than re-produce it here
+            'wrapped_method_metaclass' => \&Class::MOP::Class::wrapped_method_metaclass
+        },
+        default  => 'Class::MOP::Method::Wrapped',
+    ))
+);
+
+Class::MOP::Class->meta->add_attribute(
     Class::MOP::Attribute->new('instance_metaclass' => (
         reader   => {
             # NOTE: we need to do this in order
@@ -415,6 +388,12 @@ Class::MOP::Attribute->meta->add_attribute(
 );
 
 Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('definition_context' => (
+        reader    => { 'definition_context'     => \&Class::MOP::Attribute::definition_context     },
+    ))
+);
+
+Class::MOP::Attribute->meta->add_attribute(
     Class::MOP::Attribute->new('writer' => (
         reader    => { 'writer'     => \&Class::MOP::Attribute::writer     },
         predicate => { 'has_writer' => \&Class::MOP::Attribute::has_writer },
@@ -494,9 +473,18 @@ Class::MOP::Method->meta->add_attribute(
     ))
 );
 
+Class::MOP::Method->meta->add_attribute(
+    Class::MOP::Attribute->new('original_method' => (
+        reader   => { 'original_method'      => \&Class::MOP::Method::original_method },
+        writer   => { '_set_original_method' => \&Class::MOP::Method::_set_original_method },
+    ))
+);
+
 Class::MOP::Method->meta->add_method('clone' => sub {
     my $self  = shift;
-    $self->meta->clone_object($self, @_);
+    my $clone = $self->meta->clone_object($self, @_);
+    $clone->_set_original_method($self);
+    return $clone;
 });
 
 ## --------------------------------------------------------
@@ -521,6 +509,12 @@ Class::MOP::Method::Generated->meta->add_attribute(
     ))
 );
 
+Class::MOP::Method::Generated->meta->add_attribute(
+    Class::MOP::Attribute->new('definition_context' => (
+        reader   => { 'definition_context' => \&Class::MOP::Method::Generated::definition_context },
+    ))
+);
+
 ## --------------------------------------------------------
 ## Class::MOP::Method::Accessor
 
@@ -610,12 +604,8 @@ undef Class::MOP::Instance->meta->{_package_cache_flag};
 ## --------------------------------------------------------
 ## Now close all the Class::MOP::* classes
 
-# NOTE:
-# we don't need to inline the
-# constructors or the accessors
-# this only lengthens the compile
-# time of the MOP, and gives us
-# no actual benefits.
+# NOTE: we don't need to inline the the accessors this only lengthens
+# the compile time of the MOP, and gives us no actual benefits.
 
 $_->meta->make_immutable(
     inline_constructor  => 1,
@@ -900,36 +890,46 @@ destruction.
 
 Otherwise it's a constant returning false.
 
+=item B<load_first_existing_class ($class_name, [$class_name, ...])>
+
+B<NOTE: DO NOT USE THIS FUNCTION, IT IS FOR INTERNAL USE ONLY!>
+
+Given a list of class names, this function will attempt to load each
+one in turn.
+
+If it finds a class it can load, it will return that class' name.
+If none of the classes can be loaded, it will throw an exception.
+
 =back
 
 =head2 Metaclass cache functions
 
-Class::MOP holds a cache of metaclasses, the following are functions
+Class::MOP holds a cache of metaclasses. The following are functions
 (B<not methods>) which can be used to access that cache. It is not
-recommended that you mess with this, bad things could happen. But if
-you are brave and willing to risk it, go for it.
+recommended that you mess with these. Bad things could happen, but if
+you are brave and willing to risk it: go for it!
 
 =over 4
 
 =item B<get_all_metaclasses>
 
-This will return an hash of all the metaclass instances that have
-been cached by B<Class::MOP::Class> keyed by the package name.
+This will return a hash of all the metaclass instances that have
+been cached by B<Class::MOP::Class>, keyed by the package name.
 
 =item B<get_all_metaclass_instances>
 
-This will return an array of all the metaclass instances that have
+This will return a list of all the metaclass instances that have
 been cached by B<Class::MOP::Class>.
 
 =item B<get_all_metaclass_names>
 
-This will return an array of all the metaclass names that have
+This will return a list of all the metaclass names that have
 been cached by B<Class::MOP::Class>.
 
 =item B<get_metaclass_by_name ($name)>
 
-This will return a cached B<Class::MOP::Class> instance of nothing
-if no metaclass exist by that C<$name>.
+This will return a cached B<Class::MOP::Class> instance, or nothing
+if no metaclass exists with that C<$name>.
 
 =item B<store_metaclass_by_name ($name, $meta)>
 
@@ -937,18 +937,19 @@ This will store a metaclass in the cache at the supplied C<$key>.
 
 =item B<weaken_metaclass ($name)>
 
-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>.
+In rare cases (e.g. anonymous metaclasses) it is desirable to
+store a weakened reference in the metaclass cache. This
+function will weaken the reference to the metaclass stored
+in C<$name>.
 
 =item B<does_metaclass_exist ($name)>
 
 This will return true of there exists a metaclass stored in the 
-C<$name> key and return false otherwise.
+C<$name> key, and return false otherwise.
 
 =item B<remove_metaclass_by_name ($name)>
 
-This will remove a the metaclass stored in the C<$name> key.
+This will remove the metaclass stored in the C<$name> key.
 
 =back
 
@@ -1055,6 +1056,8 @@ B<with contributions from:>
 
 Brandon (blblack) Black
 
+Florian (rafl) Ragwitz
+
 Guillermo (groditi) Roditi
 
 Matt (mst) Trout