我写了这个模块:
module Hooks
module ExecutionHooks
def before_action(hook, *method_names)
method_names.each do |method_name|
method = method(method_name)
define_singleton_method(method_name) do |*args, &block|
method(hook).call(*args)
method.call(*args, &block)
end
end
end
end
def self.included(base)
base.send(:extend, Hooks::ExecutionHooks)
end
end
此模块允许其他模块或类定义一个钩子,该钩子应该在类似于Rails中的before_action
的特定动作之前调用。
然后我将这个模块包含在我的HTTParty模块中:
module HTTParty
include Hooks
before_action :perform_action, :get
def self.perform_action
puts "performed"
end
end
有一个包含HTTParty模块的类:
class TestClient
include HTTParty
...
end
当我尝试访问TestClient中的get
方法时,它不会调用perform_action
。此处包含的get
方法是原始方法,而不是重新定义的方法。
有没有办法在TestClient类中包含重新定义的get
方法?
答案 0 :(得分:1)
您的代码几乎可以使用,但get
实际上并未直接在HTTParty
上定义,您没有预料到,HTTParty
' s { {1}}类方法通过另一条路径向您的班级添加included
。
get
有一个名为HTTParty
的模块,其中包含HTTParty::ClassMethods
等。它将它们放在两个位置:get
本身,因此您可以调用HTTParty
,以及HTTParty.get
通过include HTTParty
挂钩的任何课程。当您打开included
和module HTTParty
时,您在include Hooks
上插入了一个挂钩,这是一个与您呼叫HTTParty.get
时不同的查找链。仅保留TestClient.get
模块,建议您创建一个Hooks::ExecutionHooks
模块而不是monkeypatching HookedHTTParty
。这样可以更清楚地了解发生了什么,并避免了HTTParty
内部的复杂性,我们不应该这样做。
HTTParty
这样可以确保# hooked_httparty.rb
require 'httparty'
require 'hooks'
module HookedHTTParty
module ClassMethods
def global_perform(*args)
puts "Running global perform with args #{args.inspect}"
end
end
def self.included(base)
base.include(HTTParty)
base.include(Hooks)
base.extend(HookedHTTParty::ClassMethods)
base.before_action :global_perform, :get
end
end
上可以使用HTTParty
和Hooks
,然后在每个base
上使用global_perform
挂钩扩展它。与初始代码的主要区别在于get
(before_action
)而不是base
上调用TestClient
,因此我们会使用正确的HTTParty
方法。您还会注意到get
接受global_perform
,因为您在生成挂钩时以这种方式调用它。
由于我们包含*args
,您现在还可以访问Hooks
中的before_action
,因此您还可以定义更具体的TestClient
:
before_action
正在运行class TestClient
include HookedHTTParty
before_action :local_perform, :get
def self.local_perform(*args)
puts "Running local perform with args #{args.inspect}"
end
end
:
get
如果你确实需要包括> TestClient.get 'https://www.stackoverflow.com'
Running local perform with args ["https://www.stackoverflow.com"]
Running global perform with args ["https://www.stackoverflow.com"]
=> #<HTTParty::Response:0x7fa523a009e0 ... >
在内的任何内容(也许是因为你无法控制包括它在内的东西),你可能需要直接monkeypatch HTTParty
,因为那& #39;是定义HTTParty::ClassMethods
的瓶颈,但它进入了更黑暗的领域。只要您重新注入代码,您也可以get
使其更明确,并使其更加封装。