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/