如何覆盖Kernel.load

时间:2015-08-05 18:31:20

标签: ruby

我需要覆盖Kernel.load才能观察和处理我们为监控而编写的一些Ruby文件。然而,它似乎对这种恶作剧免疫。

很容易覆盖requirerequire_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

我满足于仅覆盖requirerequire_relative。但是,我很好奇load发生了什么。

后记:

loadrequire未调用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东西,还有额外的奖励,你的修改实际上会出现在祖先链中,因此更容易调试。

非常明智,值得使用。

1 个答案:

答案 0 :(得分:0)

以下两个简单的示例似乎适用于覆盖requirerequire_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覆盖似乎干净利落。