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



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

由于我正在构建比基本 URI 更完整的对象,因此我可以选择重新打开模块并添加我自己的类或实例方法。虽然它可以工作,但我认为这不是最优雅的方式。

假设我想称它为 Location,其行为类似于 URI,但有一些额外的类/实例方法。让我们举一个基本的例子,一个name方法:

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 模块的方法(如解析(在我现在的位置模块上不可用:

$ undefined method `parse' for Location:Module (NoMethodError)

使用包含 URI 或扩展 URI 时出现相同错误以我上面描述的方式扩展 URI 模块并在现有变量中添加实例变量(如虚拟变量,此处(以添加功能的正确方法是什么?

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

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

最新更新