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

ruby-changes:18689

From: mame <ko1@a...>
Date: Sat, 29 Jan 2011 03:00:30 +0900 (JST)
Subject: [ruby-changes:18689] Ruby:r30714 (trunk): * compile.c (NODE_CLASS, NODE_MODULE), insns.def (defineclass): raise

mame	2011-01-29 02:57:34 +0900 (Sat, 29 Jan 2011)

  New Revision: 30714

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

  Log:
    * compile.c (NODE_CLASS, NODE_MODULE), insns.def (defineclass): raise
      an exception when "class Foo::Bar" is evaluated and Foo::Bar is
      private.  To implement this, define_type of "defineclass" is added
      so that the instruction can distinguish whether the class definition
      is scoped (class Foo::Bar) or not (class Bar).
    
    * test/ruby/test_class.rb (test_redefine_private_class),
      test/ruby/test_module.rb
      (test_define_module_under_private_constant): add tests for above.

  Modified files:
    trunk/ChangeLog
    trunk/compile.c
    trunk/insns.def
    trunk/test/ruby/test_class.rb
    trunk/test/ruby/test_module.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 30713)
+++ ChangeLog	(revision 30714)
@@ -1,3 +1,15 @@
+Sat Jan 29 01:24:57 2011  Yusuke Endoh  <mame@t...>
+
+	* compile.c (NODE_CLASS, NODE_MODULE), insns.def (defineclass): raise
+	  an exception when "class Foo::Bar" is evaluated and Foo::Bar is
+	  private.  To implement this, define_type of "defineclass" is added
+	  so that the instruction can distinguish whether the class definition
+	  is scoped (class Foo::Bar) or not (class Bar).
+
+	* test/ruby/test_class.rb (test_redefine_private_class),
+	  test/ruby/test_module.rb
+	  (test_define_module_under_private_constant): add tests for above.
+
 Sat Jan 29 01:19:17 2011  Yusuke Endoh  <mame@t...>
 
 	* constant.h, variable.c: to ensure compatibility, rb_const_get_* must
Index: insns.def
===================================================================
--- insns.def	(revision 30713)
+++ insns.def	(revision 30714)
@@ -894,7 +894,8 @@
     VALUE klass;
 
     switch ((int)define_type) {
-      case 0:
+      case 0: /* scoped:   class Foo::Bar */
+      case 3: /* no scope: class Bar */
 	/* val is dummy.  classdef returns class scope value */
 
 	if (super == Qnil) {
@@ -907,7 +908,7 @@
 	rb_autoload_load(cbase, id);
 	if (rb_const_defined_at(cbase, id)) {
 	    /* already exist */
-	    klass = rb_const_get_at(cbase, id);
+	    klass = define_type == 0 ? rb_public_const_get(cbase, id) : rb_const_get_at(cbase, id);
 	    if (TYPE(klass) != T_CLASS) {
 		rb_raise(rb_eTypeError, "%s is not a class", rb_id2name(id));
 	    }
@@ -935,7 +936,8 @@
 	/* super is dummy */
 	klass = rb_singleton_class(cbase);
 	break;
-      case 2:
+      case 2: /* scoped:   module Foo::Bar  or  module ::Bar */
+      case 5: /* no scope: module Bar */
 	/* val is dummy.  classdef returns class scope value */
 	/* super is dummy */
 
@@ -943,7 +945,7 @@
 
 	/* find klass */
 	if (rb_const_defined_at(cbase, id)) {
-	    klass = rb_const_get_at(cbase, id);
+	    klass = define_type == 2 ? rb_public_const_get(cbase, id) : rb_const_get_at(cbase, id);
 	    /* already exist */
 	    if (TYPE(klass) != T_MODULE) {
 		rb_raise(rb_eTypeError, "%s is not a module", rb_id2name(id));
Index: compile.c
===================================================================
--- compile.c	(revision 30713)
+++ compile.c	(revision 30714)
@@ -4680,10 +4680,10 @@
 		node->nd_body,
 		rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)),
 		ISEQ_TYPE_CLASS, nd_line(node));
-	compile_cpath(ret, iseq, node->nd_cpath);
+	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
 	COMPILE(ret, "super", node->nd_super);
 	ADD_INSN3(ret, nd_line(node), defineclass,
-		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(0));
+		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(noscope ? 3 : 0));
 
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
@@ -4696,10 +4696,10 @@
 	    rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)),
 	    ISEQ_TYPE_CLASS, nd_line(node));
 
-	compile_cpath(ret, iseq, node->nd_cpath);
+	VALUE noscope = compile_cpath(ret, iseq, node->nd_cpath);
 	ADD_INSN (ret, nd_line(node), putnil); /* dummy */
 	ADD_INSN3(ret, nd_line(node), defineclass,
-		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2));
+		  ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(noscope ? 5 : 2));
 	if (poped) {
 	    ADD_INSN(ret, nd_line(node), pop);
 	}
Index: test/ruby/test_module.rb
===================================================================
--- test/ruby/test_module.rb	(revision 30713)
+++ test/ruby/test_module.rb	(revision 30714)
@@ -947,8 +947,26 @@
     c.private_constant(:FOO)
     assert_raise(NameError) { c::FOO }
     assert_equal("foo", c.class_eval("FOO"))
+    assert_equal("foo", c.const_get("FOO"))
   end
 
+  class PrivateClass
+  end
+  private_constant :PrivateClass
+
+  def test_define_module_under_private_constant
+    assert_raise(NameError) do
+      eval %q{class TestModule::PrivateClass; end}
+    end
+    assert_raise(NameError) do
+      eval %q{module TestModule::PrivateClass::TestModule; end}
+    end
+    eval %q{class PrivateClass; end}
+    eval %q{module PrivateClass::TestModule; end}
+    assert_instance_of(Module, PrivateClass::TestModule)
+    PrivateClass.class_eval { remove_const(:TestModule) }
+  end
+
   def test_public_constant
     c = Class.new
     c.const_set(:FOO, "foo")
Index: test/ruby/test_class.rb
===================================================================
--- test/ruby/test_class.rb	(revision 30713)
+++ test/ruby/test_class.rb	(revision 30714)
@@ -240,4 +240,22 @@
   def test_nested_class_removal
     assert_normal_exit('File.__send__(:remove_const, :Stat); at_exit{File.stat(".")}; GC.start')
   end
+
+  class PrivateClass
+  end
+  private_constant :PrivateClass
+
+  def test_redefine_private_class
+    assert_raise(NameError) do
+      eval("class ::TestClass::PrivateClass; end")
+    end
+    eval <<-END
+      class ::TestClass
+        class PrivateClass
+          def foo; 42; end
+        end
+      end
+    END
+    assert_equal(42, PrivateClass.new.foo)
+  end
 end

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

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