Skip to content

Commit fa7cddc

Browse files
committed
Add Binding#implicit_parameters, etc.
This changeset introduces: * `Binding#implicit_parameters` * `Binding#implicit_parameter_get` * `Binding#implicit_parameter_defined?` [Bug #21049]
1 parent d428d08 commit fa7cddc

File tree

2 files changed

+135
-5
lines changed

2 files changed

+135
-5
lines changed

proc.c

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ bind_eval(int argc, VALUE *argv, VALUE bindval)
409409
}
410410

411411
static const VALUE *
412-
get_local_variable_ptr(const rb_env_t **envp, ID lid)
412+
get_local_variable_ptr(const rb_env_t **envp, ID lid, bool search_outer)
413413
{
414414
const rb_env_t *env = *envp;
415415
do {
@@ -446,7 +446,7 @@ get_local_variable_ptr(const rb_env_t **envp, ID lid)
446446
*envp = NULL;
447447
return NULL;
448448
}
449-
} while ((env = rb_vm_env_prev_env(env)) != NULL);
449+
} while (search_outer && (env = rb_vm_env_prev_env(env)) != NULL);
450450

451451
*envp = NULL;
452452
return NULL;
@@ -548,7 +548,7 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
548548
GetBindingPtr(bindval, bind);
549549

550550
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
551-
if ((ptr = get_local_variable_ptr(&env, lid)) != NULL) {
551+
if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) != NULL) {
552552
return *ptr;
553553
}
554554

@@ -600,7 +600,7 @@ bind_local_variable_set(VALUE bindval, VALUE sym, VALUE val)
600600

