[英]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
您可以在extended
, included
或excluded
回調中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, ...]
回想一下,如果一個模塊M1
被included
或extended
(或prepended
由模塊) M2
, M1
的實例方法被帶入M2
,無論是作為實例方法(如果包括)或作為模塊的方法(如果延伸)。 如果M1
包含模塊方法(在M1
調用的方法),則它們都將被include
和extend
跳過。 由於類是模塊,因此在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]
#=> []
我們看到M2
和M3
都不包含方法: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
(或在prepend
) A
。
module B
include A
def b
puts 'ho'
end
end
B.instance_methods
#=> [:b, :a]
B.methods & [:a, :b]
#=> []
然后, C
可以根據需要include
或extend
B
有人可能會問,當模塊被另一個模塊包含或擴展時,如果忽略它們,是否有任何理由來定義模塊方法。 答案是它們只是輔助方法,在非OOP語言中充當函數。 一個示例是Math模塊,該模塊僅包含模塊方法。 因此,它們在模塊上被調用; 例如,
Math.sqrt(2)
#=> 1.4142135623730951
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.