Feature #14914
closedAdd BasicObject#instance_exec_with_block
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