ruby – 如何覆盖Kernel.load

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

很容易覆盖requirerequire_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’sWhen monkey patching a method,can you call the overridden method from the new implementation?”的惊人答案

Jörg’s评论

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

解决方法

根据“ When monkey patching a method,can you call the overridden method from the new implementation?”中的示例,以下两个简单的示例似乎可以覆盖require和require_relative.
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似乎干净利落.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...