In OO design using composition is considered preferable to class inheritance. In the ruby world this is especially true because ruby only allows for single inheritance.
Using composition can lead to some vary ugly looking method chains where an Object is traversing its way through the multiple objects that it is composed of.
For example: from my_object you might need to access property_x that lives nested object two objects away.
You can chain a bunch of calls together and get there. Traversing objects this way is a bit off-putting. Also if you are doing this in one spot you are probably doing it in more than one spot and that is potentially error prone.
Passing a method call from one object to another to do the work is a common thing to want to do so the ruby standard library gives us the Forwardable module. Using Forwardable allows ruby to delegate a method called on ObjectA to another object ObjectB.
A Simple Example
Starting with a From and a To class
@to = To.new
@count = 0
self.count += 1
We can create a new From object and get to the count parameter and inc methods through the To object.
$ from = From.new
It would be better to be able to call from.count and get the count and from.inc to increment the count. This is easily done by extending the Forwardable module in our From class.
def_delegators :@to, :count, :inc
Now from the console we can do this
What if instead of count I wanted to call the method total?
That is easy. def_delegators allows us to pass an object and any number of method calls we want to delegate and it uses the existing method name to do it. Using def_delegator we have to do them one method at a time but we have the option of giving methods aliases.
def_delegator :@to, :count, :total
def_delegator :object, :method, :alias=method
def_delegator the :alias parameter is optional. If there is no alias parameter given it defaults to using the given method.
Double Delegating: a more complex example
How about delegating to a nested object? In this example we have a store that goes through a middleman to access the inventory of a warehouse. Standard chaining to get the inventory would look like this:
Instead of going through the chain and calling inventory it would be better to be able to call something directly on the Store object to get the information. Also calling store.inventory could easily be confusing to someone new coming in to the code. Something like .in_warehouse would be more descriptive of what the value getting returned actually is.
To be able to call .in_warehouse we need to do two delegations.
First from MiddleMan into Warehouse to expose inventory. Second from Store into MiddleMan to access inventory and alias it as in_warehouse.
@middle_man = MiddleMan.new
def_delegator :@middle_man, :inventory, :in_warehouse
@warehouse = Warehouse.new
def_delegator :@warehouse, :inventory
@inventory = 100
Bringing it all together
$ store = Store.new