【问题标题】:Ruby extend & include tracing codeRuby 扩展并包含跟踪代码
【发布时间】:2018-09-30 15:10:09
【问题描述】:

我对使用“include”与“extend”感到困惑,在搜索了几个小时后,我得到的只是模块方法与包括模块在内的类的实例一起使用,以及在类扩展时与类本身一起使用的模块方法这些方法的模块。

但这并没有帮助我弄清楚,为什么在注释“#extend Inventoryable”中的扩展模块行时这段代码会出错 在取消注释时工作,这是代码

module Inventoryable

    def create(attributes)
      object = new(attributes)
      instances.push(object)
      return object
    end

    def instances
      @instances ||= []
    end

  def stock_count
    @stock_count ||= 0
  end

  def stock_count=(number)
    @stock_count = number
  end

  def in_stock?
    stock_count > 0
  end
end

class Shirt
  #extend Inventoryable
  include Inventoryable
  attr_accessor :attributes

  def initialize(attributes)
    @attributes = attributes
  end
end

 shirt1 = Shirt.create(name: "MTF", size: "L")
 shirt2 = Shirt.create(name: "MTF", size: "M")
 puts Shirt.instances.inspect

输出是

store2.rb:52:in `<main>': undefined method `create' for Shirt:Class (NoMethodError)

当取消注释“扩展 Inventoryable”以使代码工作时:

module Inventoryable

    def create(attributes)
      object = new(attributes)
      instances.push(object)
      return object
    end

    def instances
      @instances ||= []
    end

  def stock_count
    @stock_count ||= 0
  end

  def stock_count=(number)
    @stock_count = number
  end

  def in_stock?
    stock_count > 0
  end
end

class Shirt
  extend Inventoryable
  include Inventoryable
  attr_accessor :attributes

  def initialize(attributes)
    @attributes = attributes
  end
end

 shirt1 = Shirt.create(name: "MTF", size: "L")
 shirt2 = Shirt.create(name: "MTF", size: "M")
 puts Shirt.instances.inspect

使代码工作并输出以下内容

[#<Shirt:0x0055792cb93890 @attributes={:name=>"MTF", :size=>"L"}>, #<Shirt:0x0055792cb937a0 @attributes={:name=>"MTF", :size=>"M"}>] 

这有点令人困惑,但我只需要知道,为什么我需要扩展模块以避免错误?以及如何编辑此代码以使其在没有扩展方法的情况下工作? ,代码中还剩下什么依赖于扩展?

【问题讨论】:

    标签: ruby-on-rails ruby include extend


    【解决方案1】:

    当您extend 一个模块时,该模块中的方法将成为“类方法”**。因此,当您 extend Inventoryable 时,create 将作为 Shirt 类上的方法使用。

    当您include 一个模块时,该模块中的方法将成为“实例方法”**。因此,当您 include Inventoryable 时,createShirt 类上不可用(但 Shirt 的实例上可用)。

    要在使用include 时使Shirt 类中的create 可用,您可以使用included 挂钩。这可能看起来像:

    module Inventoryable
      module ClassMethods
    
        def create
          puts "create!"
        end
    
      end
    
      module InstanceMethods
    
      end
    
      def self.included(receiver)
        receiver.extend ClassMethods
        receiver.include InstanceMethods
      end
    end
    

    如果你这样做:

    class Shirt
      include Invetoryable
    end
    

    你可以这样做:

    > Shirt.create
    create!
     => nil 
    

    ** 人群中的 ruby​​ 纯粹主义者会正确地指出,在 ruby​​ 中,一切都是实例方法,并且没有类方法。这在形式上是 100% 正确的,但我们将在这里使用 classinstance 方法的口语含义。

    【讨论】:

    • 很高兴它成功了。你很快就会像疯狗一样进行元编程。
    • 我想声明,我是那些喜欢指出 Ruby 中没有类方法之类的东西的 Ruby 纯粹主义者之一。不过,我完全可以通俗地使用术语类方法只要各方完全理解这是一种通俗用法。换句话说,如果您知道没有类方法这样的东西,并且术语“类方法”只是“作为实例的对象的单例类的实例方法”的缩写Class",那么就没有问题了。但除此之外,我只看到它阻碍了理解。
    • Ruby 确实比许多人想象的要简单得多,我相信在没有人为区分的地方引入人为区分是原因之一。
    • 很高兴再次见到你,Jörg W Mittag!
    【解决方案2】:

    当你在一个类中扩展一个模块时,你会得到模块的方法作为类方法公开,但是如果你包含模块,那么你会得到模块的方法作为实例方法,在你的例子中你可以调用create Inventoryable 类的方法,您需要使用 Shirt 类的实例调用它(如果包含模块)

    shirt1 = Shirt.new(attributes).create(attributes)
    

    如果没有更多信息,我无法判断您要做什么,但您需要重新设计 initializecreate 方法来决定在这些方法中的位置或操作。

    我会尝试用一个简单的例子来解释它

    module A
      def test
        puts "ok"
      end
    end
    
    class B
      include A
    end
    
    class C
      extend A
    end
    
    puts C.test # here you invoke the method against the class itself
    puts B.new.test #here you create an instance to do it
    

    希望对你有帮助。

    【讨论】:

    • 感谢您的帮助,在将代码编辑成这样之后... shirt1 = Shirt.new(name: "MTF", size: "L").create(name: "MTF", size: "L") shirt2 = Shirt.new(name: "MTF", size: "M").create(name: "MTF", size: "M") puts Shirt.instances.inspect 我仍然收到错误消息,即 #create': undefined method new” :0x00561581043750 @attributes={:name=>"MTF", :size=>"L"}> (NoMethodError) from store2.rb:36:in `
      ' "
    【解决方案3】:

    归根结底,这真的很简单:

    • C.include(M) 使C 的当前超类成为M 的超类,M 成为C 的超类。换句话说,它将M 插入C 的祖先链中。
    • obj.extend(M) (大致)与 obj.singleton_class.include(M) 相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-19
      • 2013-07-07
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      • 2011-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多