我试图将实例方法foo
添加到Ruby的Array
类中
因此,当它被调用时,数组的字符串元素将更改为字符串" foo"。
这可以通过猴子修补Ruby的String
和Array
类来轻松完成。
class String
def foo
replace "foo"
end
end
class Array
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'foo, 1, foo' as expected
现在我尝试使用Ruby 2' s refinements feature重写上述内容。 我使用的是Ruby 2.2.2版。
以下作品(在文件中,例如ruby test.rb,但由于某种原因不在irb中)
module M
refine String do
def foo
replace "foo"
end
end
end
using M
s = ''
s.foo
puts s # you get 'foo'
但是,在foo
课程中添加Array
时,我无法将其付诸实践。
module M
refine String do
def foo
replace "foo"
end
end
end
using M
module N
refine Array do
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
end
using N
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'a, 1, b', not 'foo, 1, foo' as expected
有两个问题:
respond_to?
即使可以调用也不起作用
对象上的方法。尝试添加puts 'yes' if s.respond_to? :foo
作为第二个代码段中的最后一行,您将看到“是”'是不打印。if x.respond_to? :foo
数组#foo,您将收到错误undefined method 'foo' for "a":String (NoMethodError)
。所以问题是:如何在Array#foo细化中看到String#foo细化?我如何克服这两个问题,以便我可以使用它?
(请不要提供不涉及改进的替代解决方案,因为这是一个理论练习,所以我可以学习如何使用细化)。
谢谢。
答案 0 :(得分:1)
respond_to?
方法不起作用,记录在案
here
问题是您只能在顶级激活细化 它们在范围上是词汇。
一种解决方案是:
module N
refine String do
def foo
replace 'foobar'
end
end
refine Array do
def foo
self.each do |x|
x.foo rescue x
end
end
end
end
using N
a = ['a', 1, 'b']
p a.foo
puts a.join(", ") # foo, 1, foo
答案 1 :(得分:0)
再次举起你的例子,一个简单的解决方案可能是覆盖respond_to?细化块中的方法:
module M
refine String do
def foo
replace "foo"
end
def respond_to?(name,all=false)
list_methods = self.methods.concat [:foo]
list_methods.include? name
end
end
refine Array do
def foo
self.each {|x| x.foo if x.respond_to? :foo }
end
end
end
using M
a = ['a', 1, 'b']
a.foo
puts a.join(", ") # you get 'foo, 1, foo'