Project

General

Profile

Bug #4971 ยป class_variables.diff

shugo (Shugo Maeda), 07/16/2011 08:50 PM

View differences:

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);
}
/*
    (1-1/1)