views:

144

answers:

2

Is it possible to change the binding of a procedure during invocation time?

class AllValidator
  def age_validator
    Proc.new {|value| self.age > value }
  end
end

class Bar
  attr_accessor :age
  def doSomething
    validator = AllValidator.new.age_validator
    validator.call(25) # How to pass self as the binding?
  end
end

In the code above how do I change the binding of the proc during invocation? Is there a way to pass the binding much like the eval function?

Note If the example above were real, I would use mixin/inheritence etc. I am using the code to demonstrate my problem scenario.

A: 

Why not pass self as a parameter when you create the closure?

class AllValidator
  def age_validator this
    Proc.new {|value| this.age > value }
  end
end
  validator = AllValidator.new.age_validator self
  validator.call 5
jleedev
I don't have access to `age_validator`. Hence I cant add an extra parameter.
KandadaBoggu
+3  A: 

You can use instance_eval:

class Bar
  def do_something
    validator = AllValidator.new.age_validator

    # Evaluate validator in the context of self.
    instance_eval &validator
  end
end

If you want to pass arguments (as mentioned in the comment below), you can use instance_exec instead of instance_eval if you use Ruby 1.9 or Ruby 1.8.7:

class Bar
  def do_something
    validator = AllValidator.new.age_validator

    # instance_exec is like instance_eval with arguments.
    instance_exec 5, &validator
  end
end

If you have to make it work with Ruby 1.8.6 and below as well, your best bet is to bind the proc as a method of Bar:

class Bar
  def do_something
    self.class.send :define_method, :validate, &AllValidator.new.age_validator
    self.validate 5
  end
end

An alternative is to implement instance_exec older Ruby versions (example here). All it does is define a method before calling it, and undefining it after you're done.

molf
Does that let you pass an argument to `validator`?
jleedev
`instance_eval` has a sister method that lets you do that, see update above.
molf
+1 Thanks for the detailed answer.
KandadaBoggu