我习惯于扩展类以在标准类之上提供我自己的封装功能。
由于我正在构建一个比基本URI更完整的对象,我可以选择重新打开模块并添加自己的类或实例方法。 虽然它可行,但我认为这不是最优雅的方式。
假设我想把它称为Location,并且表现得像URI,但有一些额外的类/实例方法。我们来一个基本的例子,名称方法:
return new int[] {startRow, endRow, startColumn, endColumn};
这里的问题是我现在的位置模块上没有URI模块的解析方法:
require 'uri'
PATH = 'http://example.com/dir1/dir2/file.txt'
module Location
extend URI
class Generic
attr_reader :dummy
def name
File.basename(@path)
end
end
end
e = URI.parse PATH
puts e.path
f = Location.parse PATH
puts f.path
puts f.name
puts f.dummy = "doh"
使用包含URI或扩展URI的相同错误 以我上面描述的方式扩展URI模块的正确方法是什么,并在现有的实例变量中添加实例变量(如虚拟,这里)以添加功能?
感谢您的任何提示和建议。
答案 0 :(得分:0)
URI.parse
被定义为模块上的类方法。当您包含/扩展模块时,只复制其实例方法。如果使用include,则将它们作为实例方法复制,并使用extend复制为类方法。
话虽这么说,通过一些元编程,可以编写一个方法,将类方法从一个模块复制到另一个模块:
# This returns a list of symbols (all the added methods)
def copy_class_methods(from_klass, to_klass)
from_klass.methods(false).each do |method_name|
method_obj = from_klass.method(method_name)
to_klass.define_singleton_method(method_name, &method_obj)
end
end
然后,例如:
module Location
copy_class_methods(URI, self)
end
Location.parse("http://example.com/dir1/dir2/file.txt")
# => #<URI::HTTP http://example.com/dir1/dir2/file.txt>