Delegate method in ruby
There a manner with which we can deflect a work that has been provided to an object to another object. This is known as
delegation of method, which is used to hide implementation details as well as not raise an error whenever an object
is asked to do something which isn’t natively defined in itself.
Let us look at an example.
Let us assume there’s a Building class and a subsequent Door class that is initialized when an object of Building is created.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| class Building
def initialize
@door = Door.new
end
end
class Door
def initialize
@state = "open"
end
def close
@state = "close"
end
def open
@state = 'open'
end
end
building = Building.new
|
Now, as we can tell, a call to the method close from the building object building.close
will raise a NoMethodError.
We can delegate the method to Door class, as it contains the method open that we want to call. Let’s open the class
Building and patch in a method:
1
2
3
4
5
| class Building
def close
@door.close
end
end
|
Now, calling the method close, Building.close
produces desired output. Here, the method close for Building class is
a delegator method.
Different approaches to delegating methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| require 'forwardable'
class Building extend Forwardable
def_delegators :@door, :close, :open
def initialize
@door = Door.new
end
class Door
def initialize
@state = "open"
end
def close
@state = "close"
end
def open
@state = 'open'
end
end
building = Building.new
building.close
|
Here, the delegator method takes in arguments,namely the object we are delegating to and the delegate methods
- Using method missing
eg: from class reach to reachable
1
2
3
4
5
6
7
8
9
| class Reach
def method_missing(method, *args)
if reachable.respond_to?(method)
reachable.send(method, *args)
else
super
end
end
end
|
- Define each method that we want to delegate
eg: from class reach to reachable
1
2
3
4
5
6
7
| class Reach
[:all, :my, :methods, :here].each do |m|
define_method(m) do |*args|
reachable.send(m, *args)
end
end
end
|
- Using ActiveSupport delegate module extension in rails
1
2
3
4
5
6
7
| class Door
belongs_to :building
end
class Building
has_many :windows
end
|
if we want to class door.name to return the name of the building associated to the given door, instead of creating a method
that returns the name of the building, we can simply use the delegate method as:
1
2
3
4
| class Door
belongs_to :building
delegate :name, to: :building
end
|