如何从 Ruby 中的实例方法访问模块?

How do I access a module from an instance method in Ruby?

假设我有一个模块:

module M
  def self.foo
    ...
  end

  def bar
    ...
  end
end

模块 M 包含在 class 中。

class A
  include M
end

我想从 bar 调用 foo,它最终将在 A 的实例上调用。在 bar 中执行此操作的最佳方法是什么?

当然我可以直接说M.foo,但这是模块名称的重复,感觉没有必要。

不是很优雅,但是

def bar
  Module.nesting.last.foo
end

应该这样做。

请注意,Module#nesting returns 一个数组,因为一个模块可能嵌套到另一个模块中。在一般情况下,您需要应用正确的数组索引来选择您想要的模块。

通常,在 module 中,将 class 方法和实例方法分开是一个很好的做法,如下所示:

module M
  def bar
    puts "BAR"
    self.class.foo
  end

  module ClassMethods
    def foo
      puts "FOO"
    end
  end
end

现在,在 class 中,我希望 include 这个模块 M 的方式是 A.foo 作为 class 方法和 A.new.bar 作为实例方法。诀窍是 Module.included

module M
  def bar
    puts "BAR"
    self.class.foo
  end

  module ClassMethods
    def foo
      puts "FOO"
    end
  end

  # when module is included, extend the class with ClassMethods
  def self.included(base)
    base.extend ClassMethods
  end
end

class A
  include M
end

A.singleton_methods #=> [:foo]

A.new.foo
#=> BAR
#=> FOO

通过这种方法,您可以使用 self.class 引用 class 方法,它会自动起作用。

希望对您有所帮助。

我认为使用 M.foo 是最好的,但作为练习,可以按如下方式更改 M#bar

module M
  def self.foo
    puts "In self.foo"
  end

  def bar
    puts "In bar"
    method(__method__).owner.foo
  end
end

class A
  include M
end

a = A.new
a.bar
  # In bar
  # In self.foo