Question

Given this code:

a = {1=>2}
m = a.method(:[])

I know that I can now use :

value = m.call(1)

and it will return 2. The thing is, what do I need to change so that I can call the method directly like :

m.call()

and it will get the 1 sent as a parameter? It would be nice to be able to write something like :

m = a.method(:[],1) # where the symbol is the method, and 1 will be the parameter it will be called with

The thing is, I'd like to delay the execution of certain parts of my script until some objects get created, and I'd like to avoid rewriting EVERYTHING to use lambdas.

Was it helpful?

Solution

Basically, what you want is a way to curry the function.

http://en.wikipedia.org/wiki/Curry_function

This can be done in many different ways, one of which:

def curry(method, *params)
  lambda { send method, *params }
end

You can add this to Hash's metaclass, or to a module you want to include in some of your objects, etc. Then, calling it becomes the usecase you wanted:

irb(main):001:0> a = {1 => 2}
=> {1=>2}
... # add curry to Hash's metaclass
irb(main):011:0> m = a.curry :[], 1
=> #<Proc:0xb76e2154@(irb):8>
irb(main):012:0> m.call
=> 2

OTHER TIPS

There's more than one way to do it, I'm sure.

a = {1=>2}

class << a
  def fetch_what(key)
    Proc.new { self[key] }
  end
end

....

m = a.fetch_what(1)
m.call()  # -> 2

It sounds like you should attach the method parameters to the object you're calling the method on, and have the method access them as instance variables.

In terms of simple refactoring steps:

  • Introduce new instance variables, one per method parameter.
  • Introduce new accessors for the instance variables.
  • Refactor the method to use the instance variables if the parameters are not supplied.
  • Refactor the calling code to set the instance variables through the accessors, at some point prior to the method call.
  • Refactor the calling code to pass no parameters in the method call.

As an example, refactor calling code like this:

widget = Widget.new
assembly_method = widget.method(:assemble)
# Time passes...
assembly_method.call(:electric, :smooth)

to work like this:

widget = Widget.new
widget.frombulator = :electric
widget.jazzifier = :smooth
assembly_method = widget.method(:assemble)
# Time passes...
assembly_method.call

It's not sexy or clever, but it will result in code that expresses its intent, and odds are good that it will address the real problem, namely that something is missing from your model.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top