mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20747 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									13aaff3e9f
								
							
						
					
					
						commit
						3a5c0bbcb5
					
				
					 3 changed files with 232 additions and 20 deletions
				
			
		
							
								
								
									
										20
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,23 @@
 | 
			
		|||
Mon Dec 15 14:56:59 2008  Yuki Sonoda (Yugui)  <yugui@yugui.jp>
 | 
			
		||||
 | 
			
		||||
	* 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@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* id.h, template/id.h.tmpl (ruby_method_ids): sees YYTOKENTYPE too.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								class.c
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								class.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -186,29 +186,47 @@ rb_singleton_class_attached(VALUE klass, VALUE obj)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 @@ rb_singleton_class(VALUE obj)
 | 
			
		|||
    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);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										169
									
								
								test/ruby/test_metaclass.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								test/ruby/test_metaclass.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue