2016-09-21 88 views
2

我已经使用模块来扩展类功能。但突然间我不知道它是确定的,如果我直接包括模块插入类的方法,而不是为这样的类:将模块包含到方法ruby中

原来使用:

型号:

class Baby 
    include CommunicationSkills 

    def initialize(name) 
    @name = name 
    end 
end 

模块:

module CommunicationSkills 
    def greet 
    "Hi" 
    end 
end 

所以我们可以:

ivan = Baby.new('Iván') 
ivan.greet 
=> "Hi" 

但如果我有直接的方法里面的方法:

class Baby 

    def initialize(name) 
    @name = name 
    end 

    def greet(language) 
    extend GreetLanguages 
    send(language) 
    end 
end 

模块:

module GreetLanguages 
    def spanish 
    "Hola" 
    end 

    def english 
    "Hi" 
    end 
end 

这样:

ivan = Baby.new('Iván') 
ivan.greet('spanish') 
=> "Hola" 
ivan.greet('english') 
=> "Hi" 

我知道这是更多钞票,但在概念上它是对?

+0

我不能重现这一点。 –

+0

我在include行发现错误:'> ivan.greet('spanish') NoMethodError:undefined方法'include'for#' – Ryan

+0

是的,关于@ davidhu2000我更新了代码。对不起。 –

回答

0

该模块包含两个实例方法。你想把它们发送给一个实例,而不是类,所以你需要include该模块(使用Module#include),而不是extend它。要从实例方法(实例为self)内调用include,必须将include发送到self.class。因此您需要编写以下内容。

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" 

您也可以写ivan.greet(:spanish)

如果您希望将模块中的实例方法转换为类方法,并将它们带入类中,则可以使用Object#extend

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" 

是不寻常的,从一个实例方法中调用includeextend。我不知道为什么要这样做。

0
module GreetLanguages 
    def spanish 
    "Hola" 
    end 

    def english 
    "Hi" 
    end 
end 

class Baby 

    def initialize(name) 
    @name = name 
    end 

    def greet(language) 
    extend GreetLanguages 
    send(language) 
    end 
end 

所以,我设法使用extend得到这个代码工作。此外,在您的send函数中,您需要删除引号,因为您没有发送字符串"language",所以发送代表字符串"spanish""english"的变量语言。

因此,include没有直接的接收器,所以它基本上调用它在self。当您在类Baby的实例方法中使用include时,您正在将模块添加到ivan的实例,这没有任何意义。

extend将该模块添加为类方法,因此实例本身可以调用该方法。所以,我们将模块添加到ivan的实例中,现在我们可以调用greet

我真的看不出有什么理由要这样做,所以最好在课堂上使用include

+0

'greet'方法在'Baby'的一个实例上抛出一个错误。 –

+0

错误是什么?并告诉我你的代码 – davidhu2000

+0

我打电话给'问候(西班牙语)',我得到的错误是:未定义的局部变量或方法'西班牙语为主:对象(NameError)'。 –