d11*_*wtq 5 ruby module wrapper
是否有可能使这项工作成为可能,而不必在课程结束时包含该模块并将其包含在顶部?
module VerboseJob
def self.included(job_class)
class << job_class
alias_method :original_perform, :perform
def perform(*args)
JobLogger.verbose { original_perform(*args) }
end
end
end
end
class HelloJob
include VerboseJob
def self.perform(arg1, arg2)
puts "Job invoked with #{arg1} and #{arg2}"
end
end
Run Code Online (Sandbox Code Playgroud)
我想要发生的是HelloJob.perform实际调用VerboseJob.perform(然后调用块内的原始方法).因为此处的模块包含在类的顶部,所以这不起作用,因为perform尚未定义.移动include到最后确实有效,但是有一种方式更宽容吗?我喜欢将所有包含的模块保留在我的类定义的顶部.
我正在寻找一些被调用的方法Module或者Class它已经完全加载的方法,而不是运行时解释的方法.
这是我想出的一种相当迂回/黑客的方法,将包装方法的定义推迟到原始方法被定义为止:
module A
def self.included(base)
base.class_eval do
def self.singleton_method_added(name)
@@ran||=false
if name==:perform && !@@ran
@@ran=true
class<<self
alias_method :original_perform, :perform
def perform(*args)
puts "Hello"
original_perform(*args)
end
end
end
end
end
end
end
class B
include A
def self.perform
puts "Foobar"
end
end
B.perform
Run Code Online (Sandbox Code Playgroud)
编辑:
d11wtq 将其简化为更加清晰:
module VerboseJob
module ClassMethods
def wrap_perform!
class << self
def perform_with_verbose(*args)
JobLogger.verbose { perform_without_verbose(*args) }
end
alias_method_chain :perform, :verbose \
unless instance_method(:perform) == instance_method(:perform_with_verbose)
end
end
def singleton_method_added(name)
wrap_perform! if name == :perform
end
end
def self.included(job_class)
job_class.extend ClassMethods
job_class.wrap_perform! if job_class.respond_to?(:perform)
end
end
Run Code Online (Sandbox Code Playgroud)