Ruby self.extended被称为实例方法

问题描述 投票:0回答:2
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。

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

Test.new.animals

=>动物

并且如果我删除了Test 2类,

 # class Test2
  # extend Country
# end

Test.new.animals

=>没有方法错误

ruby-on-rails ruby module class-method instance-methods
2个回答
3
投票
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 what class gets a method when there is no explicit receiver?以获取更多详细信息。

0
投票
也许我会向那些不太熟悉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,不是吗?那如何定义动物方法在Test1中?

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

我们可以在此处看到动物方法是在国家/地区中定义的模块。所以说真的,当您认为自己正在扩展时,就意味着确保将其添加为实例方法,而不是添加“静态类方法”(如果您来自c#/ java背景)。严格来说,这不是准确的:当您像这样“扩展”时-如果您做得正确-实际上是在添加方法到Test2的单例类。在这方面,Ruby的对象模型有些棘手。静态类方法是添加到类的单例类中的方法。什么是单身人士班?现在,您将进入ruby的对象模型。它很复杂并且有点人才流失,但是一旦掌握了它,就可以做一些非常有力的(而且是危险的?)事情,例如:猴子修补。

解决方案:

Jorg说比我更好。您需要像这样定义动物:def base.animals

© www.soinside.com 2019 - 2024. All rights reserved.