Ruby:如何将模块URI扩展到我自己的派生模块中

时间:2017-03-20 16:46:47

标签: ruby uri

我习惯于扩展类以在标准类之上提供我自己的封装功能。

由于我正在构建一个比基本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模块的正确方法是什么,并在现有的实例变量中添加实例变量(如虚拟,这里)以添加功能?

感谢您的任何提示和建议。

1 个答案:

答案 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>