Я пытаюсь добавить метод экземпляра 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< /а>. Я использую 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
в качестве последней строки во втором фрагменте кода, вы увидите, что «да» не печатается. - В моем уточнении массива String#foo выходит за рамки. Если вы удалите
if x.respond_to? :foo
из массива#foo, вы получите ошибкуundefined method 'foo' for "a":String (NoMethodError)
. Итак, вопрос: как сделать уточнение String#foo видимым внутри уточнения Array#foo?
Как мне преодолеть эти две проблемы, чтобы я мог заставить это работать?
(Пожалуйста, не предлагайте альтернативные решения, не требующие уточнения, потому что это теоретическое упражнение, чтобы я мог научиться использовать уточнение).
Спасибо.