[前][次][番号順一覧][スレッド一覧]

ruby-changes:9210

From: yugui <ko1@a...>
Date: Mon, 15 Dec 2008 15:24:02 +0900 (JST)
Subject: [ruby-changes:9210] Ruby:r20747 (trunk): * test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.

yugui	2008-12-15 15:23:43 +0900 (Mon, 15 Dec 2008)

  New Revision: 20747

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=20747

  Log:
    * test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
    
    * class.c (make_metametaclass): new function. extracted from
      rb_make_metaclass.
    
    * class.c (rb_make_metaclass): uses make_metametaclass when called for a
      metaclass.
    
    * class.c (rb_singleton_class): creates a meta^(n+2)-class in
      addition to a meta^(n+1)-class when called for a meta^(n)-class.
      This is because the returned meta^(n+1) class must acts as an instance of 
      Class, metaclass of Class, ..., meta^(n+1)-class of Class,
      Module, metaclass of Module, ..., meta^(n+1)-class of Module,
      Object, metaclass of Object, ..., meta^(n+2)-class of Object,
      BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
      and BasicObject even when Class, Module, Object or BasicObject has
      not have its meta^(i)-class yet.

  Added files:
    trunk/test/ruby/test_metaclass.rb
  Modified files:
    trunk/ChangeLog
    trunk/class.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 20746)
+++ ChangeLog	(revision 20747)
@@ -1,3 +1,23 @@
+Mon Dec 15 14:56:59 2008  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* test/ruby/test_metaclass.rb: new test case for metaclass hierarchy.
+
+	* class.c (make_metametaclass): new function. extracted from
+	  rb_make_metaclass.
+
+	* class.c (rb_make_metaclass): uses make_metametaclass when called for a
+	  metaclass.
+
+	* class.c (rb_singleton_class): creates a meta^(n+2)-class in
+	  addition to a meta^(n+1)-class when called for a meta^(n)-class.
+	  This is because the returned meta^(n+1) class must acts as an instance of 
+	  Class, metaclass of Class, ..., meta^(n+1)-class of Class,
+	  Module, metaclass of Module, ..., meta^(n+1)-class of Module,
+	  Object, metaclass of Object, ..., meta^(n+2)-class of Object,
+	  BasicObject, metaclass of BasicObject, ..., meta^(n+2)-class of
+	  and BasicObject even when Class, Module, Object or BasicObject has
+	  not have its meta^(i)-class yet. 
+
 Mon Dec 15 15:13:22 2008  Nobuyoshi Nakada  <nobu@r...>
 
 	* id.h, template/id.h.tmpl (ruby_method_ids): sees YYTOKENTYPE too.
Index: class.c
===================================================================
--- class.c	(revision 20746)
+++ class.c	(revision 20747)
@@ -186,29 +186,47 @@
     }
 }
 
