Kernel.load
才能观察和处理我们为监控而编写的一些Ruby文件.然而,它似乎对这种恶作剧免疫.
很容易覆盖require
和require_relative
,但是如果我没记错的话,加载位于它们之下并且会阻塞实际的文件读取.
这就是为什么它似乎受到保护而不受覆盖:
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不是由require或require_relative调用的. Mea culpa.好抓Matt.
这个问题类似于“How to override require in Ruby?”.
好读:
>“Ways to load code”
>“Ruby Require VS Load VS Include VS Extend”
>和Jörg’s“When monkey patching a method,can you call the overridden method from the new implementation?”的惊人答案
I also want to give some love to Module#prepend,which would allow you to simply use super instead of that ugly alias_method stuff,with the additional bonus that your modifications would actually show up in the ancestry chain and thus much easier to debug.
非常明智,值得使用.
> http://ruby-doc.org/core-2.2.2/Module.html#method-i-prepend
> http://ruby-doc.org/core-2.2.2/Module.html#method-i-prepend_features
> http://ruby-doc.org/core-2.2.2/Module.html#method-i-append_features
解决方法
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包含内核,使用类Object overriding似乎干净利落.