[英]Extending a Ruby module in another module, including the module methods
每當我嘗試擴展ruby模塊時,我都會丟失模塊方法。 既不包含也不延伸都不會這樣做。 考慮一下片段:
module A
def self.say_hi
puts "hi"
end
end
module B
include A
end
B.say_hi #undefined_method
無論B包括還是擴展A,都不會定義say_hi。
有沒有辦法完成這樣的事情?
如果您是module A
的作者並且經常需要這個,您可以像這樣重新創作A:
module A
module ClassMethods
def say_hi
puts "hi"
end
end
extend ClassMethods
def self.included( other )
other.extend( ClassMethods )
end
end
module B
include A
end
A.say_hi #=> "hi"
B.say_hi #=> "hi"
我認為沒有任何簡單的方法可以做到這一點。
所以這是一個復雜的方式:
module B
class << self
A.singleton_methods.each do |m|
define_method m, A.method(m).to_proc
end
end
end
你可以把它放在這樣的輔助方法中:
class Module
def include_module_methods(mod)
mod.singleton_methods.each do |m|
(class << self; self; end).send :define_method, m, mod.method(m).to_proc
end
end
end
module B
include_module_methods A
end
gem install include_complete
module A
def self.say_hi
puts "hi"
end
end
module B
include_complete A
end
B.say_hi #=> "hi"
Johnathan,我不確定你是否還在想這個,但有兩種不同的方法可以在ruby中使用模塊。 A.)您在代碼中直接使用自包含形式的Base :: Tree.entity(params)模塊,或B.)您將模塊用作mixins或helper方法。
A.允許您將模塊用作命名空間模式。 這對於可能存在方法名稱沖突的大型項目非常有用
module Base
module Tree
def self.entity(params={},&block)
# some great code goes here
end
end
end
現在,您可以使用它在代碼中創建某種樹結構,而無需為每次調用Base :: Tree.entity實例化一個新類。
另一種進行命名空間的方法是逐類進行。
module Session
module Live
class Actor
attr_accessor :type, :uuid, :name, :status
def initialize(params={},&block)
# check params, insert init values for vars..etc
# save your callback as a class variable, and use it sometime later
@block = block
end
def hit_rock_bottom
end
def has_hit_rock_bottom?
end
...
end
end
class Actor
attr_accessor :id,:scope,:callback
def initialize(params={},&block)
self.callback = block if block_given?
end
def respond
if self.callback.is_a? Proc
# do some real crazy things...
end
end
end
end
現在我們有可能在課堂上重疊。 我們想要知道,當我們創建一個Actor類,它是正確的類時,所以這就是命名空間派上用場的地方。
Session::Live::Actor.new(params) do |res|...
Session::Actor.new(params)
B.混合這些是你的朋友。 只要您認為必須在代碼中執行多次操作,請使用它們。
module Friendly
module Formatter
def to_hash(xmlstring)
#parsing methods
return hash
end
def remove_trailing_whitespace(string,&block)
# remove trailing white space from that idiot who pasted from textmate
end
end
end
現在,無論何時需要將xmlstring格式化為哈希,或者在將來的任何代碼中刪除尾隨空格,只需將其混合即可。
module Fun
class Ruby
include Friendly::Formatter
attr_accessor :string
def initialize(params={})
end
end
end
現在您可以在類中格式化字符串。
fun_ruby = Fun::Ruby.new(params)
fun_ruby.string = "<xml><why><do>most</do><people></people><use>this</use><it>sucks</it></why></xml>"
fun_ruby_hash = fun_ruby.to_hash(fun_ruby.string)
希望這是一個很好的解釋。 上面提到的幾點是擴展類的方法的很好的例子,但是對於模塊,困難的部分是何時使用self關鍵字。 它指的是ruby對象層次結構中對象的范圍。 因此,如果您想將模塊用作混合,並且不想聲明任何單例,請不要使用self關鍵字,但是如果您想在對象中保持狀態,只需使用類並混合 - 在你想要的模塊中。
我不喜歡每個人都使用self.included
。 我有更簡單的解決方案:
module A
module ClassMethods
def a
'a1'
end
end
def a
'a2'
end
end
module B
include A
module ClassMethods
include A::ClassMethods
def b
'b1'
end
end
def b
'b2'
end
end
class C
include B
extend B::ClassMethods
end
class D < C; end
puts D.a
puts D.b
puts D.new.a
puts D.new.b
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.