在另一个模块中扩展Ruby模块。

22

我正在尝试定义一些模块,以便轻松地向其他类添加一些实例方法和类方法,这是我的代码:

module Foo
  module Bar
    def speak
      puts "hey there"
    end
  end
  module Baz
    extend Foo::Bar

    def welcome
      puts "welcome, this is an instance method"
    end
  end
end

class Talker
  include Foo::Baz
end

Talker.new.welcome
Talker.speak
这的输出结果是:
welcome, this is an instance method
undefined method 'speak' for Talker.class (NoMethodError)

我原本期望Talker有'speak'方法,因为它包含了扩展了Foo::Bar的Foo::Baz类。

我漏掉了什么?


如果我将Baz从模块改为类,并将Talker更改为子类化Baz,那么我的示例就可以工作。但是,是否有可能在不将Baz变成类的情况下完成我想做的事情?(而且不必像Talker :: Foo :: Bar.speak这样做某些事情吗?) - codecraig
2个回答

25

您可以尝试这样做:

module Baz
  extend Foo::Bar

  def self.included(base)
    base.send :extend, Foo::Bar
  end

  def welcome
    puts "welcome, this is an instance method"
  end
end

这将自动扩展所有包含Baz的类。

PS:

extend Foo::Barmodule Baz 中是原始代码片段中的内容,此代码对方法 def self.included(base) 没有影响。


1
为什么要扩展Foo::Bar?一个是内部包含,一个是外部。 - shajin
1
第一个扩展将从Foo::Bar添加类级别的方法到Baz。第二个扩展将从Foo::Bar添加方法到所有包含Baz的类和模块中。 - Viacheslav Molokov
我仍然不明白在这种情况下或者其他任何情况下extend Foo::Bar有什么用处。 - Evgenia Karunus
原始的代码片段中有extend Foo::Bar,但我决定将其保留在这里。实际上,在这种情况下并不必要。我会更新我的答案。 - Viacheslav Molokov

4

试试这个:

class Talker
   extend Foo::Baz
end

由于您想将Talker.speak作为类方法而不是实例方法进行调用(如Talker.new.speak),因此必须以某种方式包含Foo:Baz,使类本身接受这些方法。

一种可能性是使用'extend'(如上所述),另一种是修改其特殊类:

class Talker
  class << self
    include Foo::Baz
  end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接