diff --git a/CHANGELOG.md b/CHANGELOG.md index 0793ef9e34dd..a029c1de3375 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug fixes: * Default `close_others` in `Process.exec` to false like Ruby 2.6 (#1798, @XrXr). * Don't clone methods when setting method to the same visibility (#1794, @XrXr). * BigDecimal() deal with large rationals precisely (#1797, @XrXr). +* Make it possible to call `instance_exec` with `rb_block_call` (#1802, @XrXr). Compatibility: diff --git a/lib/truffle/truffle/cext.rb b/lib/truffle/truffle/cext.rb index 8becd8f49be4..5e222da9271b 100644 --- a/lib/truffle/truffle/cext.rb +++ b/lib/truffle/truffle/cext.rb @@ -1512,12 +1512,13 @@ def send_splatted(object, method, args) end def rb_block_call(object, method, args, func, data) + outer_self = self object.__send__(method, *args) do |*block_args| TrufflePrimitive.cext_unwrap(TrufflePrimitive.call_with_c_mutex(func, [ TrufflePrimitive.cext_wrap(block_args.first), data, block_args.size, # argc - RARRAY_PTR(block_args), # argv + outer_self.RARRAY_PTR(block_args), # argv nil, # blockarg ])) end diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index 63a2ff843273..e98ae35067df 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -59,6 +59,14 @@ VALUE kernel_spec_rb_block_call_multi_arg(VALUE self, VALUE ary) { return rb_block_call(ary, rb_intern("inject"), 1, method_args, block_call_inject_multi_arg, Qnil); } +static VALUE return_extra_data(RB_BLOCK_CALL_FUNC_ARGLIST(yield_value, extra_data)) { + return extra_data; +} + +VALUE rb_block_call_extra_data(VALUE self, VALUE object) { + return rb_block_call(object, rb_intern("instance_exec"), 0, NULL, return_extra_data, object); +} + VALUE kernel_spec_rb_block_call_no_func(VALUE self, VALUE ary) { return rb_block_call(ary, rb_intern("map"), 0, NULL, NULL, Qnil); } @@ -304,6 +312,7 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_block_call", kernel_spec_rb_block_call, 1); rb_define_method(cls, "rb_block_call_multi_arg", kernel_spec_rb_block_call_multi_arg, 1); rb_define_method(cls, "rb_block_call_no_func", kernel_spec_rb_block_call_no_func, 1); + rb_define_method(cls, "rb_block_call_extra_data", rb_block_call_extra_data, 1); rb_define_method(cls, "rb_block_proc", kernel_spec_rb_block_proc, 0); rb_define_method(cls, "rb_block_lambda", kernel_spec_rb_block_lambda, 0); rb_define_method(cls, "rb_frame_this_func_test", kernel_spec_rb_frame_this_func, 0); diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index d123eb13ea9f..32cdd3f4218a 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -53,6 +53,11 @@ i + 1 end.should == [2, 4, 6] end + + it "can pass extra data to the function" do + ary = [3] + @s.rb_block_call_extra_data(ary).should equal(ary) + end end describe "rb_frame_this_func" do