Project

General

Profile

Feature #14914 ยป 0001-Add-BasicObject-instance_exec_with_block.patch

jeremyevans0 (Jeremy Evans), 07/16/2018 04:04 PM

View differences:

test/ruby/test_object.rb
end
end
def test_instance_exec_with_block
x = 1.instance_exec_with_block(42, 2, proc{|x| self * x}) {|a, b, &blk| (self + a).instance_exec(b, &blk) }
assert_equal(86, x)
assert_raise(ArgumentError) do
x.instance_exec_with_block{}
end
assert_raise(TypeError) do
x.instance_exec_with_block(1){}
end
assert_raise(LocalJumpError) do
x.instance_exec_with_block(proc{})
end
end
def test_extend
assert_raise(ArgumentError) do
1.extend
vm.c
return block_handler;
}
static VALUE
vm_yield_with_cref_and_block(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda, VALUE block_handler)
{
vm_block_handler_verify(block_handler);
return invoke_block_from_c_bh(ec, check_block_handler(ec),
argc, argv, block_handler,
cref, is_lambda, FALSE);
}
static VALUE
vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda)
{
vm_eval.c
static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv, enum method_missing_reason call_status);
static inline VALUE vm_yield_with_cref(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda);
static inline VALUE vm_yield_with_cref_and_block(rb_execution_context_t *ec, int argc, const VALUE *argv, const rb_cref_t *cref, int is_lambda, VALUE block_handler);
static inline VALUE vm_yield(rb_execution_context_t *ec, int argc, const VALUE *argv);
static inline VALUE vm_yield_with_block(rb_execution_context_t *ec, int argc, const VALUE *argv, VALUE block_handler);
static inline VALUE vm_yield_force_blockarg(rb_execution_context_t *ec, VALUE args);
......
/* block eval under the class/module context */
static VALUE
yield_under(VALUE under, VALUE self, int argc, const VALUE *argv)
yield_under(VALUE under, VALUE self, int argc, const VALUE *argv, VALUE passed_block)
{
rb_execution_context_t *ec = GET_EC();
rb_control_frame_t *cfp = ec->cfp;
......
}
cref = vm_cref_push(ec, under, ep, TRUE);
return vm_yield_with_cref(ec, argc, argv, cref, is_lambda);
return vm_yield_with_cref_and_block(ec, argc, argv, cref, is_lambda, passed_block);
}
VALUE
......
{
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, 1, &self);
return yield_under(klass, self, 1, &self, VM_BLOCK_HANDLER_NONE);
}
else {
VALUE file = Qundef;
......
rb_obj_instance_exec(int argc, const VALUE *argv, VALUE self)
{
VALUE klass = singleton_class_for_eval(self);
return yield_under(klass, self, argc, argv);
return yield_under(klass, self, argc, argv, VM_BLOCK_HANDLER_NONE);
}
/*
* call-seq:
* obj.instance_exec_with_block(arg..., proc) {|var..., &proc| block } -> obj
*
* Executes the given block within the context of the receiver
* (_obj_). In order to set the context, the variable +self+ is set
* to _obj_ while the code is executing, giving the code access to
* _obj_'s instance variables. The final argument is the proc to pass
* as the block argument to the block. Remaining arguments are passed
* as block parameters.
*
* class KlassWithSecret
* def initialize
* @secret = "a"
* end
* end
* k = KlassWithSecret.new
* k.instance_exec_with_block("b", 2, proc{|s| capitalize * 2}) do |x, y, &blk|
* @secret << x
* @secret.instance_exec(y, &blk)
* end #=> "AbAb"
*/
VALUE
rb_obj_instance_exec_with_block(int argc, const VALUE *argv, VALUE self)
{
VALUE block;
VALUE klass;
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
block = argv[--argc];
if (!rb_obj_is_proc(block)) {
rb_raise(rb_eTypeError, "last argument to instance_exec_with_block must be a Proc");
}
klass = singleton_class_for_eval(self);
return yield_under(klass, self, argc, argv, block);
}
/*
......
VALUE
rb_mod_module_exec(int argc, const VALUE *argv, VALUE mod)
{
return yield_under(mod, mod, argc, argv);
return yield_under(mod, mod, argc, argv, VM_BLOCK_HANDLER_NONE);
}
/*
......
rb_define_method(rb_cBasicObject, "instance_eval", rb_obj_instance_eval, -1);
rb_define_method(rb_cBasicObject, "instance_exec", rb_obj_instance_exec, -1);
rb_define_method(rb_cBasicObject, "instance_exec_with_block", rb_obj_instance_exec_with_block, -1);
rb_define_private_method(rb_cBasicObject, "method_missing", rb_method_missing, -1);
#if 1
    (1-1/1)