Whenever I try to extend a ruby module, I lose the module methods. Neither include nor extend will do this. Consider the snippet:
每当我尝试扩展ruby模块时,我都会丢失模块方法。既不包含也不延伸都不会这样做。考虑一下片段:
module A
def self.say_hi
puts "hi"
end
end
module B
include A
end
B.say_hi #undefined_method
Whether B Includes or Extends A, say_hi will not be defined.
无论B包括还是扩展A,都不会定义say_hi。
Is there any way to accomplish something like this?
有没有办法完成这样的事情?
5 个解决方案
#1
25
If you are the author of module A
and will frequently need this, you can re-author A like so:
如果您是模块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"
#2
9
I don't think there's any simple way to do it.
我认为没有任何简单的方法可以做到这一点。
So here is a complex way:
所以这是一个复杂的方式:
module B
class << self
A.singleton_methods.each do |m|
define_method m, A.method(m).to_proc
end
end
end
You can put it in a helper method like this:
你可以把它放在这样的辅助方法中:
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
#3
3
Use include_complete
使用include_complete
gem install include_complete
gem install include_complete
module A
def self.say_hi
puts "hi"
end
end
module B
include_complete A
end
B.say_hi #=> "hi"
#4
2
Johnathan, I am not sure if you're still wondering about this, but there are two different ways to use modules in ruby. A.) you use modules in their self contained form Base::Tree.entity(params) directly in your code, or B.) you use modules as mixins or helper methods.
Johnathan,我不确定你是否还在想这个,但有两种不同的方法可以在ruby中使用模块。 A.)您在代码中直接使用自包含形式的Base :: Tree.entity(params)模块,或B.)您将模块用作mixins或helper方法。
A. Will allow you to use modules as a Namespace pattern. This is good for larger projects where there is the chance for method name conflicts
A.允许您将模块用作命名空间模式。这对于可能存在方法名称冲突的大型项目非常有用
module Base
module Tree
def self.entity(params={},&block)
# some great code goes here
end
end
end
Now you can use this to create some sort of Tree structure in your code, without having to instantiate a new class for every call to Base::Tree.entity.
现在,您可以使用它在代码中创建某种树结构,而无需为每次调用Base :: Tree.entity实例化一个新类。
Another way to do Namespace-ing is on a class by class basis.
另一种进行命名空间的方法是逐类进行。
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
Now we have the potential for overlap in our classes. We want to know that when we make a create an Actor class that it is the correct class, so this is where namespaces come in handy.
现在我们有可能在课堂上重叠。我们想要知道,当我们创建一个Actor类,它是正确的类时,所以这就是命名空间派上用场的地方。
Session::Live::Actor.new(params) do |res|...
Session::Actor.new(params)
B. Mix-Ins These are your friends. Use them whenever you think you will have to do something more than once in your code.
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
Now whenever you need to format an xmlstring as a hash, or remove trailing whitespace in any of your future code, just mix it in.
现在,无论何时需要将xmlstring格式化为哈希,或者在将来的任何代码中删除尾随空格,只需将其混合即可。
module Fun
class Ruby
include Friendly::Formatter
attr_accessor :string
def initialize(params={})
end
end
end
Now you can format the string in your class.
现在,您可以在类中格式化字符串。
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)
Hope this is a good enough explanation. The points raised above are good examples of ways to extend classes, but with modules, the hard part is when to use the self keyword. It refers to the scope of the object within ruby's object hierarchy. So if you want to use a module as a mix-in, and don't want to declare anything singleton, don't use the self keyword, however if you want to keep state within the object, just use a class and mix-in the modules you want.
希望这是一个很好的解释。上面提到的几点是扩展类的方法的很好的例子,但是对于模块,困难的部分是何时使用self关键字。它指的是ruby对象层次结构中对象的范围。因此,如果您想将模块用作混合,并且不想声明任何单例,请不要使用self关键字,但是如果您想在对象中保持状态,只需使用类并混合 - 在你想要的模块中。
#5
0
I don't like everyone using self.included
. I have simpler solution:
我不喜欢每个人都使用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
#1
25
If you are the author of module A
and will frequently need this, you can re-author A like so:
如果您是模块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"
#2
9
I don't think there's any simple way to do it.
我认为没有任何简单的方法可以做到这一点。
So here is a complex way:
所以这是一个复杂的方式:
module B
class << self
A.singleton_methods.each do |m|
define_method m, A.method(m).to_proc
end
end
end
You can put it in a helper method like this:
你可以把它放在这样的辅助方法中:
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
#3
3
Use include_complete
使用include_complete
gem install include_complete
gem install include_complete
module A
def self.say_hi
puts "hi"
end
end
module B
include_complete A
end
B.say_hi #=> "hi"
#4
2
Johnathan, I am not sure if you're still wondering about this, but there are two different ways to use modules in ruby. A.) you use modules in their self contained form Base::Tree.entity(params) directly in your code, or B.) you use modules as mixins or helper methods.
Johnathan,我不确定你是否还在想这个,但有两种不同的方法可以在ruby中使用模块。 A.)您在代码中直接使用自包含形式的Base :: Tree.entity(params)模块,或B.)您将模块用作mixins或helper方法。
A. Will allow you to use modules as a Namespace pattern. This is good for larger projects where there is the chance for method name conflicts
A.允许您将模块用作命名空间模式。这对于可能存在方法名称冲突的大型项目非常有用
module Base
module Tree
def self.entity(params={},&block)
# some great code goes here
end
end
end
Now you can use this to create some sort of Tree structure in your code, without having to instantiate a new class for every call to Base::Tree.entity.
现在,您可以使用它在代码中创建某种树结构,而无需为每次调用Base :: Tree.entity实例化一个新类。
Another way to do Namespace-ing is on a class by class basis.
另一种进行命名空间的方法是逐类进行。
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
Now we have the potential for overlap in our classes. We want to know that when we make a create an Actor class that it is the correct class, so this is where namespaces come in handy.
现在我们有可能在课堂上重叠。我们想要知道,当我们创建一个Actor类,它是正确的类时,所以这就是命名空间派上用场的地方。
Session::Live::Actor.new(params) do |res|...
Session::Actor.new(params)
B. Mix-Ins These are your friends. Use them whenever you think you will have to do something more than once in your code.
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
Now whenever you need to format an xmlstring as a hash, or remove trailing whitespace in any of your future code, just mix it in.
现在,无论何时需要将xmlstring格式化为哈希,或者在将来的任何代码中删除尾随空格,只需将其混合即可。
module Fun
class Ruby
include Friendly::Formatter
attr_accessor :string
def initialize(params={})
end
end
end
Now you can format the string in your class.
现在,您可以在类中格式化字符串。
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)
Hope this is a good enough explanation. The points raised above are good examples of ways to extend classes, but with modules, the hard part is when to use the self keyword. It refers to the scope of the object within ruby's object hierarchy. So if you want to use a module as a mix-in, and don't want to declare anything singleton, don't use the self keyword, however if you want to keep state within the object, just use a class and mix-in the modules you want.
希望这是一个很好的解释。上面提到的几点是扩展类的方法的很好的例子,但是对于模块,困难的部分是何时使用self关键字。它指的是ruby对象层次结构中对象的范围。因此,如果您想将模块用作混合,并且不想声明任何单例,请不要使用self关键字,但是如果您想在对象中保持状态,只需使用类并混合 - 在你想要的模块中。
#5
0
I don't like everyone using self.included
. I have simpler solution:
我不喜欢每个人都使用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