Ruby 扩展并包含跟踪代码
Ruby extend & include tracing code
我对使用 "include" 与“扩展”感到困惑,搜索了几个小时后,我得到的只是与 class 实例一起使用的模块方法,包括模块,以及与当 class 扩展这些方法的模块时 class 本身。
但这并没有帮助我弄清楚为什么这段代码在注释“#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)
而当取消注释 "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
使代码运行并输出以下内容
[#<Shirt:0x0055792cb93890 @attributes={:name=>"MTF", :size=>"L"}>, #<Shirt:0x0055792cb937a0 @attributes={:name=>"MTF", :size=>"M"}>]
这有点令人困惑,但我需要知道的是,为什么我需要扩展模块以避免错误?,以及如何编辑此代码以使其在没有扩展方法的情况下工作? ,代码中还剩下什么仍然依赖于扩展?
当您 extend
一个模块时,该模块中的方法变为 "class methods"**。因此,当您 extend Inventoryable
时,create
可用作 Shirt
class.
上的方法
当您 include
一个模块时,该模块中的方法将变为 "instance methods"**。因此,当您 include Inventoryable
时,create
在 Shirt
class 上不可用(但 是 在 [= 的实例上可用16=]).
要在使用 include
时使 create
在 Shirt
class 上可用,您可以使用 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 中,一切都是实例方法,没有 class 方法。这在形式上是 100% 正确的,但我们将在这里使用 class
和 instance
方法的通俗含义。
当您在 class 中扩展模块时,您会将模块的方法公开为 class 方法,但如果您包含该模块,那么您会将模块的方法作为实例方法获取,在您的示例中为了能够调用 Inventoryable
class 的 create
方法,您需要使用 Shirt
class 的实例调用它(如果包含模块)
shirt1 = Shirt.new(attributes).create(attributes)
没有更多信息,我无法判断您要做什么,但您需要重新设计 initialize
和 create
方法来决定在这些方法中的位置或操作。
我会尝试用一个简单的例子来解释它
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
希望对您有所帮助。
归根结底,这真的很简单:
C.include(M)
使 C
的当前超类成为 M
的超类,而 M
成为 C
的超类。换句话说,它将 M
插入到 C
的祖先链中。
obj.extend(M)
与 obj.singleton_class.include(M)
. (大致)相同
我对使用 "include" 与“扩展”感到困惑,搜索了几个小时后,我得到的只是与 class 实例一起使用的模块方法,包括模块,以及与当 class 扩展这些方法的模块时 class 本身。
但这并没有帮助我弄清楚为什么这段代码在注释“#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)
而当取消注释 "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
使代码运行并输出以下内容
[#<Shirt:0x0055792cb93890 @attributes={:name=>"MTF", :size=>"L"}>, #<Shirt:0x0055792cb937a0 @attributes={:name=>"MTF", :size=>"M"}>]
这有点令人困惑,但我需要知道的是,为什么我需要扩展模块以避免错误?,以及如何编辑此代码以使其在没有扩展方法的情况下工作? ,代码中还剩下什么仍然依赖于扩展?
当您 extend
一个模块时,该模块中的方法变为 "class methods"**。因此,当您 extend Inventoryable
时,create
可用作 Shirt
class.
当您 include
一个模块时,该模块中的方法将变为 "instance methods"**。因此,当您 include Inventoryable
时,create
在 Shirt
class 上不可用(但 是 在 [= 的实例上可用16=]).
要在使用 include
时使 create
在 Shirt
class 上可用,您可以使用 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 中,一切都是实例方法,没有 class 方法。这在形式上是 100% 正确的,但我们将在这里使用 class
和 instance
方法的通俗含义。
当您在 class 中扩展模块时,您会将模块的方法公开为 class 方法,但如果您包含该模块,那么您会将模块的方法作为实例方法获取,在您的示例中为了能够调用 Inventoryable
class 的 create
方法,您需要使用 Shirt
class 的实例调用它(如果包含模块)
shirt1 = Shirt.new(attributes).create(attributes)
没有更多信息,我无法判断您要做什么,但您需要重新设计 initialize
和 create
方法来决定在这些方法中的位置或操作。
我会尝试用一个简单的例子来解释它
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
希望对您有所帮助。
归根结底,这真的很简单:
C.include(M)
使C
的当前超类成为M
的超类,而M
成为C
的超类。换句话说,它将M
插入到C
的祖先链中。obj.extend(M)
与obj.singleton_class.include(M)
. (大致)相同