Adam Adam - 6 months ago 7
Ruby Question

Passing a method that takes arguments as an argument in Ruby

I'd like to calculate the difference for various values inside 2 hashes with the same structure, as concisely as possible. Here's a simplified example of the data I'd like to compare:

hash1 = {"x" => { "y" => 20 } }
hash2 = {"x" => { "y" => 12 } }


I have a very simple method to get the value I want to compare. In reality, the hash can be nested a lot deeper than these examples, so this is mostly to keep the code readable:

def get_y(data)
data["x"]["y"]
end


I want to create a method that will calculate the difference between the 2 values, and can take a method like
get_y
as an argument, allowing me to re-use the code for any value in the hash. I'd like to be able to call something like this, and I'm not sure how to write the method
get_delta
:

get_delta(hash1, hash2, get_y) # => 8

Answer

The "Ruby way" would be to pass a block:

def get_delta_by(obj1, obj2)
  yield(obj1) - yield(obj2)
end

hash1 = {"x" => { "y" => 20 } }
hash2 = {"x" => { "y" => 12 } }

get_delta_by(hash1, hash2) { |h| h["x"]["y"] }
#=> 8

A method could be passed (indirectly) via:

def get_y(data)
  data["x"]["y"]
end

get_delta_by(hash1, hash2, &method(:get_y))
#=> 8
Comments