moving the scala mixins to a test only
Stevan Little [Tue, 14 Feb 2006 19:50:14 +0000 (19:50 +0000)]
Build.PL
Changes
MANIFEST
lib/Class/MOP/Class.pm
t/010_self_introspection.t
t/050_class_mixin_composition.t

index 023fd21..ffdec51 100644 (file)
--- a/Build.PL
+++ b/Build.PL
@@ -11,7 +11,6 @@ my $build = Module::Build->new(
         'Carp'         => '0.01',
         'B'            => '1.09',
         'Clone'        => '0.18',
-        'SUPER'        => '1.11',
     },
     optional => {
     },
diff --git a/Changes b/Changes
index 4b0a9f3..3ff423c 100644 (file)
--- a/Changes
+++ b/Changes
@@ -2,20 +2,14 @@ Revision history for Perl extension Class-MOP.
 
 0.07
     - adding more tests
-        - test for compatability with Class::C3
-    - added SUPER as a dependency (because we need runtime
-      dispatching of SUPER calls for mixins)
       
     * Class::MOP
       - no longer optionally exports to UNIVERSAL::meta or
         creates a custom metaclass generator, use the 
         metaclass pragma instead.
       
-    * Class::MOP::Class
-      - adding in &mixin method to do Scala style mixins
-      
     * examples/
-      - fixing the AttributesWithHistory example, it was broken
+      - fixing the AttributesWithHistory example, it was broken.
 
 0.06 Thurs Feb. 9, 2006
     * metaclass
index 913e996..a81b6ef 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -2,6 +2,8 @@ Build.PL
 Changes
 MANIFEST
 MANIFEST.SKIP
+Makefile.PL
+META.yml
 README
 examples/AttributesWithHistory.pod
 examples/ClassEncapsulatedAttributes.pod
@@ -31,6 +33,7 @@ t/020_attribute.t
 t/030_method.t
 t/040_metaclass.t
 t/041_metaclass_incompatability.t
+t/050_class_mixin_composition.t
 t/100_BinaryTree_test.t
 t/101_InstanceCountingClass_test.t
 t/102_InsideOutClass_test.t
@@ -38,7 +41,7 @@ t/103_Perl6Attribute_test.t
 t/104_AttributesWithHistory_test.t
 t/105_ClassEncapsulatedAttributes_test.t
 t/106_LazyClass_test.t
+t/200_Class_C3_compatibility.t
 t/pod.t
 t/pod_coverage.t
 t/lib/BinaryTree.pm
-Makefile.PL
index 64b8f4e..c109368 100644 (file)
@@ -493,34 +493,6 @@ sub remove_package_variable {
     delete ${$self->name . '::'}{$name};
 }
 
-# class mixins
-
-sub mixin {
-    my ($self, $mixin) = @_;
-    $mixin = $self->initialize($mixin) 
-        unless blessed($mixin);
-    
-    my @attributes = map { 
-        $mixin->get_attribute($_)->clone() 
-    } $mixin->get_attribute_list;                     
-    
-    my %methods = map  { 
-        my $method = $mixin->get_method($_);
-        (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'))
-            ? () : ($_ => $method)
-    } $mixin->get_method_list;    
-
-    foreach my $attr (@attributes) {
-        $self->add_attribute($attr) 
-            unless $self->has_attribute($attr->name);
-    }
-    
-    foreach my $method_name (keys %methods) {
-        $self->alias_method($method_name => $methods{$method_name}) 
-            unless $self->has_method($method_name);
-    }    
-}
-
 1;
 
 __END__
index 5a98408..87416dd 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 119;
+use Test::More tests => 117;
 use Test::Exception;
 
 BEGIN {
@@ -36,8 +36,6 @@ my @methods = qw(
     get_attribute_list get_attribute_map compute_all_applicable_attributes
     
     add_package_variable get_package_variable has_package_variable remove_package_variable
-    
-    mixin
     );
     
 is_deeply([ sort @methods ], [ sort $meta->get_method_list ], '... got the correct method list');
index 56e65ee..290747c 100644 (file)
@@ -3,11 +3,23 @@
 use strict;
 use warnings;
 
-use Test::More tests => 4;
+use Test::More;
+
+BEGIN {
+    eval "use SUPER 1.10";
+    plan skip_all => "SUPER 1.10 required for this test" if $@;
+    plan tests => 4;
+}
 
 =pod
 
-Scala Style Class Mixin Composition
+This test demonstrates how simple it is to create Scala Style 
+Class Mixin Composition. Below is an example taken from the 
+Scala web site's example section, and trancoded to Class::MOP.
+
+NOTE:
+We require SUPER for this test to handle the issue with SUPER::
+being determined at compile time. 
 
 L<http://scala.epfl.ch/intro/mixin.html>
 
@@ -45,6 +57,57 @@ code above is well-formed.
   
 =cut
 
+use Scalar::Util 'blessed';
+use Carp         'confess';
+
+sub ::with ($) {
+    # fetch the metaclass for the 
+    # caller and the mixin arg
+    my $metaclass = (caller)->meta;
+    my $mixin     = (shift)->meta;
+    
+    # according to Scala, the 
+    # the superclass of our class
+    # must be a subclass of the 
+    # superclass of the mixin (see above)
+    my ($super_meta)  = $metaclass->superclasses();
+    my ($super_mixin) = $mixin->superclasses();  
+    ($super_meta->isa($super_mixin))
+        || confess "The superclass must extend a subclass of the superclass of the mixin";
+    
+    # collect all the attributes
+    # and clone them so they can 
+    # associate with the new class
+    my @attributes = map { 
+        $mixin->get_attribute($_)->clone() 
+    } $mixin->get_attribute_list;                     
+    
+    my %methods = map  { 
+        my $method = $mixin->get_method($_);
+        # we want to ignore accessors since
+        # they will be created with the attrs
+        (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'))
+            ? () : ($_ => $method)
+    } $mixin->get_method_list;    
+
+    # NOTE:
+    # I assume that locally defined methods 
+    # and attributes get precedence over those
+    # from the mixin.
+
+    # add all the attributes in ....
+    foreach my $attr (@attributes) {
+        $metaclass->add_attribute($attr) 
+            unless $metaclass->has_attribute($attr->name);
+    }
+
+    # add all the methods in ....    
+    foreach my $method_name (keys %methods) {
+        $metaclass->alias_method($method_name => $methods{$method_name}) 
+            unless $metaclass->has_method($method_name);
+    }    
+}
+
 {
     package Point2D;
     use metaclass;
@@ -98,7 +161,7 @@ code above is well-formed.
     package ColoredPoint3D;
     our @ISA = ('Point3D');    
     
-    __PACKAGE__->meta->mixin('ColoredPoint2D');
+    ::with('ColoredPoint2D');
     
 }