diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | proc.c | 53 | ||||
-rw-r--r-- | test/ruby/test_variable.rb | 11 |
3 files changed, 70 insertions, 0 deletions
@@ -1,3 +1,9 @@ +Wed Dec 25 01:03:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * proc.c (bind_local_variables): allowing binding to list its + local variables. patch by Jack Danger Canty <jackdanger AT + squareup.com> at [ruby-core:56543]. [Feature #8773] + Tue Dec 24 23:20:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org> * test/fileutils/fileasserts.rb (assert_ownership_user): new @@ -448,6 +448,58 @@ check_local_id(VALUE bindval, volatile VALUE *pname) /* * 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 * * Returns a +value+ of local variable +symbol+. @@ -2718,6 +2770,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); diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 32b3d61573..321cd7e4c5 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -83,6 +83,17 @@ class TestVariable < Test::Unit::TestCase end.call end + def local_variables_of(bind) + this_should_not_be_in_bind = 2 + bind.local_variables + end + + def test_local_variables_from_other_method_binding + feature8773 = '[Feature #8773]' + x = 1 + assert_equal([:x], local_variables_of(binding), feature8773) + end + def test_global_variable_0 assert_in_out_err(["-e", "$0='t'*1000;print $0"], "", /\At+\z/, []) end |