簡體   English   中英

模塊擴展Ruby中的其他模塊

[英]module extending other modules in Ruby

在這方面,我已經閱讀了很多答案,但是我仍然無法弄清楚以下原因為何不起作用

module A
  def a
    puts 'hi'
  end
end

module B
  extend A
end

class C
  extend B
  def b
    a
  end
end
C.new.b # undefined local variable or method `a' for #<C:...

我也嘗試過:

module B
  def self.included(recipient)
    recipient.extend A
  end
end

希望C將得到擴展(但是我想層次結構是錯誤的)

重要提示 :問題在於我有一個需要extended memoist模塊,並且我想為其添加一些功能。

我該如何實現?為什么第一個示例不起作用?

extends將作為參數傳遞的模塊中的方法添加為“類方法”。 你期待看到的東西include ,它增加了從方法(在這種情況下) A模塊實例方法,就像你希望它:

module A
  def a
    puts 'hi'
  end
end

module B
  include A
end

class C
  include B
  def b
    a
  end
end
C.new.b
# hi

首先,您的示例並不完全有效。 默認情況下,擴展的模塊不會添加實例方法。 您的A模塊應如下所示:

module Memoist
  def self.extended(mod)
    mod.include InstanceMethods
  end

  module InstanceMethods
    def a
      puts 'hi'
    end
  end
end

您可以在extendedincludedexcluded回調中extend Memoist 只要您要添加到界面中,它就可以工作。 在擴展,包含或添加模塊之后,將觸發回調。 這意味着,如果要使用super擴展現有方法,則該方法將無效,因為在您的版本之前會調用原始方法。

module YourMemoist
  # Depending on how you want to incorporate your module into the class
  # you can use one of the following: 
  def self.extended(mod)
    mod.extend Memoist
  end

  # def self.included(mod)
  #   mod.extend Memoist
  # end

  # def self.prepended(mod)
  #   mod.extend Memoist
  # end

  # ...
end

class C
  extend MemoistHelper # or include, prepend
end

C.new.a #=> prints hi
C.singleton_class.ancesotrs #=> [#<Class:C>, Memoist, YourMemoist, ...]

如果您確實想使用super關鍵字,事情將會變得更加困難。 由於Memoist模塊需要首先擴展。 一種實現方法是將模塊包含在自己的模塊中,以便您可以覆蓋它們。 到目前為止非常簡單。 但是, Memoist可能定義了extended回調(以添加實例方法),當我們將模塊包括在自己的模塊中時不會觸發該回調。 因此,我們需要手動調用它。

module YourMemoist
  include Memoist

  def self.extended(mod)
    Memoist.send(:extended, mod) # using #send to call private method
    # If you want to add your own instance methods add them after the
    # above call (as shown in the Memoist module).
  end

  # ...
end

class C
  extend MemoistHelper
end

C.new.a #=> prints hi
C.singleton_class.ancesotrs #=> [#<Class:C>, YourMemoist, Memoist, ...]

回想一下,如果一個模塊M1includedextended (或prepended由模塊) M2M1的實例方法被帶入M2 ,無論是作為實例方法(如果包括)或作為模塊的方法(如果延伸)。 如果M1包含模塊方法(在M1調用的方法),則它們都將被includeextend跳過。 由於類是模塊,因此在M2是類時適用。

module M1
  def i() end
  def self.m() end
end

M1.instance_methods
  #=> [:i] 
M1.methods(false)
  #=> [:m] 

module M2; end

M2.extend M1
M2.instance_methods
  #=> []
M2.methods & [:i, :m]
  #=> [:i]

module M3; end

M3.include M1
M3.instance_methods
  #=> [:i]
M3.methods & [:i, :m]
  #=> []

我們看到M2M3都不包含方法:m 現在考慮以下內容。

module A
  def a
    puts 'hi'
  end
end

module B
  extend A
end

B.instance_methods
  #=> []
B.methods & [:a]
  #=> [:a]

不出所料, B包含任何實例方法,其模塊方法包括:a 從前面的討論可以看出,將B包含或擴展到另一個模塊(或類) C 不會將實例方法或方法帶入C

為了增加A的功能, B必須include (或在prependA

module B
  include A
  def b
    puts 'ho'
  end
end

B.instance_methods
  #=> [:b, :a] 
B.methods & [:a, :b]
  #=> []

然后, C可以根據需要includeextend B

有人可能會問,當模塊被另一個模塊包含或擴展時,如果忽略它們,是否有任何理由來定義模塊方法。 答案是它們只是輔助方法,在非OOP語言中充當函數。 一個示例是Math模塊,該模塊僅包含模塊方法。 因此,它們在模塊上被調用; 例如,

Math.sqrt(2)
  #=> 1.4142135623730951  

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM