Project

General

Profile

Feature #14914

Add BasicObject#instance_exec_with_block

Added by jeremyevans0 (Jeremy Evans) almost 2 years ago. Updated almost 2 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:87957]

Description

Currently, you cannot use instance_exec with a block that requires a block argument. If you have a block that requires a block argument and you want to get the equivalent of instance_exec, you have to do something like:

singleton_class.define_method(:temporary_method_name, &block)
send(:temporary_method_name, *args, &block_arg)
singleton_class.remove_method(:temporary_method_name)

That approach doesn't work for frozen objects, making it impossible to get the equivalent of instance_exec for a frozen object if you have a block that requires a block argument.

The attached patch implements instance_exec_with_block, which is the same as instance_exec, except the last argument must be a Proc which is passed as the block argument instead of the regular argument to the block.

1.instance_exec_with_block(42, 2, proc{|x| self * x}) do |a, b, &blk|
  (self + a).instance_exec(b, &blk)
end
# => 86

This method cannot be implemented in a gem because it requires changes to vm.c and vm_eval.c to implement. There wasn't a function allowing you to provide both a cref and a block argument when evaluating a block (hence the addition of vm_yield_with_cref_and_block in the patch).

There are alternative APIs that could support this feature. One approach would be adding support for :args and :block_arg keyword arguments to instance_eval (if no regular arguments are given).


Files

Also available in: Atom PDF