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]
This commit is contained in:
parent
05a3dc1a65
commit
b35b7a1ef2
Notes:
git
2021-11-18 15:44:14 +09:00
26
load.c
26
load.c
@ -657,7 +657,7 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline enum ruby_tag_type
|
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;
|
enum ruby_tag_type state;
|
||||||
rb_thread_t *th = rb_ec_thread_ptr(ec);
|
rb_thread_t *th = rb_ec_thread_ptr(ec);
|
||||||
@ -669,9 +669,9 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname)
|
|||||||
|
|
||||||
ec->errinfo = Qnil; /* ensure */
|
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_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);
|
rb_extend_object(th->top_self, th->top_wrapper);
|
||||||
|
|
||||||
EC_PUSH_TAG(ec);
|
EC_PUSH_TAG(ec);
|
||||||
@ -703,12 +703,15 @@ raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rb_load_internal(VALUE fname, int wrap)
|
rb_load_internal(VALUE fname, VALUE wrap)
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
enum ruby_tag_type state = TAG_NONE;
|
enum ruby_tag_type state = TAG_NONE;
|
||||||
if (wrap) {
|
if (RTEST(wrap)) {
|
||||||
state = load_wrapping(ec, fname);
|
if (!RB_TYPE_P(wrap, T_MODULE)) {
|
||||||
|
wrap = rb_module_new();
|
||||||
|
}
|
||||||
|
state = load_wrapping(ec, fname, wrap);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
load_iseq_eval(ec, fname);
|
load_iseq_eval(ec, fname);
|
||||||
@ -721,7 +724,7 @@ rb_load(VALUE fname, int wrap)
|
|||||||
{
|
{
|
||||||
VALUE tmp = rb_find_file(FilePathValue(fname));
|
VALUE tmp = rb_find_file(FilePathValue(fname));
|
||||||
if (!tmp) load_failed(fname);
|
if (!tmp) load_failed(fname);
|
||||||
rb_load_internal(tmp, wrap);
|
rb_load_internal(tmp, RBOOL(wrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -763,9 +766,10 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
|
|||||||
*
|
*
|
||||||
* If the optional _wrap_ parameter is +true+, the loaded script will
|
* If the optional _wrap_ parameter is +true+, the loaded script will
|
||||||
* be executed under an anonymous module, protecting the calling
|
* be executed under an anonymous module, protecting the calling
|
||||||
* program's global namespace. In no circumstance will any local
|
* program's global namespace. If the optional _wrap_ parameter is a
|
||||||
* variables in the loaded file be propagated to the loading
|
* module, the loaded script will be executed under the given module.
|
||||||
* environment.
|
* In no circumstance will any local variables in the loaded file be
|
||||||
|
* propagated to the loading environment.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
@ -785,7 +789,7 @@ rb_f_load(int argc, VALUE *argv, VALUE _)
|
|||||||
load_failed(orig_fname);
|
load_failed(orig_fname);
|
||||||
path = fname;
|
path = fname;
|
||||||
}
|
}
|
||||||
rb_load_internal(path, RTEST(wrap));
|
rb_load_internal(path, wrap);
|
||||||
|
|
||||||
RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
|
RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
|
||||||
|
|
||||||
|
@ -367,6 +367,38 @@ class TestRequire < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
end
|
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
|
def test_load_ospath
|
||||||
bug = '[ruby-list:49994] path in ospath'
|
bug = '[ruby-list:49994] path in ospath'
|
||||||
base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J)
|
base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user