0.0
No commit activity in last 3 years
No release in over 3 years
instance_exec can't pass block arguments through. Use a bindable block instead (there is also an optional core extension instance_exec_b, which will mimic the instance_exec interface, but also allow you to pass the block).
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 3.0.0, ~> 3.0
 Project Readme

BindableBlock

instance_exec can't take block arguments. Get around that with BindableProc (also provides optional BasicObject#instance_exec_b)

If you understand that previous statement, then I probably can't dissuade you from using this. If you don't, then a word of warning: This is probably the wrong solution. instance_exec is probably the wrong solution too. Metaprogramming is almost never merited. It's lighting your way by setting yourself on fire. Your problem will be simpler if you don't use it. It will be more comprehensible. You'll waste less time later trying to figure out how to get it to do what you want. 95% of the times I've used metaprogramming, I've later regretted it. The whole use-case that led to the creation of this gem was wrong, it was unnecessary, it added tremendous complexity to the implementation. Think Rails moving from find_by_name(name) to find_by(name: name), and how much better that was.

BUT! If I still can't convince you, then read on:

require 'bindable_block'

User = Struct.new :name
greeter = BindableBlock.new { "Welcome, #{name}" }
greeter.bind(User.new "Josh").call # => "Welcome, Josh"
require 'bindable_block/instance_exec_b'

# http://rdoc.info/stdlib/core/BasicObject:instance_exec
class KlassWithSecret
  def initialize
    @secret = 99
  end
end
k           = KlassWithSecret.new
sum         = 10
sum_updater = lambda { |to_add| sum += to_add }
result      = k.instance_exec_b(5, sum_updater) { |x, &b| b.call(@secret+x) } # => 114
sum # => 114

Here is an example. Note that it is the old-style where users had to submit the class that could be bound to.

Possible advances in usefulness

It just occurred to me that if we bound it to BasicObject then it could be used on any class without the user needing to specify which class they want to bind it to.

Where the abstraction leaks

Bindable block does something that isn't possible in Ruby. It does this with black magick. Unfortunately, that abstraction will leak in the case of return statements. Return statements in blocks will return you from the containing method.

def meth
  Proc.new { return 1 }.call
  2
end

meth # => 1

Return statements in lambdas will return you from the lambda.

def meth
  lambda { return 1 }.call
  2
end

meth # => 2

You would expect a bindable block to continue to behave like the former example, but it will actually behave like the latter example.

At present, I can only think of two ways to fix this:

  1. It might be possible to rewrite the AST with ripper.
  2. It is probably possible to write this in C.

Neither of these are high on my priority list.

Installation

Add this line to your application's Gemfile:

gem 'bindable_block'

And then execute:

$ bundle

Or install it yourself as:

$ gem install bindable_block