我们经常会用到hook 方法(钩子方法). 例如: before, after, ... 比如rails,比如delayed_job中。 ( We have been seen this kind of code everywhere: before, after... in rails or other libraries such as delayed_job. they are called 'hook method' )
最基本的设想是这样的 ( the simplest implementation is as below )
def run
before
core_method
after
end
def core_method; puts 'running the core method' ; end
def before; puts 'something happens before hand' ; end
def after; puts 'finally...' ; end
run # => 'something happens before hand'
# => 'running the core method'
# => 'finally...'
尽管上面的代码也工作, 但是还有更好的办法。可读性更强。比如delayed_job 中所使用的: ( Yes, the above code works, however there's a better way to improve the readability. see the implementation from delayed_job as below )
class ParanoidNewsletterJob < NewsletterJob
def perform
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
end
def before(job)
record_stat 'newsletter_job/start'
end
我们可以看到,delayed job 源代码中,中把hook进一步写成了一个macro ( 模拟宏) ( We could find that Delayed_job 's source code implements the hooks as a class macro )
def hook(name, *args)
if payload_object.respond_to?(name)
method = payload_object.method(name)
method.arity == 0 ? method.call : method.call(self, *args)
end
rescue DeserializationError
# do nothing
end
然后就可以写成更加自然/理所当然/一目了然的方式: ( Then, the code is more straight forward...)
def invoke_job
hook :before # instead of: payload_object.send(:before)
payload_object.perform
hook :success
rescue Exception => e
hook :error, e
raise e
ensure
hook :after
end
怎么样? 使用了 "hook" 做为macro, 是不是一目了然,核心方法 payload_object.perform 赫然出现。hooks 把它围绕在中心。效果是不是比原来的代码要容易了不少呢? ( see it? it's more obvious that 'before', 'success' are hooks and the 'payload_object.perform' is the core method. )