601601
GetBindingPtr(bindval, bind);
602602
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
603-
if ((ptr = get_local_variable_ptr(&env, lid)) == NULL) {
603+
if ((ptr = get_local_variable_ptr(&env, lid, TRUE)) == NULL) {
604604
/* not found. create new env */
605605
ptr = rb_binding_add_dynavars(bindval, bind, 1, &lid);
606606
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
@@ -647,7 +647,80 @@ bind_local_variable_defined_p(VALUE bindval, VALUE sym)
647647

648648
GetBindingPtr(bindval, bind);
649649
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
650-
return RBOOL(get_local_variable_ptr(&env, lid));
650+
return RBOOL(get_local_variable_ptr(&env, lid, TRUE));
651+
}
652+
653+
/*
654+
* call-seq:
655+
* binding.implicit_parameters -> Array
656+
*
657+
* TODO
658+
*/
659+
static VALUE
660+
bind_implicit_parameters(VALUE bindval)
661+
{
662+
const rb_binding_t *bind;
663+
const rb_env_t *env;
664+
665+
// TODO: it
666+
667+
GetBindingPtr(bindval, bind);
668+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
669+
return rb_vm_env_numbered_parameters(env);
670+
}
671+
672+
/*
673+
* call-seq:
674+
* binding.implicit_parameter_get(symbol) -> obj
675+
*
676+
* TODO
677+
*/
678+
static VALUE
679+
bind_implicit_parameter_get(VALUE bindval, VALUE sym)
680+
{
681+
ID lid = check_local_id(bindval, &sym);
682+
const rb_binding_t *bind;
683+
const VALUE *ptr;
684+
const rb_env_t *env;
685+
686+
if (!lid || !rb_numparam_id_p(lid)) {
687+
rb_name_err_raise("'%1$s' is not an implicit parameter",
688+
bindval, ID2SYM(lid));
689+
}
690+
691+
GetBindingPtr(bindval, bind);
692+
693+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
694+
if ((ptr = get_local_variable_ptr(&env, lid, FALSE)) != NULL) {
695+
return *ptr;
696+
}
697+
698+
rb_name_err_raise("implicit parameter '%1$s' is not defined for %2$s", bindval, ID2SYM(lid));
699+
UNREACHABLE_RETURN(Qundef);
700+
}
701+
702+
/*
703+
* call-seq:
704+
* binding.implicit_parameter_defined?(symbol) -> obj
705+
*
706+
* TODO
707+
*
708+
*/
709+
static VALUE
710+
bind_implicit_parameter_defined_p(VALUE bindval, VALUE sym)
711+
{
712+
ID lid = check_local_id(bindval, &sym);
713+
const rb_binding_t *bind;
714+
const rb_env_t *env;
715+
716+
if (!lid || !rb_numparam_id_p(lid)) {
717+
rb_name_err_raise("'%1$s' is not an implicit parameter",
718+
bindval, ID2SYM(lid));
719+
}
720+
721+
GetBindingPtr(bindval, bind);
722+
env = VM_ENV_ENVVAL_PTR(vm_block_ep(&bind->block));
723+
return RBOOL(get_local_variable_ptr(&env, lid, FALSE));
651724
}
652725

653726
/*
@@ -4607,6 +4680,9 @@ Init_Binding(void)
46074680
rb_define_method(rb_cBinding, "local_variable_get", bind_local_variable_get, 1);
46084681
rb_define_method(rb_cBinding, "local_variable_set", bind_local_variable_set, 2);
46094682
rb_define_method(rb_cBinding, "local_variable_defined?", bind_local_variable_defined_p, 1);
4683+
rb_define_method(rb_cBinding, "implicit_parameters", bind_implicit_parameters, 0);
4684+
rb_define_method(rb_cBinding, "implicit_parameter_get", bind_implicit_parameter_get, 1);
4685+
rb_define_method(rb_cBinding, "implicit_parameter_defined?", bind_implicit_parameter_defined_p, 1);
46104686
rb_define_method(rb_cBinding, "receiver", bind_receiver, 0);
46114687
rb_define_method(rb_cBinding, "source_location", bind_location, 0);
46124688
rb_define_global_function("binding", rb_f_binding, 0);

test/ruby/test_proc.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,60 @@ def test_numparam_is_not_local_variables
16911691
end
16921692
end
16931693

1694+
def test_implicit_parameters
1695+
x = x = 1
1696+
assert_raise(NameError) { binding.implicit_parameter_get(:x) }
1697+
assert_raise(NameError) { binding.implicit_parameter_defined?(:x) }
1698+
1699+
"foo".tap do
1700+
_5 and flunk
1701+
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
1702+
assert_equal("foo", binding.implicit_parameter_get(:_1))
1703+
assert_equal(nil, binding.implicit_parameter_get(:_5))
1704+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1705+
assert_equal(true, binding.implicit_parameter_defined?(:_1))
1706+
assert_equal(true, binding.implicit_parameter_defined?(:_5))
1707+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1708+
"bar".tap do
1709+
assert_equal([], binding.implicit_parameters)
1710+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1711+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1712+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1713+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1714+
end
1715+
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
1716+
assert_equal("foo", binding.implicit_parameter_get(:_1))
1717+
assert_equal(nil, binding.implicit_parameter_get(:_5))
1718+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1719+
assert_equal(true, binding.implicit_parameter_defined?(:_1))
1720+
assert_equal(true, binding.implicit_parameter_defined?(:_5))
1721+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1722+
end
1723+
1724+
"foo".tap do
1725+
assert_equal([], binding.implicit_parameters)
1726+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1727+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1728+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1729+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1730+
"bar".tap do
1731+
_5 and flunk
1732+
assert_equal([:_1, :_2, :_3, :_4, :_5], binding.implicit_parameters)
1733+
assert_equal("bar", binding.implicit_parameter_get(:_1))
1734+
assert_equal(nil, binding.implicit_parameter_get(:_5))
1735+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1736+
assert_equal(true, binding.implicit_parameter_defined?(:_1))
1737+
assert_equal(true, binding.implicit_parameter_defined?(:_5))
1738+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1739+
end
1740+
assert_equal([], binding.implicit_parameters)
1741+
assert_raise(NameError) { binding.implicit_parameter_get(:_1) }
1742+
assert_raise(NameError) { binding.implicit_parameter_get(:_6) }
1743+
assert_equal(false, binding.implicit_parameter_defined?(:_1))
1744+
assert_equal(false, binding.implicit_parameter_defined?(:_6))
1745+
end
1746+
end
1747+
16941748
def test_it_is_not_local_variable
16951749
"foo".tap do
16961750
it

0 commit comments

Comments
 (0)