adding in the linearized_isa method
Stevan Little [Fri, 23 Nov 2007 17:27:43 +0000 (17:27 +0000)]
Changes
lib/Class/MOP.pm
lib/Class/MOP/Attribute.pm
lib/Class/MOP/Class.pm
lib/Class/MOP/Method/Wrapped.pm
t/002_class_precedence_list.t
t/010_self_introspection.t

diff --git a/Changes b/Changes
index 2194653..96398c9 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,11 @@
 Revision history for Perl extension Class-MOP.
 
+0.46
+    * Class::MOP::Class
+      - added the linearized_isa method instead of constantly 
+        pruning duplicate classes (this will be even more 
+        useful in the 5.10-compat version coming soon)
+
 0.45 Thurs. Nov. 13, 2007
     * Class::MOP::Attribute
       - Fix error message on confess (groditi)
index 938a96d..7d60774 100644 (file)
@@ -13,7 +13,7 @@ use Class::MOP::Method;
 
 use Class::MOP::Immutable;
 
-our $VERSION   = '0.45';
+our $VERSION   = '0.46';
 our $AUTHORITY = 'cpan:STEVAN';
 
 {
index 111b9b6..3da3d96 100644 (file)
@@ -90,12 +90,15 @@ sub initialize_instance_slot {
     # attribute's default value (if it has one)
     if(exists $params->{$init_arg}){
         $meta_instance->set_slot_value($instance, $self->name, $params->{$init_arg});
-    } elsif (defined $self->{'$!default'}) {
+    } 
+    elsif (defined $self->{'$!default'}) {
         $meta_instance->set_slot_value($instance, $self->name, $self->default($instance));
-    } elsif (defined( my $builder = $self->{'$!builder'})) {
-        if($builder = $instance->can($builder) ){
+    } 
+    elsif (defined( my $builder = $self->{'$!builder'})) {
+        if ($builder = $instance->can($builder)) {
             $meta_instance->set_slot_value($instance, $self->name, $instance->$builder);
-        } else {
+        } 
+        else {
             confess(blessed($instance)." does not support builder method '". $self->{'$!builder'} ."' for attribute '" . $self->name . "'");
         }
     }
index e3b70d1..1dc8e24 100644 (file)
@@ -13,7 +13,7 @@ use Scalar::Util 'blessed', 'reftype', 'weaken';
 use Sub::Name    'subname';
 use B            'svref_2object';
 
-our $VERSION   = '0.23';
+our $VERSION   = '0.24';
 our $AUTHORITY = 'cpan:STEVAN';
 
 use base 'Class::MOP::Module';
@@ -134,7 +134,7 @@ sub check_metaclass_compatability {
     return if blessed($self)            eq 'Class::MOP::Class'   &&
               $self->instance_metaclass eq 'Class::MOP::Instance';
 
-    my @class_list = $self->class_precedence_list;
+    my @class_list = $self->linearized_isa;
     shift @class_list; # shift off $self->name
 
     foreach my $class_name (@class_list) {
@@ -386,6 +386,11 @@ sub superclasses {
     @{$self->get_package_symbol('@ISA')};
 }
 
+sub linearized_isa {
+    my %seen;
+    grep { !($seen{$_}++) } (shift)->class_precedence_list
+}
+
 sub class_precedence_list {
     my $self = shift;
     # NOTE:
@@ -549,15 +554,7 @@ sub find_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();
-    foreach my $class (@cpl) {
-        next if $seen_class{$class};
-        $seen_class{$class}++;
+    foreach my $class ($self->linearized_isa) {
         # fetch the meta-class ...
         my $meta = $self->initialize($class);
         return $meta->get_method($method_name)
@@ -568,15 +565,8 @@ sub find_method_by_name {
 
 sub compute_all_applicable_methods {
     my $self = shift;
-    my @methods;
-    # 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, %seen_method);
-    foreach my $class ($self->class_precedence_list()) {
-        next if $seen_class{$class};
-        $seen_class{$class}++;
+    my (@methods, %seen_method);
+    foreach my $class ($self->linearized_isa) {
         # fetch the meta-class ...
         my $meta = $self->initialize($class);
         foreach my $method_name ($meta->get_method_list()) {
@@ -597,14 +587,7 @@ sub find_all_methods_by_name {
     (defined $method_name && $method_name)
         || confess "You must define a method name to find";
     my @methods;
-    # 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}++;
+    foreach my $class ($self->linearized_isa) {
         # fetch the meta-class ...
         my $meta = $self->initialize($class);
         push @methods => {
@@ -620,16 +603,9 @@ 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();
+    my @cpl = $self->linearized_isa;
     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)
@@ -703,15 +679,8 @@ sub get_attribute_list {
 
 sub compute_all_applicable_attributes {
     my $self = shift;
-    my @attrs;
-    # 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, %seen_attr);
-    foreach my $class ($self->class_precedence_list()) {
-        next if $seen_class{$class};
-        $seen_class{$class}++;
+    my (@attrs, %seen_attr);
+    foreach my $class ($self->linearized_isa) {
         # fetch the meta-class ...
         my $meta = $self->initialize($class);
         foreach my $attr_name ($meta->get_attribute_list()) {
@@ -725,14 +694,7 @@ sub compute_all_applicable_attributes {
 
 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}++;
+    foreach my $class ($self->linearized_isa) {
         # fetch the meta-class ...
         my $meta = $self->initialize($class);
         return $meta->get_attribute($attr_name)
@@ -810,6 +772,7 @@ sub create_immutable_transformer {
        /],
        memoize     => {
            class_precedence_list             => 'ARRAY',
+           linearized_isa                    => 'ARRAY',
            compute_all_applicable_attributes => 'ARRAY',
            get_meta_instance                 => 'SCALAR',
            get_method_map                    => 'SCALAR',
@@ -1075,6 +1038,11 @@ This computes the a list of all the class's ancestors in the same order
 in which method dispatch will be done. This is similair to
 what B<Class::ISA::super_path> does, but we don't remove duplicate names.
 
+=item B<linearized_isa>
+
+This returns a list based on C<class_precedence_list> but with all 
+duplicates removed.
+
 =back
 
 =head2 Methods
index 4c84ae5..3c02017 100644 (file)
@@ -11,10 +11,10 @@ use Sub::Name    'subname';
 our $VERSION   = '0.02';
 our $AUTHORITY = 'cpan:STEVAN';
 
-use base 'Class::MOP::Method'; 
+use base 'Class::MOP::Method';
 
 # NOTE:
-# this ugly beast is the result of trying 
+# this ugly beast is the result of trying
 # to micro optimize this as much as possible
 # while not completely loosing maintainability.
 # At this point it's "fast enough", after all
@@ -23,45 +23,45 @@ my $_build_wrapped_method = sub {
        my $modifier_table = shift;
        my ($before, $after, $around) = (
                $modifier_table->{before},
-               $modifier_table->{after},               
-               $modifier_table->{around},              
+               $modifier_table->{after},
+               $modifier_table->{around},
        );
        if (@$before && @$after) {
                $modifier_table->{cache} = sub {
                        $_->(@_) for @{$before};
                        my @rval;
                        ((defined wantarray) ?
-                               ((wantarray) ? 
-                                       (@rval = $around->{cache}->(@_)) 
-                                       : 
+                               ((wantarray) ?
+                                       (@rval = $around->{cache}->(@_))
+                                       :
                                        ($rval[0] = $around->{cache}->(@_)))
                                :
                                $around->{cache}->(@_));
-                       $_->(@_) for @{$after};                 
+                       $_->(@_) for @{$after};
                        return unless defined wantarray;
                        return wantarray ? @rval : $rval[0];
-               }               
+               }
        }
        elsif (@$before && !@$after) {
                $modifier_table->{cache} = sub {
                        $_->(@_) for @{$before};
                        return $around->{cache}->(@_);
-               }               
+               }
        }
        elsif (@$after && !@$before) {
                $modifier_table->{cache} = sub {
                        my @rval;
                        ((defined wantarray) ?
-                               ((wantarray) ? 
-                                       (@rval = $around->{cache}->(@_)) 
-                                       : 
+                               ((wantarray) ?
+                                       (@rval = $around->{cache}->(@_))
+                                       :
                                        ($rval[0] = $around->{cache}->(@_)))
                                :
                                $around->{cache}->(@_));
-                       $_->(@_) for @{$after};                 
+                       $_->(@_) for @{$after};
                        return unless defined wantarray;
                        return wantarray ? @rval : $rval[0];
-               }               
+               }
        }
        else {
                $modifier_table->{cache} = $around->{cache};
@@ -72,25 +72,25 @@ sub wrap {
        my $class = shift;
        my $code  = shift;
        (blessed($code) && $code->isa('Class::MOP::Method'))
-               || confess "Can only wrap blessed CODE";        
-       my $modifier_table = { 
+               || confess "Can only wrap blessed CODE";
+       my $modifier_table = {
                cache  => undef,
                orig   => $code,
                before => [],
-               after  => [],           
+               after  => [],
                around => {
                        cache   => $code->body,
-                       methods => [],          
+                       methods => [],
                },
        };
        $_build_wrapped_method->($modifier_table);
-       my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) });       
+       my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) });
        $method->{'%!modifier_table'} = $modifier_table;
-       $method;  
+       $method;
 }
 
 sub get_original_method {
-       my $code = shift; 
+       my $code = shift;
     $code->{'%!modifier_table'}->{orig};
 }
 
@@ -105,14 +105,14 @@ sub add_after_modifier {
        my $code     = shift;
        my $modifier = shift;
        push @{$code->{'%!modifier_table'}->{after}} => $modifier;
-       $_build_wrapped_method->($code->{'%!modifier_table'});  
+       $_build_wrapped_method->($code->{'%!modifier_table'});
 }
 
 {
        # NOTE:
-       # this is another possible candidate for 
+       # this is another possible candidate for
        # optimization as well. There is an overhead
-       # associated with the currying that, if 
+       # associated with the currying that, if
        # eliminated might make around modifiers
        # more manageable.
        my $compile_around_method = sub {{
@@ -126,13 +126,13 @@ sub add_after_modifier {
        sub add_around_modifier {
                my $code     = shift;
                my $modifier = shift;
-               unshift @{$code->{'%!modifier_table'}->{around}->{methods}} => $modifier;               
+               unshift @{$code->{'%!modifier_table'}->{around}->{methods}} => $modifier;
                $code->{'%!modifier_table'}->{around}->{cache} = $compile_around_method->(
                        @{$code->{'%!modifier_table'}->{around}->{methods}},
                        $code->{'%!modifier_table'}->{orig}->body
                );
-               $_build_wrapped_method->($code->{'%!modifier_table'});          
-       }       
+               $_build_wrapped_method->($code->{'%!modifier_table'});
+       }
 }
 
 1;
@@ -141,7 +141,7 @@ __END__
 
 =pod
 
-=head1 NAME 
+=head1 NAME
 
 Class::MOP::Method::Wrapped - Method Meta Object to handle before/around/after modifiers
 
@@ -186,7 +186,7 @@ Copyright 2006, 2007 by Infinity Interactive, Inc.
 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. 
+it under the same terms as Perl itself.
 
 =cut
 
index 2a749ae..2abfeb7 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 6;
+use Test::More tests => 8;
 
 BEGIN {
     use_ok('Class::MOP');   
@@ -36,6 +36,11 @@ is_deeply(
     [ 'My::D', 'My::B', 'My::A', 'My::C', 'My::A' ], 
     '... My::D->meta->class_precedence_list == (D B A C A)');
 
+is_deeply(
+    [ My::D->meta->linearized_isa ], 
+    [ 'My::D', 'My::B', 'My::A', 'My::C' ], 
+    '... My::D->meta->linearized_isa == (D B A C)');
+
 =pod
 
  A <-+
@@ -93,6 +98,11 @@ is_deeply(
     [ 'My::3::D', 'My::3::B', 'My::3::A', 'My::3::C', 'My::3::A', 'My::3::B', 'My::3::A' ], 
     '... My::3::D->meta->class_precedence_list == (D B A C A B A)');
 
+is_deeply(
+    [ My::3::D->meta->linearized_isa ], 
+    [ 'My::3::D', 'My::3::B', 'My::3::A', 'My::3::C' ], 
+    '... My::3::D->meta->linearized_isa == (D B A C B)');
+
 =pod
 
 Test all the class_precedence_lists 
index 33a2f4a..1ca0081 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 195;
+use Test::More tests => 197;
 use Test::Exception;
 
 BEGIN {
@@ -61,7 +61,7 @@ my @class_mop_class_methods = qw(
 
     attribute_metaclass method_metaclass
 
-    superclasses class_precedence_list
+    superclasses class_precedence_list linearized_isa
 
     has_method get_method add_method remove_method alias_method
     get_method_list get_method_map compute_all_applicable_methods