ruby 猴子修补模块的类方法
ruby monkey patching a module's classmethod
A gem 我正在使用 (gem "A") 依赖于另一个 gem (gem "B") 我的方法正在尝试打补丁。当我修补 gem "B" 并从 gem "A" 调用方法时,猴子修补程序将被忽略。我的补丁如下所示:
module B
class<< self
def patched_method()
raise
end
end
end
我在整个过程中都插入了语句来打印方法的位置,使用的形式是
puts B.method(:patched_method).source_location
补丁前调用时,指向gem"B"的位置。补丁后指向我定义补丁的位置,但它仍然没有调用我的补丁!
现在我的补丁只调用 raise
所以我可以验证它是否被调用,但我也尝试打印文本并调用我的实际补丁代码,none 有效。我做错了什么?
Gem 和代码细节
我正在尝试修补 Numerizer
gem's numerize
method which is used by the 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_eval
和 module_eval
,但似乎都不起作用。
I've created a gist on github 包含我正在 运行 测试的脚本。
Numerizer
是一个 class 而 numerize
是一个方法。
您不能使用模块覆盖 class 方法,因为 ruby 按以下顺序查找方法:
- class
- 包含/扩展模块
- parent class
- parent 的 class 个模块
- ...
- Object
- Object 包含的模块
- 基本Object
这个做起来应该很简单,不知道你有没有试过?
class Numerizer
def self.numerize(string)
# override it here
end
end
我希望这能奏效,除非你先这样做然后 require 'numerizer'
在这种情况下,您将覆盖您的更改。
PS。
抱歉,我还没有测试过,但我懒得安装 gem,这需要我 运行 sudo gem sources -a http://gemcutter.org
我不知道如何撤消该操作,也不会 google。
PPS。
如果这行不通,我会感到非常惊讶。
你打错补丁了class :)
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
团队决定他们不想将一个 class 作为单独的依赖项进行维护,他们只是 copy-pasted 并将其包含在命名空间中。
您正在修补 gem,实际上 chronic
并未使用它。猪的把戏 :) 但对 chronic
人来说是合理的。
A gem 我正在使用 (gem "A") 依赖于另一个 gem (gem "B") 我的方法正在尝试打补丁。当我修补 gem "B" 并从 gem "A" 调用方法时,猴子修补程序将被忽略。我的补丁如下所示:
module B
class<< self
def patched_method()
raise
end
end
end
我在整个过程中都插入了语句来打印方法的位置,使用的形式是
puts B.method(:patched_method).source_location
补丁前调用时,指向gem"B"的位置。补丁后指向我定义补丁的位置,但它仍然没有调用我的补丁!
现在我的补丁只调用 raise
所以我可以验证它是否被调用,但我也尝试打印文本并调用我的实际补丁代码,none 有效。我做错了什么?
Gem 和代码细节
我正在尝试修补 Numerizer
gem's numerize
method which is used by the 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_eval
和 module_eval
,但似乎都不起作用。
I've created a gist on github 包含我正在 运行 测试的脚本。
Numerizer
是一个 class 而 numerize
是一个方法。
您不能使用模块覆盖 class 方法,因为 ruby 按以下顺序查找方法:
- class
- 包含/扩展模块
- parent class
- parent 的 class 个模块
- ...
- Object
- Object 包含的模块
- 基本Object
这个做起来应该很简单,不知道你有没有试过?
class Numerizer
def self.numerize(string)
# override it here
end
end
我希望这能奏效,除非你先这样做然后 require 'numerizer'
在这种情况下,您将覆盖您的更改。
PS。
抱歉,我还没有测试过,但我懒得安装 gem,这需要我 运行 sudo gem sources -a http://gemcutter.org
我不知道如何撤消该操作,也不会 google。
PPS。 如果这行不通,我会感到非常惊讶。
你打错补丁了class :)
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
团队决定他们不想将一个 class 作为单独的依赖项进行维护,他们只是 copy-pasted 并将其包含在命名空间中。
您正在修补 gem,实际上 chronic
并未使用它。猪的把戏 :) 但对 chronic
人来说是合理的。