我写了这个模块:
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
该模块允许其他模块或类定义一个挂钩,在类似于before_action
in Rails的特定操作之前应调用该挂钩。然后,我将此模块包含在HTTParty模块中:
module HTTParty
include Hooks
before_action :perform_action, :get
def self.perform_action
puts "performed"
end
end
有一个包含HTTParty模块的类:
class TestClient
include HTTParty
...
end
当我尝试访问get
TestClient中的方法时,它不会调用perform_action
。get
这里包含的方法是原始方法,而不是重新定义的方法。
有没有办法get
在TestClient类中包含重新定义的方法?
您的代码几乎可以正常运行,但get
实际上HTTParty
并没有直接在上定义,这是您所没有想到的,并且HTTParty
的included
class方法get
通过另一条路径添加到您的类中。
HTTParty
有一个名为HTTParty::ClassMethods
contains的模块get
,等等。它将它们放在两个位置:在HTTParty
其本身上,您可以调用HTTParty.get
,在任何类上include HTTParty
,都可以通过included
钩子进行调用。打开module HTTParty
和时include Hooks
,插入了钩子HTTParty.get
,这与调用时不同TestClient.get
。不理会您的Hooks::ExecutionHooks
模块,建议您制作一个HookedHTTParty
模块,而不是monkeypatching 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
)而不是on上调用的HTTParty
,因此我们可以找到正确的get
方法。您还会注意到global_perform
accepts *args
,因为在生成钩子时是以这种方式调用它的。
因为我们有Hooks
,你现在还可以使用before_action
在TestClient
本身,所以你也可以定义更具体的before_action
S:
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 ... >
如果确实需要进行任何操作HTTParty
(也许是因为您无法控制包括该操作的东西),则可能需要HTTParty::ClassMethods
直接进行monkeypatch ,因为这get
是定义的瓶颈,但进入了更黑暗的领域。只要您在周围注入代码,还OtherThing.include(HookedHTTParty)
可以使其更加显式并使其更加封装。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句