summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-07-19 06:41:47 +0000
committershugo <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-07-19 06:41:47 +0000
commit1f03c90dbf40fdba75fdb150f6382f77efeda175 (patch)
tree735b1eccea88ed8f79630a804e42ce83e8268371
parent0e60c71038a754c0d1e06afd48c142a58240d275 (diff)
* 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
-rw-r--r--ChangeLog8
-rw-r--r--include/ruby/intern.h2
-rw-r--r--object.c2
-rw-r--r--test/ruby/test_module.rb12
-rw-r--r--variable.c83
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 <shugo@ruby-lang.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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
* <i>mod</i>. This includes the names of constants in any included
- * modules (example at start of section), unless the <i>all</i>
+ * modules (example at start of section), unless the <i>inherit</i>
* parameter is set to <code>false</code>.
*
* 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 <i>mod</i>.
+ * This includes the names of class variables in any included
+ * modules, unless the <i>inherit</i> parameter is set to
+ * <code>false</code>.
*
* 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);
}
/*