我打开了HTTParty模块,并使用以下命令在运行时重新定义了get和post类方法:
define_singleton_method(method_name) do |*args, &block|
method = method(method_name)
method(hook).call(*args)
method.call(*args, &block)
end
此处,hook
是HTTParty模块中另一个方法的名称。 method_name
可以是获取或发布。
之后我尝试在TestClient类中包含HTTParty,如下所示:
class TestClient
include HTTParty
...
end
但是包含的get和post方法的版本只是原始版本。它不应该使用重新定义的方法吗?
答案 0 :(得分:1)
我认为这是因为当你define_singleton_method
时,接收者是HTTParty
模块,而不是它所包含的类(它还不存在)调用define_singleton_method
时。因此,当您include HTTParty
TestClient
时,您重新定义的get
已经绑定到HTTParty
,并且在TestClient
上调用它将无法到达它。但是,如果您执行HTTParty.get("http://google.com")
,则会获得重新定义的方法:
module HTTParty
%i{ get post }.each do |method_name|
define_singleton_method(method_name) do |*args, &block|
puts "redefined!"
end
end
end
class TestClient
include HTTParty
end
TestClient.get("http://google.com")
# real GET
TestClient.method(:get).source_location
# ["/Users/kitkat/.rvm/gems/ruby-2.0.0-p576@kitkat/gems/httparty-0.13.7/lib/httparty.rb", 475]
HTTParty.get("http://google.com")
# => redefined!
HTTParty.method(:get).source_location
=> ["(irb)", 30]
以下是您如何真正重新定义您的方法:
module HTTParty
def self.included(klass)
%i{ get post }.each do |method_name|
klass.define_singleton_method(method_name) do |*args, &block|
puts "redefined!"
end
end
end
end
class TestClient
include HTTParty
end
2.0.0-p576 :058 > TestClient.get("http://google.com")
redefined!
=> nil
2.0.0-p576 :060 > TestClient.method(:get).source_location
=> ["(irb)", 48]