summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-24 16:03:12 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-12-24 16:03:12 +0000
commita11831a9a559c296617559f664bcba0aab254563 (patch)
tree9867a689d68d7cc4befbc7b33e1be16e9529ffe9
parent2e6ffdf9577f2bb6513f2909e9c270d6c9dcd6c0 (diff)
proc.c: Binding#local_variables
* 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] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44392 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog6
-rw-r--r--proc.c53
-rw-r--r--test/ruby/test_variable.rb11
3 files changed, 70 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 71ca216da7..5ee3872c68 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/proc.c b/proc.c
index 2630df15d0..9de48a053f 100644
--- a/proc.c
+++ b/proc.c
@@ -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