correct link to Perl6-ObjectSpace
[gitmo/Class-MOP.git] / lib / Class / MOP.pm
index b6dfca4..5fee940 100644 (file)
@@ -9,47 +9,46 @@ use 5.008;
 use MRO::Compat;
 
 use Carp          'confess';
-use Devel::GlobalDestruction qw( in_global_destruction );
-use Scalar::Util  'weaken', 'reftype';
-use Sub::Name qw( subname );
+use Scalar::Util  'weaken', 'reftype', 'blessed';
+use Data::OptList;
+use Try::Tiny;
 
+use Class::MOP::Mixin::AttributeCore;
+use Class::MOP::Mixin::HasAttributes;
+use Class::MOP::Mixin::HasMethods;
 use Class::MOP::Class;
 use Class::MOP::Attribute;
 use Class::MOP::Method;
 
-use Class::MOP::Immutable;
-
 BEGIN {
-    *IS_RUNNING_ON_5_10 = ($] < 5.009_005) 
+    *IS_RUNNING_ON_5_10 = ($] < 5.009_005)
         ? sub () { 0 }
-        : sub () { 1 };    
+        : sub () { 1 };
 
-    *HAVE_ISAREV = defined(&mro::get_isarev)
+    *DEBUG_NO_META = ($ENV{DEBUG_NO_META})
         ? sub () { 1 }
-        : sub () { 1 };
+        : sub () { 0 };
 
     # this is either part of core or set up appropriately by MRO::Compat
     *check_package_cache_flag = \&mro::get_pkg_gen;
 }
 
-our $VERSION   = '0.78';
+our $VERSION   = '1.08';
 our $XS_VERSION = $VERSION;
 $VERSION = eval $VERSION;
-our $AUTHORITY = 'cpan:STEVAN';    
+our $AUTHORITY = 'cpan:STEVAN';
 
 require XSLoader;
 XSLoader::load( __PACKAGE__, $XS_VERSION );
 
-
 {
     # Metaclasses are singletons, so we cache them here.
     # there is no need to worry about destruction though
     # because they should die only when the program dies.
     # After all, do package definitions even get reaped?
+    # Anonymous classes manage their own destruction.
     my %METAS;
 
-    # means of accessing all the metaclasses that have
-    # been initialized thus far (for mugwumps obj browser)
     sub get_all_metaclasses         {        %METAS         }
     sub get_all_metaclass_instances { values %METAS         }
     sub get_all_metaclass_names     { keys   %METAS         }
@@ -57,7 +56,14 @@ XSLoader::load( __PACKAGE__, $XS_VERSION );
     sub store_metaclass_by_name     { $METAS{$_[0]} = $_[1] }
     sub weaken_metaclass            { weaken($METAS{$_[0]}) }
     sub does_metaclass_exist        { exists $METAS{$_[0]} && defined $METAS{$_[0]} }
-    sub remove_metaclass_by_name    { $METAS{$_[0]} = undef }
+    sub remove_metaclass_by_name    { delete $METAS{$_[0]}; return }
+
+    # This handles instances as well as class names
+    sub class_of {
+        return unless defined $_[0];
+        my $class = blessed($_[0]) || $_[0];
+        return $METAS{$class};
+    }
 
     # NOTE:
     # We only cache metaclasses, meaning instances of
@@ -66,62 +72,77 @@ XSLoader::load( __PACKAGE__, $XS_VERSION );
     # because I don't yet see a good reason to do so.
 }
 
