考虑以下脚本:
module Kernel
unless defined?(gem_original_require_2)
alias gem_original_require_2 require
private :gem_original_require_2
end
def require(path)
return gem_original_require_2(path)
end
end
p method(:require) # #<Method: main.require>
p method(:require).owner # Kernel
p method(:require).receiver # main
p method(:require).source_location # ["1.rb", 7]
puts '-' * 10
p Kernel.method(:require) # #<Method: Kernel.require>
p Kernel.method(:require).owner # #<Class:Kernel>
p Kernel.method(:require).receiver # Kernel
p Kernel.method(:require).source_location # nil
puts '-' * 10
p Kernel.method(:gem_original_require) # #<Method: Kernel.gem_original_require(require)>
p Kernel.method(:gem_original_require).owner # Kernel
p Kernel.method(:gem_original_require).receiver # Kernel
p Kernel.method(:gem_original_require).source_location # nil
puts '-' * 10
p Kernel.method(:gem_original_require_2) # #<Method: Kernel.gem_original_require_2(require)>
p Kernel.method(:gem_original_require_2).owner # Kernel
p Kernel.method(:gem_original_require_2).receiver # Kernel
p Kernel.method(:gem_original_require_2).source_location # ["/home/yuri/.rubies/ruby-2.6.3/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb", 34]我对输出有很多疑问。为什么Kernel有时是类,有时是模块?为什么他们有不同的接收器?当方法被调用时,receiver会变成self吗?
但更重要的是,Kernel.require和Kernel.gem_original_require是同一种方法吗?Kernel.require 被重写。还有别的地方吗?如果你能回答剩下的问题,那就太棒了。
换句话说。让我们尝试用普通的类和方法来重现这个问题。正如在其他问题中所述,在Kernel上定义一个方法会创建两个方法(实例和单例)。所以:
class MyKernel
# original require
def require; puts 'require'; end
def self.require; puts 'require'; end
# copy original require
alias gem_original_require require
class << self
alias gem_original_require require
end
end
main = MyKernel.newKernel实际上是一个模块,但据推测,这在这里并不重要。
p MyKernel.method(:require)
== MyKernel.method(:gem_original_require)
# true
p main.method(:require)
== main.method(:gem_original_require)
# true
p main.method(:require)
== MyKernel.method(:require)
# false因此,为了比较方法,您必须要么通过类访问它们,要么通过实例访问。让我们重写require
class MyKernel
# override one of the original require's
def require; puts 'require'; end
end现在我们有了3个require:
main.require (original)
MyKernel.require
main.require和2个gem_original_requires:
main.gem_original_require
MyKernel.gem_original_require我们可以比较类似(实例方法与实例方法,单例方法与单例方法)。但是我们不再能够访问原始的main.require,所以只剩下单例方法了。以下情况仍然有效:
p MyKernel.method(:require)
== MyKernel.method(:gem_original_require)
# true但对于真正的require来说却不是
p Kernel.method(:require)
== Kernel.method(:gem_original_require)
# false发布于 2020-03-31 19:19:01
我想你会在这里找到部分答案:https://stackoverflow.com/a/57236134/6008847
Rubygems代码替换了包含的require版本。
当您调用Kernel.require时,您将得到原始的require方法。
当您调用require时,您将从Rubygems获得该方法(接收方将是您调用require的上下文)。
gem_original_require是原始require方法的别名:require.rb#L16
https://stackoverflow.com/questions/58528539
复制相似问题