+
+static VALUE
+make_metametaclass(VALUE metaclass)
+{
+    VALUE metametaclass, super_of_metaclass;
+
+    if (RBASIC(metaclass)->klass == metaclass) { /* for meta^(n)-class of Class */
+        metametaclass = rb_class_boot(Qnil);
+        RBASIC(metametaclass)->klass = metametaclass;
+    }
+    else {
+        metametaclass = rb_class_boot(Qnil);
+        RBASIC(metametaclass)->klass = 
+            (RBASIC(RBASIC(metaclass)->klass)->klass == RBASIC(metaclass)->klass)
+            ? make_metametaclass(RBASIC(metaclass)->klass)
+            : RBASIC(RBASIC(metaclass)->klass)->klass;
+    }
+
+    FL_SET(metametaclass, FL_SINGLETON);
+    rb_singleton_class_attached(metametaclass, metaclass);
+    RBASIC(metaclass)->klass = metametaclass;
+
+    super_of_metaclass = RCLASS_SUPER(metaclass);
+    while (FL_TEST(super_of_metaclass, T_ICLASS)) {
+        super_of_metaclass = RCLASS_SUPER(super_of_metaclass);
+    }
+    RCLASS_SUPER(metametaclass) = 
+        rb_iv_get(RBASIC(super_of_metaclass)->klass, "__attached__") == super_of_metaclass
+        ? RBASIC(super_of_metaclass)->klass 
+        : make_metametaclass(super_of_metaclass);
+    OBJ_INFECT(metametaclass, RCLASS_SUPER(metametaclass));
+
+    return metametaclass;
+}
+
+
 VALUE
 rb_make_metaclass(VALUE obj, VALUE super)
 {
-    if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
-        VALUE metaclass, meta_of_super;
-        if (RBASIC(obj)->klass == obj) { /* for meta^(n)-class of Class */
-            metaclass = rb_class_boot(obj);
-            RBASIC(metaclass)->klass = metaclass;
-        }
-        else {
-            metaclass = rb_class_boot(super);
-            RBASIC(metaclass)->klass = rb_singleton_class(RBASIC(obj)->klass);
-        }
-        FL_SET(metaclass, FL_SINGLETON);
-        rb_singleton_class_attached(metaclass, obj);
-        RBASIC(obj)->klass = metaclass;
-
-        meta_of_super = RCLASS(obj)->ptr->super;
-        while (FL_TEST(meta_of_super, T_ICLASS)) {
-            meta_of_super = RCLASS(meta_of_super)->ptr->super;
-        }
-        RCLASS(metaclass)->ptr->super = rb_singleton_class(meta_of_super);
-        return metaclass;
+    if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { /* obj is a metaclass */
+        return make_metametaclass(obj);
     }
     else {
 	VALUE metasuper;
@@ -844,6 +862,11 @@
     else {
 	klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
     }
+
+    if (BUILTIN_TYPE(obj) == T_CLASS) {
+	if (rb_iv_get(RBASIC(klass)->klass, "__attached__") != klass)
+        make_metametaclass(klass);
+    }
     if (OBJ_TAINTED(obj)) {
 	OBJ_TAINT(klass);
     }
Index: test/ruby/test_metaclass.rb
===================================================================
--- test/ruby/test_metaclass.rb	(revision 0)
+++ test/ruby/test_metaclass.rb	(revision 20747)
@@ -0,0 +1,169 @@
+require 'test/unit'
+require_relative 'envutil'
+require '~/dev/metaclass_util/metaclass_util'
+
+class TestMetaclass < Test::Unit::TestCase
+  class Foo; end
+  class Bar < Foo; end
+  class Baz; end
+
+  def setup
+    Object.class_eval do
+      def method_o; end
+    end
+    Module.class_eval do
+      def method_m; end
+    end
+    Class.class_eval do
+      def method_c; end
+    end
+  end
+  def teardown
+    Object.class_eval do
+      remove_method :method_o rescue nil
+    end
+    Module.class_eval do
+      remove_method :method_m rescue nil
+    end
+    Class.class_eval do
+      remove_method :method_c rescue nil
+    end
+    Object.class_eval do
+      class << self
+        remove_method :class_method_o rescue nil
+      end
+    end
+    Module.class_eval do
+      class << self
+        remove_method :class_method_m rescue nil
+      end
+    end
+    Class.class_eval do
+      class << self
+        remove_method :class_method_c rescue nil
+      end
+    end
+    Object.class_eval do
+      class << self
+        class << self
+          remove_method :metaclass_method_o rescue nil
+        end
+      end
+    end
+    Module.class_eval do
+      class << self
+        class << self
+          remove_method :metaclass_method_m rescue nil
+        end
+      end
+    end
+    Class.class_eval do
+      class << self
+        class << self
+          remove_method :metaclass_method_c rescue nil
+        end
+      end
+    end
+  end
+
+  def test_metaclass
+    class << Object
+      def class_method_o; end
+    end
+    class << Foo
+      def class_method_f; end
+    end
+    class << Baz
+      def class_method_b; end
+    end
+    assert_nothing_raised{ Bar.method_o }
+    assert_nothing_raised{ Bar.method_m }
+    assert_nothing_raised{ Bar.method_c }
+    assert_nothing_raised{ Bar.class_method_o }
+    assert_nothing_raised{ Bar.class_method_f }
+    assert_raise(NoMethodError){ Bar.class_method_b }
+
+    class << Module
+      def class_method_m; end
+    end
+    class << Class
+      def class_method_c; end
+    end
+    class << Object
+      class << self
+        def metaclass_method_o; end
+      end
+    end
+    class << Foo
+      class << self
+        def metaclass_method_f; end
+      end
+    end
+    class << Baz
+      class << self
+        def metaclass_method_b; end
+      end
+    end
+    metaclass_of_bar = class << Bar; self end
+    assert_nothing_raised{ metaclass_of_bar.method_o }
+    assert_nothing_raised{ metaclass_of_bar.method_m }
+    assert_nothing_raised{ metaclass_of_bar.method_c }
+    assert_nothing_raised{ metaclass_of_bar.class_method_o }
+    assert_raise(NoMethodError){ metaclass_of_bar.class_method_f }
+    assert_raise(NoMethodError){ metaclass_of_bar.class_method_b }
+    assert_nothing_raised{ metaclass_of_bar.class_method_m }
+    assert_nothing_raised{ metaclass_of_bar.class_method_c }
+    assert_nothing_raised{ metaclass_of_bar.metaclass_method_o }
+    assert_nothing_raised{ metaclass_of_bar.metaclass_method_f }
+    assert_raise(NoMethodError){ metaclass_of_bar.metaclass_method_b }
+
+    class << Module
+      class << self
+        def metaclass_method_m; end
+      end
+    end
+    class << Class
+      class << self
+        def metaclass_method_c; end
+      end
+    end
+    class << Object
+      class << self
+        class << self
+          def metametaclass_method_o; end
+        end
+      end
+    end
+    class << Foo
+      class << self
+        class << self
+          def metametaclass_method_f; end
+        end
+      end
+    end
+    class << Baz
+      class << self
+        class << self
+          def metametaclass_method_b; end
+        end
+      end
+    end
+    metametaclass_of_bar = class << metaclass_of_bar; self end
+    assert_nothing_raised{ metametaclass_of_bar.method_o }
+    assert_nothing_raised{ metametaclass_of_bar.method_m }
+    assert_nothing_raised{ metametaclass_of_bar.method_c }
+    assert_nothing_raised{ metametaclass_of_bar.class_method_o }
+    assert_raise(NoMethodError){ metametaclass_of_bar.class_method_f }
+    assert_raise(NoMethodError){ metametaclass_of_bar.class_method_b }
+    assert_nothing_raised{ metametaclass_of_bar.class_method_m }
+    assert_nothing_raised{ metametaclass_of_bar.class_method_c }
+    assert_nothing_raised{ metametaclass_of_bar.metaclass_method_o }
+    assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_f }
+    assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b }
+    assert_nothing_raised{ metametaclass_of_bar.metaclass_method_m }
+    assert_nothing_raised{ metametaclass_of_bar.metaclass_method_c }
+    assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_o }
+    assert_nothing_raised{ metametaclass_of_bar.metametaclass_method_f }
+    assert_raise(NoMethodError){ metametaclass_of_bar.metaclass_method_b }
+  end
+end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]