+sub _class_to_pmfile {
+    my $class = shift;
+
+    my $file = $class . '.pm';
+    $file =~ s{::}{/}g;
+
+    return $file;
+}
+
 sub load_first_existing_class {
-    my @classes = @_
-        or return;
+    my $classes = Data::OptList::mkopt(\@_)
+      or return;
 
-    foreach my $class (@classes) {
-        unless ( _is_valid_class_name($class) ) {
-            my $display = defined($class) ? $class : 'undef';
+    foreach my $class (@{ $classes }) {
+        my $name = $class->[0];
+        unless ( _is_valid_class_name($name) ) {
+            my $display = defined($name) ? $name : 'undef';
             confess "Invalid class name ($display)";
         }
     }
 
     my $found;
     my %exceptions;
-    for my $class (@classes) {
-        my $e = _try_load_one_class($class);
 
-        if ($e) {
-            $exceptions{$class} = $e;
+    for my $class (@{ $classes }) {
+        my ($name, $options) = @{ $class };
+
+        if ($options) {
+            return $name if is_class_loaded($name, $options);
+            if (is_class_loaded($name)) {
+                # we already know it's loaded and too old, but we call
+                # ->VERSION anyway to generate the exception for us
+                $name->VERSION($options->{-version});
+            }
         }
         else {
-            $found = $class;
-            last;
+            return $name if is_class_loaded($name);
         }
-    }
 
-    return $found if $found;
-
-    confess join(
-        "\n",
-        map {
-            sprintf(
-                "Could not load class (%s) because : %s", $_,
-                $exceptions{$_}
-                )
-            } @classes
-    );
-}
-
-sub _try_load_one_class {
-    my $class = shift;
-
-    return if is_class_loaded($class);
+        my $file = _class_to_pmfile($name);
+        return $name if try {
+            local $SIG{__DIE__};
+            require $file;
+            $name->VERSION($options->{-version})
+                if defined $options->{-version};
+            return 1;
+        }
+        catch {
+            unless (/^Can't locate \Q$file\E in \@INC/) {
+                confess "Couldn't load class ($name) because: $_";
+            }
 
-    my $file = $class . '.pm';
-    $file =~ s{::}{/}g;
+            return;
+        };
+    }
 
-    return do {
-        local $@;
-        eval { require($file) };
-        $@;
-    };
+    if ( @{ $classes } > 1 ) {
+        my @list = map { $_->[0] } @{ $classes };
+        confess "Can't locate any of @list in \@INC (\@INC contains: @INC).";
+    } else {
+        confess "Can't locate " . _class_to_pmfile($classes->[0]->[0]) . " in \@INC (\@INC contains: @INC).";
+    }
 }
 
 sub load_class {
-    my $class = load_first_existing_class($_[0]);
-    return get_metaclass_by_name($class) || $class;
+    load_first_existing_class($_[0], ref $_[1] ? $_[1] : ());
+
+    # This is done to avoid breaking code which checked the return value. Said
+    # code is dumb. The return value was _always_ true, since it dies on
+    # failure!
+    return 1;
 }
 
 sub _is_valid_class_name {
@@ -158,7 +179,76 @@ sub _is_valid_class_name {
 
 # We need to add in the meta-attributes here so that
 # any subclass of Class::MOP::* will be able to
-# inherit them using &construct_instance
+# inherit them using _construct_instance
+
+## --------------------------------------------------------
+## Class::MOP::Mixin::HasMethods
+
+Class::MOP::Mixin::HasMethods->meta->add_attribute(
+    Class::MOP::Attribute->new('_methods' => (
+        reader   => {
+            # NOTE:
+            # we just alias the original method
+            # rather than re-produce it here
+            '_full_method_map' => \&Class::MOP::Mixin::HasMethods::_full_method_map
+        },
+        default => sub { {} }
+    ))
+);
+
+Class::MOP::Mixin::HasMethods->meta->add_attribute(
+    Class::MOP::Attribute->new('method_metaclass' => (
+        reader   => {
+            # NOTE:
+            # we just alias the original method
+            # rather than re-produce it here
+            'method_metaclass' => \&Class::MOP::Mixin::HasMethods::method_metaclass
+        },
+        default  => 'Class::MOP::Method',
+    ))
+);
+
+Class::MOP::Mixin::HasMethods->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::Mixin::HasMethods::wrapped_method_metaclass
+        },
+        default  => 'Class::MOP::Method::Wrapped',
+    ))
+);
+
+## --------------------------------------------------------
+## Class::MOP::Mixin::HasMethods
+
+Class::MOP::Mixin::HasAttributes->meta->add_attribute(
+    Class::MOP::Attribute->new('attributes' => (
+        reader   => {
+            # NOTE: we need to do this in order
+            # for the instance meta-object to
+            # not fall into meta-circular death
+            #
+            # we just alias the original method
+            # rather than re-produce it here
+            '_attribute_map' => \&Class::MOP::Mixin::HasAttributes::_attribute_map
+        },
+        default  => sub { {} }
+    ))
+);
+
+Class::MOP::Mixin::HasAttributes->meta->add_attribute(
+    Class::MOP::Attribute->new('attribute_metaclass' => (
+        reader   => {
+            # NOTE:
+            # we just alias the original method
+            # rather than re-produce it here
+            'attribute_metaclass' => \&Class::MOP::Mixin::HasAttributes::attribute_metaclass
+        },
+        default  => 'Class::MOP::Attribute',
+    ))
+);
 
 ## --------------------------------------------------------
 ## Class::MOP::Package
@@ -239,33 +329,6 @@ Class::MOP::Module->meta->add_attribute(
 ## Class::MOP::Class
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('attributes' => (
-        reader   => {
-            # NOTE: we need to do this in order
-            # for the instance meta-object to
-            # not fall into meta-circular death
-            #
-            # we just alias the original method
-            # rather than re-produce it here
-            'get_attribute_map' => \&Class::MOP::Class::get_attribute_map
-        },
-        default  => sub { {} }
-    ))
-);
-
-Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('methods' => (
-        reader   => {
-            # NOTE:
-            # we just alias the original method
-            # rather than re-produce it here
-            'get_method_map' => \&Class::MOP::Class::get_method_map
-        },
-        default => sub { {} }
-    ))
-);
-
-Class::MOP::Class->meta->add_attribute(
     Class::MOP::Attribute->new('superclasses' => (
         accessor => {
             # NOTE:
@@ -279,53 +342,53 @@ Class::MOP::Class->meta->add_attribute(
 );
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('attribute_metaclass' => (
+    Class::MOP::Attribute->new('instance_metaclass' => (
         reader   => {
-            # NOTE:
+            # NOTE: we need to do this in order
+            # for the instance meta-object to
+            # not fall into meta-circular death
+            #
             # we just alias the original method
             # rather than re-produce it here
-            'attribute_metaclass' => \&Class::MOP::Class::attribute_metaclass
+            'instance_metaclass' => \&Class::MOP::Class::instance_metaclass
         },
-        default  => 'Class::MOP::Attribute',
+        default  => 'Class::MOP::Instance',
     ))
 );
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('method_metaclass' => (
+    Class::MOP::Attribute->new('immutable_trait' => (
         reader   => {
-            # NOTE:
-            # we just alias the original method
-            # rather than re-produce it here
-            'method_metaclass' => \&Class::MOP::Class::method_metaclass
+            'immutable_trait' => \&Class::MOP::Class::immutable_trait
         },
-        default  => 'Class::MOP::Method',
+        default => "Class::MOP::Class::Immutable::Trait",
     ))
 );
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('wrapped_method_metaclass' => (
+    Class::MOP::Attribute->new('constructor_name' => (
         reader   => {
-            # NOTE:
-            # we just alias the original method
-            # rather than re-produce it here
-            'wrapped_method_metaclass' => \&Class::MOP::Class::wrapped_method_metaclass
+            'constructor_name' => \&Class::MOP::Class::constructor_name,
         },
-        default  => 'Class::MOP::Method::Wrapped',
+        default => "new",
     ))
 );
 
 Class::MOP::Class->meta->add_attribute(
-    Class::MOP::Attribute->new('instance_metaclass' => (
+    Class::MOP::Attribute->new('constructor_class' => (
         reader   => {
-            # NOTE: we need to do this in order
-            # for the instance meta-object to
-            # not fall into meta-circular death
-            #
-            # we just alias the original method
-            # rather than re-produce it here
-            'instance_metaclass' => \&Class::MOP::Class::instance_metaclass
+            'constructor_class' => \&Class::MOP::Class::constructor_class,
+        },
+        default => "Class::MOP::Method::Constructor",
+    ))
+);
+
+
+Class::MOP::Class->meta->add_attribute(
+    Class::MOP::Attribute->new('destructor_class' => (
+        reader   => {
+            'destructor_class' => \&Class::MOP::Class::destructor_class,
         },
-        default  => 'Class::MOP::Instance',
     ))
 );
 
@@ -333,12 +396,11 @@ Class::MOP::Class->meta->add_attribute(
 # we don't actually need to tie the knot with
 # Class::MOP::Class here, it is actually handled
 # within Class::MOP::Class itself in the
-# construct_class_instance method.
+# _construct_class_instance method.
 
 ## --------------------------------------------------------
-## Class::MOP::Attribute
-
-Class::MOP::Attribute->meta->add_attribute(
+## Class::MOP::Mixin::AttributeCore
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('name' => (
         reader   => {
             # NOTE: we need to do this in order
@@ -347,91 +409,101 @@ Class::MOP::Attribute->meta->add_attribute(
             #
             # we just alias the original method
             # rather than re-produce it here
-            'name' => \&Class::MOP::Attribute::name
-        }
-    ))
-);
-
-Class::MOP::Attribute->meta->add_attribute(
-    Class::MOP::Attribute->new('associated_class' => (
-        reader   => {
-            # NOTE: we need to do this in order
-            # for the instance meta-object to
-            # not fall into meta-circular death
-            #
-            # we just alias the original method
-            # rather than re-produce it here
-            'associated_class' => \&Class::MOP::Attribute::associated_class
+            'name' => \&Class::MOP::Mixin::AttributeCore::name
         }
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('accessor' => (
-        reader    => { 'accessor'     => \&Class::MOP::Attribute::accessor     },
-        predicate => { 'has_accessor' => \&Class::MOP::Attribute::has_accessor },
+        reader    => { 'accessor'     => \&Class::MOP::Mixin::AttributeCore::accessor     },
+        predicate => { 'has_accessor' => \&Class::MOP::Mixin::AttributeCore::has_accessor },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('reader' => (
-        reader    => { 'reader'     => \&Class::MOP::Attribute::reader     },
-        predicate => { 'has_reader' => \&Class::MOP::Attribute::has_reader },
+        reader    => { 'reader'     => \&Class::MOP::Mixin::AttributeCore::reader     },
+        predicate => { 'has_reader' => \&Class::MOP::Mixin::AttributeCore::has_reader },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('initializer' => (
-        reader    => { 'initializer'     => \&Class::MOP::Attribute::initializer     },
-        predicate => { 'has_initializer' => \&Class::MOP::Attribute::has_initializer },
+        reader    => { 'initializer'     => \&Class::MOP::Mixin::AttributeCore::initializer     },
+        predicate => { 'has_initializer' => \&Class::MOP::Mixin::AttributeCore::has_initializer },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('definition_context' => (
-        reader    => { 'definition_context'     => \&Class::MOP::Attribute::definition_context     },
+        reader    => { 'definition_context'     => \&Class::MOP::Mixin::AttributeCore::definition_context     },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('writer' => (
-        reader    => { 'writer'     => \&Class::MOP::Attribute::writer     },
-        predicate => { 'has_writer' => \&Class::MOP::Attribute::has_writer },
+        reader    => { 'writer'     => \&Class::MOP::Mixin::AttributeCore::writer     },
+        predicate => { 'has_writer' => \&Class::MOP::Mixin::AttributeCore::has_writer },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('predicate' => (
-        reader    => { 'predicate'     => \&Class::MOP::Attribute::predicate     },
-        predicate => { 'has_predicate' => \&Class::MOP::Attribute::has_predicate },
+        reader    => { 'predicate'     => \&Class::MOP::Mixin::AttributeCore::predicate     },
+        predicate => { 'has_predicate' => \&Class::MOP::Mixin::AttributeCore::has_predicate },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('clearer' => (
-        reader    => { 'clearer'     => \&Class::MOP::Attribute::clearer     },
-        predicate => { 'has_clearer' => \&Class::MOP::Attribute::has_clearer },
+        reader    => { 'clearer'     => \&Class::MOP::Mixin::AttributeCore::clearer     },
+        predicate => { 'has_clearer' => \&Class::MOP::Mixin::AttributeCore::has_clearer },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('builder' => (
-        reader    => { 'builder'     => \&Class::MOP::Attribute::builder     },
-        predicate => { 'has_builder' => \&Class::MOP::Attribute::has_builder },
+        reader    => { 'builder'     => \&Class::MOP::Mixin::AttributeCore::builder     },
+        predicate => { 'has_builder' => \&Class::MOP::Mixin::AttributeCore::has_builder },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('init_arg' => (
-        reader    => { 'init_arg'     => \&Class::MOP::Attribute::init_arg     },
-        predicate => { 'has_init_arg' => \&Class::MOP::Attribute::has_init_arg },
+        reader    => { 'init_arg'     => \&Class::MOP::Mixin::AttributeCore::init_arg     },
+        predicate => { 'has_init_arg' => \&Class::MOP::Mixin::AttributeCore::has_init_arg },
     ))
 );
 
-Class::MOP::Attribute->meta->add_attribute(
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
     Class::MOP::Attribute->new('default' => (
         # default has a custom 'reader' method ...
-        predicate => { 'has_default' => \&Class::MOP::Attribute::has_default },
+        predicate => { 'has_default' => \&Class::MOP::Mixin::AttributeCore::has_default },
+    ))
+);
+
+Class::MOP::Mixin::AttributeCore->meta->add_attribute(
+    Class::MOP::Attribute->new('insertion_order' => (
+        reader      => { 'insertion_order' => \&Class::MOP::Mixin::AttributeCore::insertion_order },
+        writer      => { '_set_insertion_order' => \&Class::MOP::Mixin::AttributeCore::_set_insertion_order },
+        predicate   => { 'has_insertion_order' => \&Class::MOP::Mixin::AttributeCore::has_insertion_order },
+    ))
+);
+
+## --------------------------------------------------------
+## Class::MOP::Attribute
+Class::MOP::Attribute->meta->add_attribute(
+    Class::MOP::Attribute->new('associated_class' => (
+        reader   => {
+            # NOTE: we need to do this in order
+            # for the instance meta-object to
+            # not fall into meta-circular death
+            #
+            # we just alias the original method
+            # rather than re-produce it here
+            'associated_class' => \&Class::MOP::Attribute::associated_class
+        }
     ))
 );
 
@@ -480,13 +552,6 @@ Class::MOP::Method->meta->add_attribute(
     ))
 );
 
-Class::MOP::Method->meta->add_method('clone' => sub {
-    my $self  = shift;
-    my $clone = $self->meta->clone_object($self, @_);
-    $clone->_set_original_method($self);
-    return $clone;
-});
-
 ## --------------------------------------------------------
 ## Class::MOP::Method::Wrapped
 
@@ -515,6 +580,16 @@ Class::MOP::Method::Generated->meta->add_attribute(
     ))
 );
 
+
+## --------------------------------------------------------
+## Class::MOP::Method::Inlined
+
+Class::MOP::Method::Inlined->meta->add_attribute(
+    Class::MOP::Attribute->new('_expected_method_class' => (
+        reader   => { '_expected_method_class' => \&Class::MOP::Method::Inlined::_expected_method_class },
+    ))
+);
+
 ## --------------------------------------------------------
 ## Class::MOP::Method::Accessor
 
@@ -593,6 +668,7 @@ Class::MOP::Instance->meta->add_attribute(
     ),
 );
 
+require Class::MOP::Deprecated unless our $no_deprecated;
 
 # we need the meta instance of the meta instance to be created now, in order
 # for the constructor to be able to use it
@@ -608,8 +684,7 @@ undef Class::MOP::Instance->meta->{_package_cache_flag};
 # the compile time of the MOP, and gives us no actual benefits.
 
 $_->meta->make_immutable(
-    inline_constructor  => 1,
-    replace_constructor => 1,
+    inline_constructor  => 0,
     constructor_name    => "_new",
     inline_accessors => 0,
 ) for qw/
@@ -624,12 +699,24 @@ $_->meta->make_immutable(
     Class::MOP::Object
 
     Class::MOP::Method::Generated
+    Class::MOP::Method::Inlined
 
     Class::MOP::Method::Accessor
     Class::MOP::Method::Constructor
     Class::MOP::Method::Wrapped
 /;
 
+$_->meta->make_immutable(
+    inline_constructor  => 0,
+    constructor_name    => undef,
+    inline_accessors => 0,
+) for qw/
+    Class::MOP::Mixin
+    Class::MOP::Mixin::AttributeCore
+    Class::MOP::Mixin::HasAttributes
+    Class::MOP::Mixin::HasMethods
+/;
+
 1;
 
 __END__
@@ -640,7 +727,7 @@ __END__
 
 Class::MOP - A Meta Object Protocol for Perl 5
 
-=head1 DESCRIPTON
+=head1 DESCRIPTION
 
 This module is a fully functioning meta object protocol for the
 Perl 5 object system. It makes no attempt to change the behavior or
@@ -673,9 +760,9 @@ part of how the object system works. The explicit MOP typically
 handles the introspection/reflection features of the object system.
 
 All object systems have implicit MOPs. Without one, they would not
-work. Explict MOPs are much less common, and depending on the language
-can vary from restrictive (Reflection in Java or C#) to wide open
-(CLOS is a perfect example).
+work. Explicit MOPs are much less common, and depending on the
+language can vary from restrictive (Reflection in Java or C#) to wide
+open (CLOS is a perfect example).
 
 =head2 Yet Another Class Builder! Why?
 
@@ -698,7 +785,7 @@ method dispatch.
 =head2 What changes do I have to make to use this module?
 
 This module was designed to be as unintrusive as possible. Many of its
-features are accessible without B<any> change to your existsing
+features are accessible without B<any> change to your existing
 code. It is meant to be a compliment to your existing code and not an
 intrusion on your code base. Unlike many other B<Class::> modules,
 this module B<does not> require you subclass it, or even that you
@@ -712,7 +799,7 @@ in. More information about this feature can be found below.
 
 =head2 About Performance
 
-It is a common misconception that explict MOPs are a performance hit.
+It is a common misconception that explicit MOPs are a performance hit.
 This is not a universal truth, it is a side-effect of some specific
 implementations. For instance, using Java reflection is slow because
 the JVM cannot take advantage of any compiler optimizations, and the
@@ -757,6 +844,18 @@ metaclass compatibility both upwards and downwards.
     |    A    |<----|    B    |
     +---------+     +---------+
 
+In actuality, I<all> of a class's metaclasses must be compatible,
+not just the class metaclass. That includes the instance, attribute,
+and method metaclasses, as well as the constructor and destructor
+classes.
+
+C<Class::MOP> will attempt to fix some simple types of
+incompatibilities. If all the metaclasses for the parent class are
+I<subclasses> of the child's metaclasses then we can simply replace
+the child's metaclasses with the parent's. In addition, if the child
+is missing a metaclass that the parent has, we can also just make the
+child use the parent's metaclass.
+
 As I said this is a highly esoteric topic and one you will only run
 into if you do a lot of subclassing of L<Class::MOP::Class>. If you
 are interested in why this is an issue see the paper I<Uniform and
@@ -766,9 +865,9 @@ this document.
 =head2 Using custom metaclasses
 
 Always use the L<metaclass> pragma when using a custom metaclass, this
-will ensure the proper initialization order and not accidentely create
-an incorrect type of metaclass for you. This is a very rare problem,
-and one which can only occur if you are doing deep metaclass
+will ensure the proper initialization order and not accidentally
+create an incorrect type of metaclass for you. This is a very rare
+problem, and one which can only occur if you are doing deep metaclass
 programming. So in other words, don't worry about it.
 
 Note that if you're using L<Moose> we encourage you to I<not> use
@@ -829,12 +928,7 @@ Note that this module does not export any constants or functions.
 
 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<Class::MOP::HAVE_ISAREV>
-
-Whether or not the L<mro> pragme provides C<get_isarev>, a much faster
-way to get all the subclasses of a certain class.
+compatible.
 
 =back
 
@@ -844,13 +938,24 @@ Note that these are all called as B<functions, not methods>.
 
 =over 4
 
-=item B<Class::MOP::load_class($class_name)>
+=item B<Class::MOP::load_class($class_name, \%options?)>
 
-This will load the specified C<$class_name>. This function can be used
+This will load the specified C<$class_name>, if it is not already
+loaded (as reported by C<is_class_loaded>). This function can be used
 in place of tricks like C<eval "use $module"> or using C<require>
 unconditionally.
 
-=item B<Class::MOP::is_class_loaded($class_name)>
+If the module cannot be loaded, an exception is thrown.
+
+You can pass a hash reference with options as second argument. The
+only option currently recognised is C<-version>, which will ensure
+that the loaded class has at least the required version.
+
+See also L</Class Loading Options>.
+
+For historical reasons, this function explicitly returns a true value.
+
+=item B<Class::MOP::is_class_loaded($class_name, \%options?)>
 
 Returns a boolean indicating whether or not C<$class_name> has been
 loaded.
@@ -858,15 +963,29 @@ loaded.
 This does a basic check of the symbol table to try and determine as
 best it can if the C<$class_name> is loaded, it is probably correct
 about 99% of the time, but it can be fooled into reporting false
-positives.
+positives. In particular, loading any of the core L<IO> modules will
+cause most of the rest of the core L<IO> modules to falsely report
+having been loaded, due to the way the base L<IO> module works.
+
+You can pass a hash reference with options as second argument. The
+only option currently recognised is C<-version>, which will ensure
+that the loaded class has at least the required version.
+
+See also L</Class Loading Options>.
 
 =item B<Class::MOP::get_code_info($code)>
 
 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
+elements of the MOP to determine where a given C<$code> reference is
 from.
 
+=item B<Class::MOP::class_of($instance_or_class_name)>
+
+This will return the metaclass of the given instance or class name.  If the
+class lacks a metaclass, no metaclass will be initialized, and C<undef> will be
+returned.
+
 =item B<Class::MOP::check_package_cache_flag($pkg)>
 
 B<NOTE: DO NOT USE THIS FUNCTION, IT IS FOR INTERNAL USE ONLY!>
@@ -880,6 +999,8 @@ variable which is not package specific.
 
 =item B<Class::MOP::load_first_existing_class(@class_names)>
 
+=item B<Class::MOP::load_first_existing_class($classA, \%optionsA?, $classB, ...)>
+
 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
@@ -888,6 +1009,13 @@ 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.
 
+Additionally, you can pass a hash reference with options after each
+class name. Currently, only C<-version> is recognised and will ensure
+that the loaded class has at least the required version. If the class
+version is not sufficient, an exception will be raised.
+
+See also L</Class Loading Options>.
+
 =back
 
 =head2 Metaclass cache functions
@@ -941,6 +1069,17 @@ This will remove the metaclass stored in the C<$name> key.
 
 =back
 
+=head2 Class Loading Options
+
+=over 4
+
+=item -version
+
+Can be used to pass a minimum required version that will be checked
+against the class version after it was loaded.
+
+=back
+
 =head1 SEE ALSO
 
 =head2 Books
@@ -993,9 +1132,9 @@ L<http://citeseer.ist.psu.edu/37617.html>
 
 =over 4
 
-=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel>
+=item L<http://svn.openfoundry.org/pugs/misc/Perl-MetaModel/>
 
-=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-ObjectSpace>
+=item L<http://github.com/perl6/p5-modules/tree/master/Perl6-ObjectSpace/>
 
 =back
 
@@ -1023,8 +1162,14 @@ creates are very different from this modules.
 =head1 BUGS
 
 All complex software has bugs lurking in it, and this module is no
-exception. If you find a bug please either email me, or add the bug
-to cpan-RT.
+exception.
+
+Please report any bugs to C<bug-class-mop@rt.cpan.org>, or through the
+web interface at L<http://rt.cpan.org>.
+
+You can also discuss feature requests or possible bugs on the Moose
+mailing list (moose@perl.org) or on IRC at
+L<irc://irc.perl.org/#moose>.
 
 =head1 ACKNOWLEDGEMENTS
 
@@ -1048,6 +1193,8 @@ Florian (rafl) Ragwitz
 
 Guillermo (groditi) Roditi
 
+Dave (autarch) Rolsky
+
 Matt (mst) Trout
 
 Rob (robkinyon) Kinyon
@@ -1056,9 +1203,11 @@ Yuval (nothingmuch) Kogman
 
 Scott (konobi) McWhirter
 
+Dylan Hardison
+
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2006-2009 by Infinity Interactive, Inc.
+Copyright 2006-2010 by Infinity Interactive, Inc.
 
 L<http://www.iinteractive.com>