Allowing binding to list its local variables #1

Closed
wants to merge 1 commit into
from
Jump to file or symbol
Failed to load files and symbols.
+62 −0
Split
View
53 proc.c
@@ -442,6 +442,58 @@ check_local_id(VALUE bindval, volatile VALUE *pname)
return lid;
}
+/*
+ * call-seq:
+ * binding.local_variables -> Array
+ *
+ * Returns the +symbol+ names of the binding's local variables
+ *
+ * def foo
+ * a = 1
+ * 2.times do |n|
+ * binding.local_variables #=> [:a, :n]
+ * end
+ * end
+ *
+ * This method is short version of the following code.
+ *
+ * binding.eval("local_variables")
+ *
+ */
+static VALUE
+bind_local_variables(VALUE bindval)
+{
+ VALUE ary = rb_ary_new();
+
+ const rb_binding_t *bind;
+ const rb_env_t *env;
+ VALUE envval;
+
+ GetBindingPtr(bindval, bind);
+
+ envval = bind->env;
+ GetEnvPtr(envval, env);
+
+ do {
+ const rb_iseq_t *iseq;
+ int i;
+ ID id;
+ iseq = env->block.iseq;
+
+ for (i=0; i<iseq->local_table_size; i++) {
+ id = iseq->local_table[i];
+ if (id) {
+ const char *vname = rb_id2name(id);
+ if (vname) {
+ rb_ary_push(ary, ID2SYM(id));
+ }
+ }
+ }
+ } while ((envval = env->prev_envval) != 0);
+
+ return ary;
+}
+
/*
* call-seq:
* binding.local_variable_get(symbol) -> obj
@@ -2697,6 +2749,7 @@ Init_Binding(void)
rb_define_method(rb_cBinding, "clone", binding_clone, 0);
rb_define_method(rb_cBinding, "dup", binding_dup, 0);
rb_define_method(rb_cBinding, "eval", bind_eval, -1);
+ rb_define_method(rb_cBinding, "local_variables", bind_local_variables, 0);
rb_define_method(rb_cBinding, "local_variable_get", bind_local_variable_get, 1);
rb_define_method(rb_cBinding, "local_variable_set", bind_local_variable_set, 2);
rb_define_method(rb_cBinding, "local_variable_defined?", bind_local_variable_defined_p, 1);
@@ -83,6 +83,15 @@ def test_local_variables3
end.call
end
+ def _new_binding(bind)
+ this_should_not_be_in_bind = 2
+ assert_equal([:x], bind.local_variables)
+ end
+ def test_local_variables_from_other_method_binding
+ x = 1
+ _new_binding(binding)
+ end
+
def test_global_variable_0
assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, [])
end