summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-08-09 16:44:43 -0700
committerJeremy Evans <code@jeremyevans.net>2019-09-21 16:10:18 -0700
commit7470f965650bf17875632f0c5f9e5a4d9de9fc3f (patch)
treeca40dbb76456ff9ff7a69bc5b6b5a02a494f4b43
parent5cb283217b713605c6bddc527f96bbc773fd1fb9 (diff)
Fix Module#class_variables for singleton classes of classes/modules
Module#class_variables should reflect class variable lookup. For singleton classes of classes/modules, this means the lookup should be: * Singleton Class * Class * All Ancestors of Class Note that this doesn't include modules included in the singleton class, because class variable lookup doesn't include those. Singleton classes of other objects do not have this behavior and always just search all ancestors of the singleton class, so do not change the behavior for them. Fixes [Bug #8297]
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2478
-rw-r--r--test/ruby/test_variable.rb28
-rw-r--r--variable.c6
2 files changed, 34 insertions, 0 deletions
diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb
index aa301f2bc7..f14b4019df 100644
--- a/test/ruby/test_variable.rb
+++ b/test/ruby/test_variable.rb
@@ -35,6 +35,34 @@ class TestVariable < Test::Unit::TestCase
end
end
+ def test_singleton_class_included_class_variable
+ c = Class.new
+ c.extend(Olympians)
+ assert_empty(c.singleton_class.class_variables)
+ assert_raise(NameError){ c.singleton_class.class_variable_get(:@@rule) }
+ c.class_variable_set(:@@foo, 1)
+ assert_equal([:@@foo], c.singleton_class.class_variables)
+ assert_equal(1, c.singleton_class.class_variable_get(:@@foo))
+
+ c = Class.new
+ c.extend(Olympians)
+ sc = Class.new(c)
+ assert_empty(sc.singleton_class.class_variables)
+ assert_raise(NameError){ sc.singleton_class.class_variable_get(:@@rule) }
+ c.class_variable_set(:@@foo, 1)
+ assert_equal([:@@foo], sc.singleton_class.class_variables)
+ assert_equal(1, sc.singleton_class.class_variable_get(:@@foo))
+
+ c = Class.new
+ o = c.new
+ o.extend(Olympians)
+ assert_equal([:@@rule], o.singleton_class.class_variables)
+ assert_equal("Zeus", o.singleton_class.class_variable_get(:@@rule))
+ c.class_variable_set(:@@foo, 1)
+ assert_equal([:@@foo, :@@rule], o.singleton_class.class_variables.sort)
+ assert_equal(1, o.singleton_class.class_variable_get(:@@foo))
+ end
+
def test_variable
assert_instance_of(Integer, $$)
diff --git a/variable.c b/variable.c
index f3d73fac63..1627467bd9 100644
--- a/variable.c
+++ b/variable.c
@@ -3209,6 +3209,12 @@ static void*
mod_cvar_of(VALUE mod, void *data)
{
VALUE tmp = mod;
+ if (FL_TEST(mod, FL_SINGLETON)) {
+ if (rb_namespace_p(rb_ivar_get(mod, id__attached__))) {
+ data = mod_cvar_at(tmp, data);
+ tmp = cvar_front_klass(tmp);
+ }
+ }
for (;;) {
data = mod_cvar_at(tmp, data);
tmp = RCLASS_SUPER(tmp);