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

ruby-changes:51659

From: nobu <ko1@a...>
Date: Fri, 6 Jul 2018 22:57:05 +0900 (JST)
Subject: [ruby-changes:51659] nobu:r63871 (trunk): const_missing on private constants

nobu	2018-07-06 22:56:58 +0900 (Fri, 06 Jul 2018)

  New Revision: 63871

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63871

  Log:
    const_missing on private constants
    
    * variable.c (rb_const_search): call #const_missing method on
      private constants, as well as uninitialized constants.
      [Feature #14328]

  Modified files:
    trunk/spec/ruby/language/constants_spec.rb
    trunk/test/ruby/test_module.rb
    trunk/variable.c
    trunk/vm.c
    trunk/vm_core.h
Index: variable.c
===================================================================
--- variable.c	(revision 63870)
+++ variable.c	(revision 63871)
@@ -1795,7 +1795,12 @@ rb_const_missing(VALUE klass, VALUE name https://github.com/ruby/ruby/blob/trunk/variable.c#L1795
 VALUE
 rb_mod_const_missing(VALUE klass, VALUE name)
 {
+    VALUE ref = GET_EC()->private_const_reference;
     rb_vm_pop_cfunc_frame();
+    if (ref) {
+	rb_name_err_raise("private constant %2$s::%1$s referenced",
+			  ref, name);
+    }
     uninitialized_constant(klass, name);
 
     UNREACHABLE;
@@ -2363,8 +2368,8 @@ rb_const_search(VALUE klass, ID id, int https://github.com/ruby/ruby/blob/trunk/variable.c#L2368
 	while ((ce = rb_const_lookup(tmp, id))) {
 	    if (visibility && RB_CONST_PRIVATE_P(ce)) {
 		if (BUILTIN_TYPE(tmp) == T_ICLASS) tmp = RBASIC(tmp)->klass;
-		rb_name_err_raise("private constant %2$s::%1$s referenced",
-				  tmp, ID2SYM(id));
+		GET_EC()->private_const_reference = tmp;
+		return Qundef;
 	    }
 	    rb_const_warn_if_deprecated(ce, tmp, id);
 	    value = ce->value;
@@ -2376,7 +2381,7 @@ rb_const_search(VALUE klass, ID id, int https://github.com/ruby/ruby/blob/trunk/variable.c#L2381
 		continue;
 	    }
 	    if (exclude && tmp == rb_cObject && klass != rb_cObject) {
-		return Qundef;
+		goto not_found;
 	    }
 	    return value;
 	}
@@ -2389,6 +2394,8 @@ rb_const_search(VALUE klass, ID id, int https://github.com/ruby/ruby/blob/trunk/variable.c#L2394
 	goto retry;
     }
 
+  not_found:
+    GET_EC()->private_const_reference = 0;
     return Qundef;
 }
 
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 63870)
+++ vm_core.h	(revision 63871)
@@ -836,6 +836,7 @@ typedef struct rb_execution_context_stru https://github.com/ruby/ruby/blob/trunk/vm_core.h#L836
     VALUE passed_block_handler; /* for rb_iterate */
     const rb_callable_method_entry_t *passed_bmethod_me; /* for bmethod */
     enum method_missing_reason method_missing_reason;
+    VALUE private_const_reference;
 
     /* for GC */
     struct {
Index: spec/ruby/language/constants_spec.rb
===================================================================
--- spec/ruby/language/constants_spec.rb	(revision 63870)
+++ spec/ruby/language/constants_spec.rb	(revision 63871)
@@ -458,6 +458,18 @@ describe "Module#private_constant marked https://github.com/ruby/ruby/blob/trunk/spec/ruby/language/constants_spec.rb#L458
     lambda {mod::Foo}.should raise_error(NameError)
   end
 
+  it "sends #const_missing to the original class or module" do
+    mod = Module.new
+    mod.const_set :Foo, true
+    mod.send :private_constant, :Foo
+    def mod.const_missing(name)
+      @const_missing_arg = name
+      name == :Foo ? name : super
+    end
+
+    mod::Foo.should == :Foo
+  end
+
   describe "in a module" do
     it "cannot be accessed from outside the module" do
       lambda do
Index: vm.c
===================================================================
--- vm.c	(revision 63870)
+++ vm.c	(revision 63871)
@@ -2418,6 +2418,7 @@ rb_execution_context_mark(const rb_execu https://github.com/ruby/ruby/blob/trunk/vm.c#L2418
     rb_mark_tbl(ec->local_storage);
     RUBY_MARK_UNLESS_NULL(ec->local_storage_recursive_hash);
     RUBY_MARK_UNLESS_NULL(ec->local_storage_recursive_hash_for_trace);
+    RUBY_MARK_UNLESS_NULL(ec->private_const_reference);
 }
 
 void rb_fiber_mark_self(rb_fiber_t *fib);
Index: test/ruby/test_module.rb
===================================================================
--- test/ruby/test_module.rb	(revision 63870)
+++ test/ruby/test_module.rb	(revision 63871)
@@ -1422,6 +1422,21 @@ class TestModule < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_module.rb#L1422
     RUBY
   end
 
+  def test_private_constant_const_missing
+    c = Class.new
+    c.const_set(:FOO, "foo")
+    c.private_constant(:FOO)
+    class << c
+      attr_reader :const_missing_arg
+      def const_missing(name)
+        @const_missing_arg = name
+	name == :FOO ? const_get(:FOO) : super
+      end
+    end
+    assert_equal("foo", c::FOO)
+    assert_equal(:FOO, c.const_missing_arg)
+  end
+
   class PrivateClass
   end
   private_constant :PrivateClass

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

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