1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Add an optional inherit argument to Module#autoload?

[Feature #15777]

Closes: https://github.com/ruby/ruby/pull/2173
This commit is contained in:
Jean Boussier 2019-05-07 12:52:24 +02:00 committed by Nobuyoshi Nakada
parent 887163beb8
commit fb85a42860
No known key found for this signature in database
GPG key ID: 4BC7D6DF58D8DF60
7 changed files with 63 additions and 9 deletions

7
NEWS
View file

@ -123,6 +123,13 @@ Integer::
0b01001100[2...6] #=> 0b0011
^^^^
Module::
Modified method::
* Module#autoload? now takes an +inherit+ optional argument, like as
Module#const_defined?. [Feature #15777]
Regexp / String::
* Update Unicode version and Emoji version from 11.0.0 to

View file

@ -2200,6 +2200,7 @@ VALUE rb_search_class_path(VALUE);
VALUE rb_attr_delete(VALUE, ID);
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
void rb_autoload_str(VALUE mod, ID id, VALUE file);
VALUE rb_autoload_at_p(VALUE, ID, VALUE);
void rb_deprecate_constant(VALUE mod, const char *name);
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
rb_gvar_getter_t *rb_gvar_getter_function_of(const struct rb_global_entry *);

35
load.c
View file

@ -1142,25 +1142,42 @@ rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
/*
* call-seq:
* mod.autoload?(name) -> String or nil
* mod.autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
* +autoload+ in the namespace of _mod_.
* +autoload+ in the namespace of _mod_ or one of its ancestors.
*
* module A
* end
* A.autoload(:B, "b")
* A.autoload?(:B) #=> "b"
*
* If +inherit+ is false, the lookup only checks the autoloads in the receiver:
*
* class A
* autoload :CONST, "const.rb"
* end
*
* class B < A
* end
*
* B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
* B.autoload?(:CONST, false) #=> nil, not found in B itself
*
*/
static VALUE
rb_mod_autoload_p(VALUE mod, VALUE sym)
rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
{
rb_check_arity(argc, 1, 2);
VALUE sym = argv[0];
VALUE recur = (argc == 1) ? Qtrue : argv[1];
ID id = rb_check_id(&sym);
if (!id) {
return Qnil;
}
return rb_autoload_p(mod, id);
return rb_autoload_at_p(mod, id, recur);
}
/*
@ -1186,7 +1203,7 @@ rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
/*
* call-seq:
* autoload?(name) -> String or nil
* autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
* +autoload+.
@ -1196,14 +1213,14 @@ rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
*/
static VALUE
rb_f_autoload_p(VALUE obj, VALUE sym)
rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
{
/* use rb_vm_cbase() as same as rb_f_autoload. */
VALUE klass = rb_vm_cbase();
if (NIL_P(klass)) {
return Qnil;
}
return rb_mod_autoload_p(klass, sym);
return rb_mod_autoload_p(argc, argv, klass);
}
void
@ -1233,9 +1250,9 @@ Init_load(void)
rb_define_global_function("require", rb_f_require, 1);
rb_define_global_function("require_relative", rb_f_require_relative, 1);
rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
rb_define_global_function("autoload", rb_f_autoload, 2);
rb_define_global_function("autoload?", rb_f_autoload_p, 1);
rb_define_global_function("autoload?", rb_f_autoload_p, -1);
ruby_dln_librefs = rb_ary_tmp_new(0);
rb_gc_register_mark_object(ruby_dln_librefs);

View file

@ -11,6 +11,18 @@ describe "Module#autoload?" do
it "returns nil if no file has been registered for a constant" do
ModuleSpecs::Autoload.autoload?(:Manualload).should be_nil
end
it "returns the name of the file that will be autoloaded if an ancestor defined that autoload" do
ModuleSpecs::Autoload::Parent.autoload :AnotherAutoload, "another_autoload.rb"
ModuleSpecs::Autoload::Child.autoload?(:AnotherAutoload).should == "another_autoload.rb"
end
ruby_version_is "2.7" do
it "returns nil if an ancestor defined that autoload but recursion is disabled" do
ModuleSpecs::Autoload::Parent.autoload :AnotherAutoload, "another_autoload.rb"
ModuleSpecs::Autoload::Child.autoload?(:AnotherAutoload, false).should be_nil
end
end
end
describe "Module#autoload" do

View file

@ -386,6 +386,12 @@ module ModuleSpecs
end
end
class Parent
end
class Child < Parent
end
module FromThread
module A
autoload :B, fixture(__FILE__, "autoload_empty.rb")

View file

@ -54,6 +54,10 @@ p Foo::Bar
assert_equal(true, b.const_defined?(:X))
assert_equal(tmpfile, a.autoload?(:X), bug4565)
assert_equal(tmpfile, b.autoload?(:X), bug4565)
assert_equal(tmpfile, a.autoload?(:X, false))
assert_equal(tmpfile, a.autoload?(:X, nil))
assert_nil(b.autoload?(:X, false))
assert_nil(b.autoload?(:X, nil))
assert_equal(true, a.const_defined?("Y"))
assert_equal(true, b.const_defined?("Y"))
assert_equal(tmpfile2, a.autoload?("Y"))

View file

@ -2331,11 +2331,18 @@ rb_autoload_load(VALUE mod, ID id)
VALUE
rb_autoload_p(VALUE mod, ID id)
{
return rb_autoload_at_p(mod, id, Qtrue);
}
VALUE
rb_autoload_at_p(VALUE mod, ID id, VALUE recur)
{
VALUE load;
struct autoload_data_i *ele;
while (!autoload_defined_p(mod, id)) {
if (!RTEST(recur)) return Qnil;
mod = RCLASS_SUPER(mod);
if (!mod) return Qnil;
}