我需要覆盖Kernel.load
才能观察和处理我们为监控而编写的一些Ruby文件。然而,它似乎对这种恶作剧免疫。
很容易覆盖require
和require_relative
,但load
位于它们之下,如果我没记错的话,会将实际文件读取瓶颈。
这就是为什么它似乎不受覆盖的原因:
Kernel.module_eval do
alias_method :original_require, :require
def require(filename)
require_result = original_require(filename)
puts "required #{filename}"
require_result
end
alias_method :original_load, :load
def load(filename, wrap=true)
load_result = original_load(filename, wrap)
puts "loaded #{filename}"
load_result
end
end
include Kernel
require 'open-uri'
puts 'done'
运行输出:
required uri/rfc2396_parser
required uri/rfc3986_parser
required uri/common
required uri/common
required uri/generic
required uri/generic
required uri/ftp
required uri/generic
required uri/http
required uri/http
required uri/https
required uri/generic
required uri/ldap
required uri/ldap
required uri/ldaps
required uri/generic
required uri/mailto
required uri
required stringio
required date_core
required date
required time
required open-uri
done
我满足于仅覆盖require
和require_relative
。但是,我很好奇load
发生了什么。
后记:
load
或require
未调用require_relative
。 Mea culpa。好抓Matt。
此问题类似于“How to override require in Ruby?”。
好读:
http://ruby-doc.org/core-2.2.2/Module.html#method-i-prepend评论
我也想对Module#prepend给予一些喜爱,这将允许你简单地使用super而不是那些丑陋的alias_method东西,还有额外的奖励,你的修改实际上会出现在祖先链中,因此更容易调试。
非常明智,值得使用。
答案 0 :(得分:0)
以下两个简单的示例似乎适用于覆盖require
和require_relative
,基于" When monkey patching a method, can you call the overridden method from the new implementation?"中的示例。
module Kernel
old_require = method(:require)
define_method(:require) do |filename|
puts "require #{filename}"
old_require.call(filename)
end
old_require_relative = method(:require_relative)
define_method(:require_relative) do |filename|
puts "require_relative #{filename}"
old_require_relative.call(filename)
end
end
或
module KernelExtensions
def require(filename)
puts "require #{filename}"
super
end
def require_relative(filename)
puts "require_relative #{filename}"
super
end
end
class Object
prepend KernelExtensions
end
使用
运行第二个module Kernel
prepend KernelExtensions
end
没有用,但由于Object包含内核,因此使用class Object
覆盖似乎干净利落。