Forwardable Module
Forwardable module is able to give new behaviour to an object by delegating the method to it, using def_delegator
or def_delegators
.
Let’s say we have this
class HousingUnit
attr_reader :example
def initialize
@example = [:apartment, :flat, :residence]
end
end
newhouse = HousingUnit.new
puts "This year I'm gonna get myself new #{newhouse.example.sample}!"
This will return This year I'm gonna get myself new apartment!
as sample method will return random element from the array. However, it will be more readable if we have a method that can return the random element directly.
class HousingUnit
attr_reader :example
def initialize
@example = [:apartment, :flat, :residence]
end
def type
@example.sample
end
end
newhouse = HousingUnit.new
puts "This year I'm gonna get myself new #{newhouse.type}!"
This will give us This year I'm gonna get myself new residence!
. Perfect! The HousingUnit#type
has power to access the housing unit example type.
Fast forward, Ruby provides a way to perform this kind of action by using def_delegator
. To use it, we have to use keyword extend to add module method at class level. Then, we need to define the delegator method. The formula is
def_delegator :an_instance, :the_delegated_method, :the_alias_method
like this one
require 'forwardable'
class HousingUnit
extend Forwardable
attr_reader :example
def_delegator :@example, :sample, :type
def initialize
@example = [:apartment, :flat, :residence]
end
# def type
# @example.sample
# end
end
newhouse = HousingUnit.new
puts "This year I'm gonna get myself new #{newhouse.type}!"
This will give us This year I'm gonna get myself new residence!
. Note that I’m calling forwardable library here to be able to use the method.
How about def_delegators?
In whole view it works similar like def_delegator
. The difference is def_delegators
able to handle multiple methods but those methods can’t have alias name of method.
require 'forwardable'
class HousingUnit
extend Forwardable
attr_reader :example
def_delegators :@example, :sample, :size
def initialize
@example = [:apartment, :flat, :residence]
end
end
newhouse = HousingUnit.new
puts "Total number of housing unit types: #{newhouse.size} "
puts "Random example of housing unit: #{newhouse.sample}"
This will produce
Total number of housing unit types: 3
Random example of housing unit: apartment