From 1f03c90dbf40fdba75fdb150f6382f77efeda175 Mon Sep 17 00:00:00 2001 From: shugo Date: Thu, 19 Jul 2012 06:41:47 +0000 Subject: [PATCH] * variable.c (rb_mod_class_variables): return inherited variables except when the optional argument is set to false. [ruby-dev:44034] [Bug #4971] * variable.c (rb_mod_constants): fix typo in documentation. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 8 ++++ include/ruby/intern.h | 2 +- object.c | 2 +- test/ruby/test_module.rb | 12 ++++++ variable.c | 83 ++++++++++++++++++++++++++++++++++------ 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c95d78162..855a051874 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Jul 19 15:38:35 2012 Shugo Maeda + + * variable.c (rb_mod_class_variables): return inherited variables + except when the optional argument is set to false. + [ruby-dev:44034] [Bug #4971] + + * variable.c (rb_mod_constants): fix typo in documentation. + Thu Jul 19 14:30:43 2012 Nobuyoshi Nakada * internal.h: move mark function declarations that should be private. diff --git a/include/ruby/intern.h b/include/ruby/intern.h index f28ad5e186..bc3d0fcea2 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -886,7 +886,7 @@ VALUE rb_cvar_get(VALUE, ID); void rb_cv_set(VALUE, const char*, VALUE); VALUE rb_cv_get(VALUE, const char*); void rb_define_class_variable(VALUE, const char*, VALUE); -VALUE rb_mod_class_variables(VALUE); +VALUE rb_mod_class_variables(int, VALUE*, VALUE); VALUE rb_mod_remove_cvar(VALUE, VALUE); ID rb_frame_callee(void); diff --git a/object.c b/object.c index f890d49728..7cc1e79b69 100644 --- a/object.c +++ b/object.c @@ -2979,7 +2979,7 @@ Init_Object(void) rb_define_method(rb_cModule, "const_missing", rb_mod_const_missing, 1); /* in variable.c */ rb_define_method(rb_cModule, "class_variables", - rb_mod_class_variables, 0); /* in variable.c */ + rb_mod_class_variables, -1); /* in variable.c */ rb_define_method(rb_cModule, "remove_class_variable", rb_mod_remove_cvar, 1); /* in variable.c */ rb_define_method(rb_cModule, "class_variable_get", rb_mod_cvar_get, 1); diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 06ab6cba9f..b27f9ddd0f 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -1356,4 +1356,16 @@ class TestModule < Test::Unit::TestCase assert_equal([:m1], Class.new{ prepend Module.new; def m1; end }.instance_methods(false), bug6660) assert_equal([:m1], Class.new(Class.new{def m2;end}){ prepend Module.new; def m1; end }.instance_methods(false), bug6660) end + + def test_class_variables + m = Module.new + m.class_variable_set(:@@foo, 1) + m2 = Module.new + m2.send(:include, m) + m2.class_variable_set(:@@bar, 2) + assert_equal([:@@foo], m.class_variables) + assert_equal([:@@bar, :@@foo], m2.class_variables) + assert_equal([:@@bar, :@@foo], m2.class_variables(true)) + assert_equal([:@@bar], m2.class_variables(false)) + end end diff --git a/variable.c b/variable.c index 02fa08476f..bf3ad63469 100644 --- a/variable.c +++ b/variable.c @@ -1939,7 +1939,7 @@ rb_const_list(void *data) * * Returns an array of the names of the constants accessible in * mod. This includes the names of constants in any included - * modules (example at start of section), unless the all + * modules (example at start of section), unless the inherit * parameter is set to false. * * IO.constants.include?(:SYNC) #=> true @@ -2323,22 +2323,71 @@ static int cv_i(st_data_t k, st_data_t v, st_data_t a) { ID key = (ID)k; - VALUE ary = (VALUE)a; + st_table *tbl = (st_table *)a; if (rb_is_class_id(key)) { - VALUE kval = ID2SYM(key); - if (!rb_ary_includes(ary, kval)) { - rb_ary_push(ary, kval); + if (!st_lookup(tbl, (st_data_t)key, 0)) { + st_insert(tbl, (st_data_t)key, 0); } } return ST_CONTINUE; } + +static void* +mod_cvar_at(VALUE mod, void *data) +{ + st_table *tbl = data; + if (!tbl) { + tbl = st_init_numtable(); + } + if (RCLASS_IV_TBL(mod)) { + st_foreach_safe(RCLASS_IV_TBL(mod), cv_i, (st_data_t)tbl); + } + return tbl; +} + +static void* +mod_cvar_of(VALUE mod, void *data) +{ + VALUE tmp = mod; + for (;;) { + data = mod_cvar_at(tmp, data); + tmp = RCLASS_SUPER(tmp); + if (!tmp) break; + } + return data; +} + +static int +cv_list_i(st_data_t key, st_data_t value, VALUE ary) +{ + ID sym = (ID)key; + rb_ary_push(ary, ID2SYM(sym)); + return ST_CONTINUE; +} + +static VALUE +cvar_list(void *data) +{ + st_table *tbl = data; + VALUE ary; + + if (!tbl) return rb_ary_new2(0); + ary = rb_ary_new2(tbl->num_entries); + st_foreach_safe(tbl, cv_list_i, ary); + st_free_table(tbl); + + return ary; +} /* * call-seq: - * mod.class_variables -> array + * mod.class_variables(inherit=true) -> array * * Returns an array of the names of class variables in mod. + * This includes the names of class variables in any included + * modules, unless the inherit parameter is set to + * false. * * class One * @@var1 = 1 @@ -2347,18 +2396,28 @@ cv_i(st_data_t k, st_data_t v, st_data_t a) * @@var2 = 2 * end * One.class_variables #=> [:@@var1] - * Two.class_variables #=> [:@@var2] + * Two.class_variables #=> [:@@var2, :@@var1] */ VALUE -rb_mod_class_variables(VALUE obj) +rb_mod_class_variables(int argc, VALUE *argv, VALUE mod) { - VALUE ary = rb_ary_new(); + VALUE inherit; + st_table *tbl; - if (RCLASS_IV_TBL(obj)) { - st_foreach_safe(RCLASS_IV_TBL(obj), cv_i, (st_data_t)ary); + if (argc == 0) { + inherit = Qtrue; } - return ary; + else { + rb_scan_args(argc, argv, "01", &inherit); + } + if (RTEST(inherit)) { + tbl = mod_cvar_of(mod, 0); + } + else { + tbl = mod_cvar_at(mod, 0); + } + return cvar_list(tbl); } /*