instance-refactored
[gitmo/Class-MOP.git] / lib / Class / MOP / Class.pm
index c109368..945cf90 100644 (file)
@@ -8,9 +8,10 @@ use Carp         'confess';
 use Scalar::Util 'blessed', 'reftype';
 use Sub::Name    'subname';
 use B            'svref_2object';
-use Clone         ();
 
-our $VERSION = '0.04';
+our $VERSION = '0.14';
+
+use Class::MOP::Instance;
 
 # Self-introspection 
 
@@ -18,20 +19,24 @@ sub meta { Class::MOP::Class->initialize(blessed($_[0]) || $_[0]) }
 
 # Creation
 
-{
+#{
     # 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?
-    my %METAS;    
+    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 }     
     
     sub initialize {
         my $class        = shift;
         my $package_name = shift;
-        (defined $package_name && $package_name)
-            || confess "You must pass a package name";    
-        # make sure the package name is not blessed
-        $package_name = blessed($package_name) || $package_name;
+        (defined $package_name && $package_name && !blessed($package_name))
+            || confess "You must pass a package name and it cannot be blessed";    
         $class->construct_class_instance(':package' => $package_name, @_);
     }
     
@@ -47,7 +52,13 @@ sub meta { Class::MOP::Class->initialize(blessed($_[0]) || $_[0]) }
         my $package_name = $options{':package'};
         (defined $package_name && $package_name)
             || confess "You must pass a package name";  
-        return $METAS{$package_name} if exists $METAS{$package_name};              
+        # NOTE:
+        # return the metaclass if we have it cached, 
+        # and it is still defined (it has not been 
+        # reaped by DESTROY yet, which can happen 
+        # annoyingly enough during global destruction)
+        return $METAS{$package_name} 
+            if exists $METAS{$package_name} && defined $METAS{$package_name};  
         $class = blessed($class) || $class;
         # now create the metaclass
         my $meta;
@@ -56,7 +67,8 @@ sub meta { Class::MOP::Class->initialize(blessed($_[0]) || $_[0]) }
                 '$:package'             => $package_name, 
                 '%:attributes'          => {},
                 '$:attribute_metaclass' => $options{':attribute_metaclass'} || 'Class::MOP::Attribute',
-                '$:method_metaclass'    => $options{':method_metaclass'}    || 'Class::MOP::Method',                
+                '$:method_metaclass'    => $options{':method_metaclass'}    || 'Class::MOP::Method',
+                '$:instance_metaclass'  => $options{':instance_metaclass'}  || 'Class::MOP::Instance',    
             } => $class;
         }
         else {
@@ -81,14 +93,14 @@ sub meta { Class::MOP::Class->initialize(blessed($_[0]) || $_[0]) }
         shift @class_list; # shift off $self->name
 
         foreach my $class_name (@class_list) { 
-            my $meta = $METAS{$class_name};
+            my $meta = $METAS{$class_name} || next;
             ($self->isa(blessed($meta)))
                 || confess $self->name . "->meta => (" . (blessed($self)) . ")" . 
                            " is not compatible with the " . 
                            $class_name . "->meta => (" . (blessed($meta)) . ")";
         }        
     }
