I have used module to extend class functionality. But suddenly I wonder if it is ok if I include a module directly into a method of the class instead of into the class like this:
Original use:
model:
class Baby
include CommunicationSkills
def initialize(name)
@name = name
end
end
module:
module CommunicationSkills
def greet
"Hi"
end
end
so we can:
ivan = Baby.new('Iván')
ivan.greet
=> "Hi"
but what if I include the method inside a method directly:
class Baby
def initialize(name)
@name = name
end
def greet(language)
extend GreetLanguages
send(language)
end
end
module:
module GreetLanguages
def spanish
"Hola"
end
def english
"Hi"
end
end
so:
ivan = Baby.new('Iván')
ivan.greet('spanish')
=> "Hola"
ivan.greet('english')
=> "Hi"
I know that this is posible, but conceptually it is right?
The module contains two instance methods. You want to send them to an instance, not to the class, so you need to include
the module (using Module#include), not extend
it. To invoke include
from within an instance method (self
being the instance), you must send include
to self.class
. You therefore need to write the following.
class Baby
def initialize(name)
@name = name
end
def greet(language)
self.class.include GreetLanguages
send(language)
end
end
ivan = Baby.new('Iván')
ivan.greet('spanish')
#=> "Hola"
Baby.instance_methods.include?(:english) &&
Baby.instance_methods.include?(:spanish)
#=> true
ivan.greet('english')
#=> "Hi"
You can alternatively write ivan.greet(:spanish)
.
You would use Object#extend if you wanted to convert the instance methods in the module to class methods when you bring them into the class.
class Baby
def initialize(name)
@name = name
end
def extend_mod
self.class.extend GreetLanguages
end
end
Baby.new('Iván').extend_mod
Baby.methods.include?(:spanish) &&
Baby.methods.include?(:english)
#=> true
Baby.spanish
#=> "Hola"
Baby.english
#=> "Hi"
Here self.class.extend GreetLanguages
is equivalent to self.class.singleton_class.include GreetLanguages
.