【问题标题】:Ruby self.extended gets called as instance methodRuby self.extended 被称为实例方法
【发布时间】:2020-08-23 10:55:33
【问题描述】:
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

=>没有方法错误

【问题讨论】:

  • 您可以使用extended 定义任意方法,但不能在该块中使用def。如果您需要动态执行此操作,您应该执行 base.define_method(...)

标签: ruby-on-rails ruby module class-method instance-methods


【解决方案1】:

也许我会明确说明我认为没有完全明确地向那些不熟悉 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 中?

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

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

解决方案:

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

【讨论】:

  • 如果你想创建一个“静态类方法”,你就这样做 - 严格来说并不准确,我写它只是因为你来自 java / c# 背景
  • 好的,所以我相信 def self.included(base),我不需要把 def base.cities 正确吗?
  • @noobyz 不正确:如果要创建静态类方法,则必须将:def base.cities 放入 def self.included(base)
  • 但我想当我们包含一个模块时,它会使所有函数成为包含它的类的实例,反之亦然,排除一个模块。也许我错过了 def self.included/self.excluded 的目的?
  • 确实如此,但您在代码中犯了一个错误。你在定义静态类方法时忘记了base这个词,这个词决定了一切。
【解决方案2】:

def bar 没有明确的definee(即def foo.bar)在最近的词法封闭模块中定义bar。对于所有三个defs,最接近的词法封闭模块始终是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?

【讨论】:

  • 在 def self.include 中呢?我需要像 def base.cities 一样做同样的事情吗?
猜你喜欢
  • 2021-12-11
  • 1970-01-01
  • 2016-07-29
  • 1970-01-01
  • 2011-08-27
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多