Bug #4971 ยป class_variables.diff
include/ruby/intern.h | ||
---|---|---|
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);
|
||
/* version.c */
|
||
void ruby_show_version(void);
|
object.c | ||
---|---|---|
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);
|
test/ruby/test_module.rb | ||
---|---|---|
}
|
||
assert_equal(42, bar::D)
|
||
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
|
variable.c | ||
---|---|---|
}
|
||
static int
|
||
cv_i(ID key, VALUE value, VALUE ary)
|
||
cv_i(ID key, VALUE value, st_table *tbl)
|
||
{
|
||
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, (st_data_t)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;
|
||
#if 0
|
||
if (tmp == rb_cObject && mod != rb_cObject) break;
|
||
#endif
|
||
}
|
||
return data;
|
||
}
|
||
static int
|
||
cv_list_i(st_data_t key, st_data_t value, VALUE ary)
|
||
{
|
||
ID sym = (ID)key;
|
||
rb_const_entry_t *ce = (rb_const_entry_t *)value;
|
||
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
|
||
... | ... | |
* @@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, 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);
|
||
}
|
||
/*
|