Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic method chain?

Tags:

ruby

How can I call a nested hash of methods names on an object?

For example, given the following hash:

hash = {:a => {:b => {:c => :d}}}

I would like to create a method that, given the above hash, does the equivalent of the following:

object.send(:a).send(:b).send(:c).send(:d)

The idea is that I need to get a specific attribute from an unknown association (unknown to this method, but known to the programmer).

I would like to be able to specify a method chain to retrieve that attribute in the form of a nested hash. For example:

hash = {:manufacturer => {:addresses => {:first => :postal_code}}}
car.execute_method_hash(hash)
=> 90210
like image 382
joshblour Avatar asked Jan 02 '14 11:01

joshblour


People also ask

Can append method be chained?

append is a bit of a special case for method chaining because it creates a new element and returns a selection to it. In most cases methods that operate on an object will return the same object being operated on.

What do you mean by method chaining?

Method chaining, also known as named parameter idiom, is a common syntax for invoking multiple method calls in object-oriented programming languages. Each method returns an object, allowing the calls to be chained together in a single statement without requiring variables to store the intermediate results.

What is method chain in Java?

Method Chaining is the practice of calling different methods in a single line instead of calling other methods with the same object reference separately. Under this procedure, we have to write the object reference once and then call the methods by separating them with a (dot.).


1 Answers

I'd use an array instead of a hash, because a hash allows inconsistencies (what if there is more than one key in a (sub)hash?).

object = Thing.new
object.call_methods [:a, :b, :c, :d]

Using an array, the following works:

# This is just a dummy class to allow introspection into what's happening
# Every method call returns self and puts the methods name.
class Thing
  def method_missing(m, *args, &block)
    puts m
    self
  end
end

# extend Object to introduce the call_methods method
class Object
  def call_methods(methods)
    methods.inject(self) do |obj, method|
      obj.send method
    end
  end
end

Within call_methods we use inject in the array of symbols, so that we send every symbol to the result of the method execution that was returned by the previous method send. The result of the last send is automatically returned by inject.

like image 89
tessi Avatar answered Sep 19 '22 12:09

tessi