Skip to content
Permalink
Browse files

Add an optional `inherit` argument to Module#autoload?

[Feature #15777]

Closes: #2173
  • Loading branch information...
byroot authored and nobu committed May 7, 2019
1 parent 887163b commit fb85a428605265a8fd449b0702a4dd88cb6f3b20
Showing with 63 additions and 9 deletions.
  1. +7 −0 NEWS
  2. +1 −0 internal.h
  3. +26 −9 load.c
  4. +12 −0 spec/ruby/core/module/autoload_spec.rb
  5. +6 −0 spec/ruby/core/module/fixtures/classes.rb
  6. +4 −0 test/ruby/test_autoload.rb
  7. +7 −0 variable.c
7 NEWS
@@ -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
@@ -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
@@ -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);
@@ -11,6 +11,18 @@
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
@@ -386,6 +386,12 @@ def self.use_ex1
end
end

class Parent
end

class Child < Parent
end

module FromThread
module A
autoload :B, fixture(__FILE__, "autoload_empty.rb")
@@ -54,6 +54,10 @@ def test_autoload_p
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"))
@@ -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;
}

0 comments on commit fb85a42

Please sign in to comment.
You can’t perform that action at this time.