Ruby Monkey 修补模块的类方法



我正在使用的一个gem(gem"A")依赖于另一个我正在尝试修补其方法的gem(gem"B")。当我修补gem"B"并从gem"a"调用一个方法时,monkey补丁将被忽略。我的补丁如下所示:

module B
class<< self
def patched_method()
raise
end
end
end

我在整个过程中插入了语句来打印方法的位置,使用格式

puts B.method(:patched_method).source_location

当在补丁之前调用时,它指向宝石"B"的位置。补丁之后,它指向我定义补丁的位置,但它仍然不调用我的补丁!

现在,我的补丁只调用raise,这样我就可以验证它是否被调用了,但我也尝试过打印文本和调用实际的补丁代码,但都不起作用。我做错了什么?

宝石和代码细节

我正在尝试修补Numerizer-gem的numerize方法,该方法由Chronic-gem使用。

我尝试过多种方法进行修补,但最近的是:

module NumerizerExpand
module ClassMethods
def self.numerize(value)
raise
end
end
def self.included(receiver)
receiver.extend ClassMethods
end
end
Numerizer.send(:include, NumerizerExpand)

Numerizer.instance_eval do
class<< self
def my_numerize(value)
puts "here"
raise
end
alias_method :numerize, :my_numerize
end
end

对于第二种方法,我尝试过同时使用instance_evalmodule_eval,但似乎都不起作用。

我在github上创建了一个要点,其中包含我正在运行的测试脚本。

您正在修补错误的类:)

require 'numerizer'
require 'chronic'
puts Chronic::Numerizer.method(:numerize).source_location

class Chronic::Numerizer
def self.numerize(value)
puts "here"
raise
end
end
puts Chronic::Numerizer.method(:numerize).source_location
#p Chronic::Numerizer.numerize(3)
p Chronic.parse('January 2nd')

输出

bbozo@eva:~/dev/SO_question_1$ ruby wii.rb
/home/bbozo/.rvm/gems/ruby-2.2.3/gems/chronic-0.10.2/lib/chronic/numerizer.rb
72
wii.rb
8
here
wii.rb:10:in `numerize': unhandled exception
from /home/bbozo/.rvm/gems/ruby-2.2.3/gems/chronic-0.10.2/lib/chronic/parser.rb:100:in `pre_normalize'
from /home/bbozo/.rvm/gems/ruby-2.2.3/gems/chronic-0.10.2/lib/chronic/parser.rb:226:in `tokenize'
from /home/bbozo/.rvm/gems/ruby-2.2.3/gems/chronic-0.10.2/lib/chronic/parser.rb:60:in `parse'
from /home/bbozo/.rvm/gems/ruby-2.2.3/gems/chronic-0.10.2/lib/chronic.rb:90:in `parse'
from wii.rb:17:in `<main>'

显然,chronic团队决定不想将一个类作为单独的依赖项来维护,他们只是将其复制粘贴并包含在名称空间中。

你在修补一块实际上chronic没有使用的宝石。猪的把戏:)但对chronic人来说是合理的。

Numerizer是一个类,numerize是一个方法。您不能使用模块覆盖类方法,因为ruby按以下顺序查找方法:

  • 包含/扩展模块
  • 父类
  • 父类模块
  • 对象
  • 对象包含的模块
  • 基本对象

这应该很简单,不确定你是否尝试过?

class Numerizer
def self.numerize(string)
# override it here
end
end

我希望这能奏效,除非你先这样做,然后require 'numerizer'在这种情况下,您将覆盖您的更改。

PS。很抱歉我还没有测试过这个,但我不想安装一个需要我运行sudo gem sources -a http://gemcutter.org的gem我不知道如何扭转这种操作,也不会在谷歌上搜索。

PPS。如果这不起作用,我会非常惊讶。

最新更新