Ruby self.extended 作为实例方法被调用

Ruby self.extended gets called as instance method

module Country
  def location
    puts "location"
  end

  def self.included(base)
    def cities
      puts "cities"
    end
  end

  def self.extended(base)
    def animals
      puts "animals"
    end
  end
end

class Test
  include Country
end

class Test2
  extend Country
end

据我了解,self.included 将在模块作为实例方法包含时调用,而 self.extended 将在模块扩展为静态时调用 class方法。

但是当我在同一个文件中有两个 class 时,为什么它没有抛出错误

Test.new.animals

=>动物

如果我删除了测试 2 class,

 # class Test2
  # extend Country
# end

Test.new.animals

=>没有方法错误

def bar 没有明确的 definee(即 def foo.bar)在最近的词法封闭模块中定义 bar。所有三个 def 的最接近词法封闭模块始终是 Country,因此所有三个方法都在 Country 模块中定义。

如果你想定义一个单例方法,你可以使用

module Country
  def self.extended(base)
    def base.animals
      puts "animals"
    end
  end
end

有关详细信息,请参阅

也许我会向那些不熟悉 Ruby 的“Object Model”的人明确说明我认为没有完全和明确地解决 Jorg 漂亮的回答(怀着最大的敬意):

module Country
  def location
    puts "location"
  end

  def self.included(base)
    def cities
      puts "cities"
    end
  end

  def self.extended(base)

    puts "#{self}"  ## NOTICE THIS NEW LINE! NEW LINE

    def animals
      puts "animals"
    end
  end
end


class Test
  include Country
end

class Test2
  extend Country
end

Test.new.animals

有什么问题?

我们正在扩展 Test2,不是吗?那么 animals 方法是如何定义的 在测试 1 中?

关键是在 animals 方法上面添加 puts "#{self} 行。

我们可以看到这里的animals方法是在Country中定义的 模块。所以真的,当你认为你正在扩展时,它,你在 事实上确保它被添加为实例方法,而不是 "static class method"(如果您来自 c#/java 背景)。严格来说,这并不准确:当你像这样 "extending" - 如果你做对了 - 你实际上是在添加方法 到 Test2 的单例 class。 Ruby 的对象模型在这方面有点棘手。静态 class 方法是添加到 class 的单例 class 的方法。什么是单例class?现在您正在进入 ruby 的对象模型。它很复杂,有点耗费人才,但一旦你掌握了它,你就可以做一些非常强大(而且危险?)的事情,比如:猴子修补。

解决方案:

Jorg 说得比我好。你需要这样定义动物:def base.animals.