-}
+#}
 
 sub create {
     my ($class, $package_name, $package_version, %options) = @_;
@@ -125,6 +137,20 @@ sub create {
     return $meta;
 }
 
+{
+    # NOTE:
+    # this should be sufficient, if you have a 
+    # use case where it is not, write a test and 
+    # I will change it.
+    my $ANON_CLASS_SERIAL = 0;
+    
+    sub create_anon_class {
+        my ($class, %options) = @_;   
+        my $package_name = 'Class::MOP::Class::__ANON__::SERIAL::' . ++$ANON_CLASS_SERIAL;
+        return $class->create($package_name, '0.00', %options);
+    }
+}
+
 ## Attribute readers
 
 # NOTE:
@@ -135,6 +161,7 @@ sub name                { $_[0]->{'$:package'}             }
 sub get_attribute_map   { $_[0]->{'%:attributes'}          }
 sub attribute_metaclass { $_[0]->{'$:attribute_metaclass'} }
 sub method_metaclass    { $_[0]->{'$:method_metaclass'}    }
+sub instance_metaclass  { $_[0]->{'$:instance_metaclass'}  }
 
 # Instance Construction & Cloning
 
@@ -147,25 +174,23 @@ sub new_object {
     # which will deal with the singletons
     return $class->construct_class_instance(@_)
         if $class->name->isa('Class::MOP::Class');
-    bless $class->construct_instance(@_) => $class->name;
+    return $class->construct_instance(@_);
 }
 
 sub construct_instance {
     my ($class, %params) = @_;
-    my $instance = {};
+    my $instance = $class->get_meta_instance->create_instance();
     foreach my $attr ($class->compute_all_applicable_attributes()) {
-        my $init_arg = $attr->init_arg();
-        # try to fetch the init arg from the %params ...
-        my $val;        
-        $val = $params{$init_arg} if exists $params{$init_arg};
-        # if nothing was in the %params, we can use the 
-        # attribute's default value (if it has one)
-        $val ||= $attr->default($instance) if $attr->has_default();            
-        $instance->{$attr->name} = $val;
+        $attr->initialize_instance_slot($instance, \%params);
     }
     return $instance;
 }
 
+sub get_meta_instance {
+    my $class = shift;
+    $class->{':instance_meta_object_cache'} ||= $class->instance_metaclass->new($class);
+}
+
 sub clone_object {
     my $class    = shift;
     my $instance = shift; 
@@ -183,19 +208,7 @@ sub clone_instance {
     my ($class, $instance, %params) = @_;
     (blessed($instance))
         || confess "You can only clone instances, \$self is not a blessed instance";
-    # NOTE:
-    # This will deep clone, which might
-    # not be what you always want. So 
-    # the best thing is to write a more
-    # controled &clone method locally 
-    # in the class (see Class::MOP)
-    my $clone = Clone::clone($instance); 
-    foreach my $attr ($class->compute_all_applicable_attributes()) {
-        my $init_arg = $attr->init_arg();
-        # try to fetch the init arg from the %params ...        
-        $clone->{$attr->name} = $params{$init_arg} 
-            if exists $params{$init_arg};
-    }
+    my $clone = { %$instance, %params }; 
     return $clone;    
 }
 
@@ -206,8 +219,7 @@ sub clone_instance {
 
 sub version {  
     my $self = shift;
-    no strict 'refs';
-    ${$self->name . '::VERSION'};
+    ${$self->get_package_variable('$VERSION')};
 }
 
 # Inheritance
@@ -219,7 +231,7 @@ sub superclasses {
         my @supers = @_;
         @{$self->name . '::ISA'} = @supers;
     }
-    @{$self->name . '::ISA'};        
+    @{$self->name . '::ISA'};
 }
 
 sub class_precedence_list {
@@ -229,12 +241,16 @@ sub class_precedence_list {
     # This will do nothing if all is well, and blow
     # up otherwise. Yes, it's an ugly hack, better 
     # suggestions are welcome.
-    { $self->name->isa('This is a test for circular inheritance') }
-    # ... and no back to our regularly scheduled program
+    { ($self->name || return)->isa('This is a test for circular inheritance') }
+    # ... and now back to our regularly scheduled program
     (
         $self->name, 
         map { 
-            $self->initialize($_)->class_precedence_list()
+            # OPTIMIZATION NOTE:
+            # we grab the metaclass from the %METAS 
+            # hash here to save the initialize() call
+            # if we can, but it is not always possible            
+            ($METAS{$_} || $self->initialize($_))->class_precedence_list()
         } $self->superclasses()
     );   
 }
@@ -246,49 +262,115 @@ sub add_method {
     (defined $method_name && $method_name)
         || confess "You must define a method name";
     # use reftype here to allow for blessed subs ...
-    (reftype($method) && reftype($method) eq 'CODE')
+    ('CODE' eq (reftype($method) || ''))
         || confess "Your code block must be a CODE reference";
     my $full_method_name = ($self->name . '::' . $method_name);    
-        
+
+    $method = $self->method_metaclass->wrap($method) unless blessed($method);
+    
     no strict 'refs';
     no warnings 'redefine';
     *{$full_method_name} = subname $full_method_name => $method;
 }
 
+{
+    my $fetch_and_prepare_method = sub {
+        my ($self, $method_name) = @_;
+        # fetch it locally
+        my $method = $self->get_method($method_name);
+        # if we dont have local ...
+        unless ($method) {
+            # make sure this method even exists ...
+            ($self->find_next_method_by_name($method_name))
+                || confess "The method '$method_name' is not found in the inherience hierarchy for this class";
+            # if so, then create a local which just 
+            # calls the next applicable method ...              
+            $self->add_method($method_name => sub {
+                $self->find_next_method_by_name($method_name)->(@_);
+            });
+            $method = $self->get_method($method_name);
+        }
+        
+        # now make sure we wrap it properly 
+        # (if it isnt already)
+        unless ($method->isa('Class::MOP::Method::Wrapped')) {
+            $method = Class::MOP::Method::Wrapped->wrap($method);
+            $self->add_method($method_name => $method); 
+        }       
+        return $method;
+    };
+
+    sub add_before_method_modifier {
+        my ($self, $method_name, $method_modifier) = @_;
+        (defined $method_name && $method_name)
+            || confess "You must pass in a method name";    
+        my $method = $fetch_and_prepare_method->($self, $method_name);
+        $method->add_before_modifier(subname ':before' => $method_modifier);
+    }
+
+    sub add_after_method_modifier {
+        my ($self, $method_name, $method_modifier) = @_;
+        (defined $method_name && $method_name)
+            || confess "You must pass in a method name";    
+        my $method = $fetch_and_prepare_method->($self, $method_name);
+        $method->add_after_modifier(subname ':after' => $method_modifier);
+    }
+    
+    sub add_around_method_modifier {
+        my ($self, $method_name, $method_modifier) = @_;
+        (defined $method_name && $method_name)
+            || confess "You must pass in a method name";
+        my $method = $fetch_and_prepare_method->($self, $method_name);
+        $method->add_around_modifier(subname ':around' => $method_modifier);
+    }   
+
+    # NOTE: 
+    # the methods above used to be named like this:
+    #    ${pkg}::${method}:(before|after|around)
+    # but this proved problematic when using one modifier
+    # to wrap multiple methods (something which is likely
+    # to happen pretty regularly IMO). So instead of naming
+    # it like this, I have chosen to just name them purely 
+    # with their modifier names, like so:
+    #    :(before|after|around)
+    # The fact is that in a stack trace, it will be fairly 
+    # evident from the context what method they are attached
+    # to, and so don't need the fully qualified name.
+}
+
 sub alias_method {
     my ($self, $method_name, $method) = @_;
     (defined $method_name && $method_name)
         || confess "You must define a method name";
     # use reftype here to allow for blessed subs ...
-    (reftype($method) && reftype($method) eq 'CODE')
+    ('CODE' eq (reftype($method) || ''))
         || confess "Your code block must be a CODE reference";
-    my $full_method_name = ($self->name . '::' . $method_name);    
+    my $full_method_name = ($self->name . '::' . $method_name);
+
+    $method = $self->method_metaclass->wrap($method) unless blessed($method);    
         
     no strict 'refs';
     no warnings 'redefine';
     *{$full_method_name} = $method;
 }
 
-{
-
-    ## private utility functions for has_method
-    my $_find_subroutine_package_name = sub { eval { svref_2object($_[0])->GV->STASH->NAME } || '' };
-    my $_find_subroutine_name         = sub { eval { svref_2object($_[0])->GV->NAME        } || '' };
+sub has_method {
+    my ($self, $method_name) = @_;
+    (defined $method_name && $method_name)
+        || confess "You must define a method name";    
 
-    sub has_method {
-        my ($self, $method_name) = @_;
-        (defined $method_name && $method_name)
-            || confess "You must define a method name";    
+    my $sub_name = ($self->name . '::' . $method_name);   
     
-        my $sub_name = ($self->name . '::' . $method_name);    
-        
-        no strict 'refs';
-        return 0 if !defined(&{$sub_name});        
-        return 0 if $_find_subroutine_package_name->(\&{$sub_name}) ne $self->name &&
-                    $_find_subroutine_name->(\&{$sub_name})         ne '__ANON__';
-        return 1;
-    }
-
+    no strict 'refs';
+    return 0 if !defined(&{$sub_name});        
+    my $method = \&{$sub_name};
+    return 0 if (svref_2object($method)->GV->STASH->NAME || '') ne $self->name &&
+                (svref_2object($method)->GV->NAME || '')        ne '__ANON__';      
+    
+    # at this point we are relatively sure 
+    # it is our method, so we bless/wrap it 
+    $self->method_metaclass->wrap($method) unless blessed($method);
+    return 1;
 }
 
 sub get_method {
@@ -296,10 +378,10 @@ sub get_method {
     (defined $method_name && $method_name)
         || confess "You must define a method name";
 
+    return unless $self->has_method($method_name);
+
     no strict 'refs';    
-    return \&{$self->name . '::' . $method_name} 
-        if $self->has_method($method_name);   
-    return; # <- make sure to return undef
+    return \&{$self->name . '::' . $method_name};
 }
 
 sub remove_method {
@@ -362,7 +444,7 @@ sub find_all_methods_by_name {
         next if $seen_class{$class};
         $seen_class{$class}++;
         # fetch the meta-class ...
-        my $meta = $self->initialize($class);;
+        my $meta = $self->initialize($class);
         push @methods => {
             name  => $method_name, 
             class => $class,
@@ -370,7 +452,28 @@ sub find_all_methods_by_name {
         } if $meta->has_method($method_name);
     }
     return @methods;
+}
 
+sub find_next_method_by_name {
+    my ($self, $method_name) = @_;
+    (defined $method_name && $method_name)
+        || confess "You must define a method name to find"; 
+    # keep a record of what we have seen
+    # here, this will handle all the 
+    # inheritence issues because we are 
+    # using the &class_precedence_list
+    my %seen_class;
+    my @cpl = $self->class_precedence_list();
+    shift @cpl; # discard ourselves
+    foreach my $class (@cpl) {
+        next if $seen_class{$class};
+        $seen_class{$class}++;
+        # fetch the meta-class ...
+        my $meta = $self->initialize($class);
+        return $meta->get_method($method_name) 
+            if $meta->has_method($method_name);
+    }
+    return;
 }
 
 ## Attributes
@@ -384,7 +487,7 @@ sub add_attribute {
     ($attribute->isa('Class::MOP::Attribute'))
         || confess "Your attribute must be an instance of Class::MOP::Attribute (or a subclass)";    
     $attribute->attach_to_class($self);
-    $attribute->install_accessors();        
+    $attribute->install_accessors();
     $self->get_attribute_map->{$attribute->name} = $attribute;
 }
 
@@ -399,8 +502,13 @@ sub get_attribute {
     my ($self, $attribute_name) = @_;
     (defined $attribute_name && $attribute_name)
         || confess "You must define an attribute name";
-    return $self->get_attribute_map->{$attribute_name} 
-        if $self->has_attribute($attribute_name);    
+    # OPTIMIZATION NOTE:
+    # we used to say `if $self->has_attribute($attribute_name)` 
+    # here, but since get_attribute is called so often, we 
+    # eliminate the function call here
+    return $self->{'%:attributes'}->{$attribute_name} 
+        if exists $self->{'%:attributes'}->{$attribute_name};   
+    return; 
 } 
 
 sub remove_attribute {
@@ -408,16 +516,21 @@ sub remove_attribute {
     (defined $attribute_name && $attribute_name)
         || confess "You must define an attribute name";
     my $removed_attribute = $self->get_attribute_map->{$attribute_name};    
-    delete $self->get_attribute_map->{$attribute_name} 
-        if defined $removed_attribute;        
-    $removed_attribute->remove_accessors();        
-    $removed_attribute->detach_from_class();    
+    return unless defined $removed_attribute;
+    delete $self->get_attribute_map->{$attribute_name};        
+    $removed_attribute->remove_accessors(); 
+    $removed_attribute->detach_from_class();
     return $removed_attribute;
 } 
 
 sub get_attribute_list {
     my $self = shift;
-    keys %{$self->get_attribute_map};
+    # OPTIMIZATION NOTE:
+    # We don't use get_attribute_map here because 
+    # we ask for the attribute list quite often 
+    # in compute_all_applicable_attributes, so 
+    # eliminating the function call helps 
+    keys %{$self->{'%:attributes'}};
 } 
 
 sub compute_all_applicable_attributes {
@@ -432,7 +545,10 @@ sub compute_all_applicable_attributes {
         next if $seen_class{$class};
         $seen_class{$class}++;
         # fetch the meta-class ...
-        my $meta = $self->initialize($class);
+        # OPTIMIZATION NOTE:
+        # we grab the metaclass from the %METAS 
+        # hash here to save the initialize() call
+        my $meta = $METAS{$class};
         foreach my $attr_name ($meta->get_attribute_list()) { 
             next if exists $seen_attr{$attr_name};
             $seen_attr{$attr_name}++;
@@ -442,6 +558,24 @@ sub compute_all_applicable_attributes {
     return @attrs;    
 }
 
+sub find_attribute_by_name {
+    my ($self, $attr_name) = @_;
+    # keep a record of what we have seen
+    # here, this will handle all the 
+    # inheritence issues because we are 
+    # using the &class_precedence_list
+    my %seen_class;
+    foreach my $class ($self->class_precedence_list()) {
+        next if $seen_class{$class};
+        $seen_class{$class}++;
+        # fetch the meta-class ...
+        my $meta = $self->initialize($class);
+        return $meta->get_attribute($attr_name)
+            if $meta->has_attribute($attr_name);
+    }
+    return;
+}
+
 # Class attributes
 
 sub add_package_variable {
@@ -455,8 +589,17 @@ sub add_package_variable {
         *{$self->name . '::' . $name} = $initial_value;
     }
     else {
-        eval $sigil . $self->name . '::' . $name;
-        confess "Could not create package variable ($variable) because : $@" if $@;
+        my $e;
+        {        
+            # NOTE:
+            # We HAVE to localize $@ or all 
+            # hell breaks loose. It is not 
+            # good, believe me, not good.
+            local $@;
+            eval $sigil . $self->name . '::' . $name;
+            $e = $@ if $@;            
+        }
+        confess "Could not create package variable ($variable) because : $e" if $e;
     }
 }
 
@@ -474,14 +617,19 @@ sub get_package_variable {
     (defined $variable && $variable =~ /^[\$\@\%]/)
         || confess "variable name does not have a sigil";
     my ($sigil, $name) = ($variable =~ /^(.)(.*)$/); 
-    no strict 'refs';
-    # try to fetch it first,.. see what happens
-    eval '\\' . $sigil . $self->name . '::' . $name;
-    confess "Could not get the package variable ($variable) because : $@" if $@;    
+    my ($ref, $e);
+    {
+        # NOTE:
+        # We HAVE to localize $@ or all 
+        # hell breaks loose. It is not 
+        # good, believe me, not good.
+        local $@;        
+        $ref = eval '\\' . $sigil . $self->name . '::' . $name;
+        $e = $@ if $@;
+    }
+    confess "Could not get the package variable ($variable) because : $e" if $e;    
     # if we didn't die, then we can return it
-    # NOTE:
-    # this is not ideal, better suggestions are welcome
-    eval '\\' . $sigil . $self->name . '::' . $name;   
+    return $ref;
 }
 
 sub remove_package_variable {
@@ -505,6 +653,9 @@ Class::MOP::Class - Class Meta Object
 
 =head1 SYNOPSIS
 
+  # assuming that class Foo 
+  # has been defined, you can
+  
   # use this for introspection ...
   
   # add a method to Foo ...
@@ -556,6 +707,21 @@ bootstrap this module by installing a number of attribute meta-objects
 into it's metaclass. This will allow this class to reap all the benifits 
 of the MOP when subclassing it. 
 
+=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. 
+
+=item B<get_all_metaclass_instances>
+
+This will return an array 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 
+been cached by B<Class::MOP::Class>.
+
 =back
 
 =head2 Class construction
@@ -580,6 +746,14 @@ C<$package_name> into existence and adding any of the
 C<$package_version>, C<@superclasses>, C<%methods> and C<%attributes> 
 to it.
 
+=item B<create_anon_class (superclasses =E<gt> ?@superclasses, 
+                           methods      =E<gt> ?%methods, 
+                           attributes   =E<gt> ?%attributes)>
+
+This will create an anonymous class, it works much like C<create> but 
+it does not need a C<$package_name>. Instead it will create a suitably 
+unique package name for you to stash things into.
+
 =item B<initialize ($package_name)>
 
 This initializes and returns returns a B<Class::MOP::Class> object 
@@ -610,6 +784,10 @@ to use them or not.
 
 =over 4
 
+=item B<instance_metaclass>
+
+=item B<get_meta_instance>
+
 =item B<new_object (%params)>
 
 This is a convience method for creating a new object of the class, and 
@@ -640,8 +818,10 @@ attribute meta-object.
 =item B<clone_object ($instance, %params)>
 
 This is a convience method for cloning an object instance, then  
-blessing it into the appropriate package. Ideally your class 
-would call a C<clone> this method like so:
+blessing it into the appropriate package. This method will call 
+C<clone_instance>, which performs a shallow copy of the object, 
+see that methods documentation for more details. Ideally your 
+class would call a C<clone> this method like so:
 
   sub MyClass::clone {
       my ($self, %param) = @_;
@@ -654,14 +834,20 @@ but that is considered bad style, so we do not do that.
 =item B<clone_instance($instance, %params)>
 
 This method is a compliment of C<construct_instance> (which means if 
-you override C<construct_instance>, you need to override this one too).
+you override C<construct_instance>, you need to override this one too), 
+and clones the instance shallowly.
+
+The cloned structure returned is (like with C<construct_instance>) an 
+unC<bless>ed HASH reference, it is your responsibility to then bless 
+this cloned structure into the right class (which C<clone_object> will
+do for you).
 
-This method will clone the C<$instance> structure created by the 
-C<construct_instance> method, and apply any C<%params> passed to it 
-to change the attribute values. The structure returned is (like with 
-C<construct_instance>) an unC<bless>ed HASH reference, it is your 
-responsibility to then bless this cloned structure into the right 
-class.
+As of 0.11, this method will clone the C<$instance> structure shallowly, 
+as opposed to the deep cloning implemented in prior versions. After much 
+thought, research and discussion, I have decided that anything but basic 
+shallow cloning is outside the scope of the meta-object protocol. I 
+think Yuval "nothingmuch" Kogman put it best when he said that cloning 
+is too I<context-specific> to be part of the MOP.
 
 =back
 
@@ -797,6 +983,110 @@ duplicates in it. This is especially useful for things like object
 initialization and destruction where you only want the method called 
 once, and in the correct order.
 
+=item B<find_next_method_by_name ($method_name)>
+
+This will return the first method to match a given C<$method_name> in 
+the superclasses, this is basically equivalent to calling 
+C<SUPER::$method_name>, but it can be dispatched at runtime.
+
+=back
+
+=head2 Method Modifiers
+
+Method modifiers are a concept borrowed from CLOS, in which a method 
+can be wrapped with I<before>, I<after> and I<around> method modifiers 
+that will be called everytime the method is called. 
+
+=head3 How method modifiers work?
+
+Method modifiers work by wrapping the original method and then replacing 
+it in the classes symbol table. The wrappers will handle calling all the 
+modifiers in the appropariate orders and preserving the calling context 
+for the original method. 
+
+Each method modifier serves a particular purpose, which may not be 
+obvious to users of other method wrapping modules. To start with, the 
+return values of I<before> and I<after> modifiers are ignored. This is 
+because thier purpose is B<not> to filter the input and output of the 
+primary method (this is done with an I<around> modifier). This may seem 
+like an odd restriction to some, but doing this allows for simple code 
+to be added at the begining or end of a method call without jeapordizing 
+the normal functioning of the primary method or placing any extra 
+responsibility on the code of the modifier. Of course if you have more 
+complex needs, then use the I<around> modifier, which uses a variation 
+of continutation passing style to allow for a high degree of flexibility. 
+
+Before and around modifiers are called in last-defined-first-called order, 
+while after modifiers are called in first-defined-first-called order. So 
+the call tree might looks something like this:
+  
+  before 2
+   before 1
+    around 2
+     around 1
+      primary
+     after 1
+    after 2
+
+To see examples of using method modifiers, see the following examples 
+included in the distribution; F<InstanceCountingClass>, F<Perl6Attribute>, 
+F<AttributesWithHistory> and F<C3MethodDispatchOrder>. There is also a 
+classic CLOS usage example in the test F<017_add_method_modifier.t>.
+
+=head3 What is the performance impact?
+
+Of course there is a performance cost associated with method modifiers, 
+but we have made every effort to make that cost be directly proportional 
+to the amount of modifier features you utilize.
+
+The wrapping method does it's best to B<only> do as much work as it 
+absolutely needs to. In order to do this we have moved some of the 
+performance costs to set-up time, where they are easier to amortize.
+
+All this said, my benchmarks have indicated the following:
+
+  simple wrapper with no modifiers             100% slower
+  simple wrapper with simple before modifier   400% slower
+  simple wrapper with simple after modifier    450% slower
+  simple wrapper with simple around modifier   500-550% slower
+  simple wrapper with all 3 modifiers          1100% slower
+
+These numbers may seem daunting, but you must remember, every feature 
+comes with some cost. To put things in perspective, just doing a simple 
+C<AUTOLOAD> which does nothing but extract the name of the method called
+and return it costs about 400% over a normal method call. 
+
+=over 4
+
+=item B<add_before_method_modifier ($method_name, $code)>
+
+This will wrap the method at C<$method_name> and the supplied C<$code> 
+will be passed the C<@_> arguments, and called before the original 
+method is called. As specified above, the return value of the I<before> 
+method modifiers is ignored, and it's ability to modify C<@_> is 
+fairly limited. If you need to do either of these things, use an 
+C<around> method modifier.
+
+=item B<add_after_method_modifier ($method_name, $code)>
+
+This will wrap the method at C<$method_name> so that the original 
+method will be called, it's return values stashed, and then the 
+supplied C<$code> will be passed the C<@_> arguments, and called.
+As specified above, the return value of the I<after> method 
+modifiers is ignored, and it cannot modify the return values of 
+the original method. If you need to do either of these things, use an 
+C<around> method modifier.
+
+=item B<add_around_method_modifier ($method_name, $code)>
+
+This will wrap the method at C<$method_name> so that C<$code> 
+will be called and passed the original method as an extra argument 
+at the begining of the C<@_> argument list. This is a variation of 
+continuation passing style, where the function prepended to C<@_> 
+can be considered a continuation. It is up to C<$code> if it calls 
+the original method or not, there is no restriction on what the 
+C<$code> can or cannot do.
+
 =back
 
 =head2 Attributes
@@ -868,6 +1158,12 @@ HASH reference like C<compute_all_applicable_methods> because all
 that same information is discoverable through the attribute 
 meta-object itself.
 
+=item B<find_attribute_by_name ($attr_name)>
+
+This method will traverse the inheritance heirachy and find the 
+first attribute whose name matches C<$attr_name>, then return it. 
+It will return undef if nothing is found.
+
 =back
 
 =head2 Package Variables
@@ -916,4 +1212,4 @@ L<http://www.iinteractive.com>
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself. 
 
-=cut
\ No newline at end of file
+=cutchistian
\ No newline at end of file