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

ruby-changes:69801

From: Jeremy <ko1@a...>
Date: Thu, 18 Nov 2021 15:44:04 +0900 (JST)
Subject: [ruby-changes:69801] b35b7a1ef2 (master): Allow Kernel#load to load code into a specified module

https://git.ruby-lang.org/ruby.git/commit/?id=b35b7a1ef2

From b35b7a1ef25347735a6bb7c28ab7e77afea1d856 Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Mon, 18 Oct 2021 08:50:10 -0700
Subject: Allow Kernel#load to load code into a specified module

Instead of always using a new anonymous module for Kernel#load if
the wrap argument is not false/nil, use the given module if a module
is provided.

Implements [Feature #6210]
---
 load.c                    | 26 +++++++++++++++-----------
 test/ruby/test_require.rb | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 11 deletions(-)

diff --git a/load.c b/load.c
index 58f71b9d225..a2b9da48fb2 100644
--- a/load.c
+++ b/load.c
@@ -657,7 +657,7 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname) https://github.com/ruby/ruby/blob/trunk/load.c#L657
 }
 
 static inline enum ruby_tag_type
-load_wrapping(rb_execution_context_t *ec, VALUE fname)
+load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
 {
     enum ruby_tag_type state;
     rb_thread_t *th = rb_ec_thread_ptr(ec);
@@ -669,9 +669,9 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname) https://github.com/ruby/ruby/blob/trunk/load.c#L669
 
     ec->errinfo = Qnil; /* ensure */
 
-    /* load in anonymous module as toplevel */
+    /* load in module as toplevel */
     th->top_self = rb_obj_clone(rb_vm_top_self());
-    th->top_wrapper = rb_module_new();
+    th->top_wrapper = load_wrapper;
     rb_extend_object(th->top_self, th->top_wrapper);
 
     EC_PUSH_TAG(ec);
@@ -703,12 +703,15 @@ raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state) https://github.com/ruby/ruby/blob/trunk/load.c#L703
 }
 
 static void
-rb_load_internal(VALUE fname, int wrap)
+rb_load_internal(VALUE fname, VALUE wrap)
 {
     rb_execution_context_t *ec = GET_EC();
     enum ruby_tag_type state = TAG_NONE;
-    if (wrap) {
-        state = load_wrapping(ec, fname);
+    if (RTEST(wrap)) {
+        if (!RB_TYPE_P(wrap, T_MODULE)) {
+            wrap = rb_module_new();
+        }
+        state = load_wrapping(ec, fname, wrap);
     }
     else {
         load_iseq_eval(ec, fname);
@@ -721,7 +724,7 @@ rb_load(VALUE fname, int wrap) https://github.com/ruby/ruby/blob/trunk/load.c#L724
 {
     VALUE tmp = rb_find_file(FilePathValue(fname));
     if (!tmp) load_failed(fname);
-    rb_load_internal(tmp, wrap);
+    rb_load_internal(tmp, RBOOL(wrap));
 }
 
 void
@@ -763,9 +766,10 @@ rb_load_protect(VALUE fname, int wrap, int *pstate) https://github.com/ruby/ruby/blob/trunk/load.c#L766
  *
  *  If the optional _wrap_ parameter is +true+, the loaded script will
  *  be executed under an anonymous module, protecting the calling
- *  program's global namespace. In no circumstance will any local
- *  variables in the loaded file be propagated to the loading
- *  environment.
+ *  program's global namespace.  If the optional _wrap_ parameter is a
+ *  module, the loaded script will be executed under the given module.
+ *  In no circumstance will any local variables in the loaded file be
+ *  propagated to the loading environment.
  */
 
 static VALUE
@@ -785,7 +789,7 @@ rb_f_load(int argc, VALUE *argv, VALUE _) https://github.com/ruby/ruby/blob/trunk/load.c#L789
 	    load_failed(orig_fname);
 	path = fname;
     }
-    rb_load_internal(path, RTEST(wrap));
+    rb_load_internal(path, wrap);
 
     RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
 
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 7a9faf18f9a..77cdae64d9e 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -367,6 +367,38 @@ class TestRequire < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_require.rb#L367
     }
   end
 
+  def test_load_into_module
+    Tempfile.create(["test_ruby_test_require", ".rb"]) {|t|
+      t.puts "def b; 1 end"
+      t.puts "class Foo"
+      t.puts "  def c; 2 end"
+      t.puts "end"
+      t.close
+
+      m = Module.new
+      load(t.path, m)
+      assert_equal([:b], m.private_instance_methods(false))
+      c = Class.new do
+        include m
+        public :b
+      end
+      assert_equal(1, c.new.b)
+      assert_equal(2, m::Foo.new.c)
+    }
+  end
+
+  def test_load_wrap_nil
+    Dir.mktmpdir do |tmp|
+      File.write("#{tmp}/1.rb", "class LoadWrapNil; end\n")
+      assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+      path = ""#{tmp.dump}"/1.rb"
+      begin;
+        load path, nil
+        assert_instance_of(Class, LoadWrapNil)
+      end;
+    end
+  end
+
   def test_load_ospath
     bug = '[ruby-list:49994] path in ospath'
     base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J)
-- 
cgit v1.2.1


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

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