Можно ли определить одноэлементный метод Ruby с помощью блока?
-
02-07-2019 - |
Вопрос
Итак, я хочу определить одноэлементный метод для объекта, но хочу сделать это с помощью замыкания.
Например,
def define_say(obj, msg)
def obj.say
puts msg
end
end
o = Object.new
define_say o, "hello world!"
o.say
Это не работает, поскольку определение одноэлементного метода с помощью «def» не является замыканием, поэтому я получаю исключение, что «msg» является неопределенной переменной или методом.
Я хотел бы сделать что-то вроде использования метода «define_method» в классе модуля, но, насколько я могу судить, это можно использовать только для определения метода в классе...но мне нужен метод Singleton...
Итак, я хотел бы написать это примерно так:
def define_say(obj, msg)
obj.define_singleton_method(:say) {
puts msg
}
end
Кто-нибудь знает, как я могу добиться этого без необходимости создавать метод для хранения Proc, а затем использовать Proc в одноэлементном методе?(по сути, мне нужен чистый, нехакерский способ сделать это)
Решение
Вот ответ, который делает то, что вы ищете
def define_say(obj, msg)
# Get a handle to the singleton class of obj
metaclass = class << obj; self; end
# add the method using define_method instead of def x.say so we can use a closure
metaclass.send :define_method, :say do
puts msg
end
end
Использование (вставка из IRB)
>> s = "my string"
=> "my string"
>> define_say(s, "I am S")
=> #<Proc:0xb6ed55b0@(irb):11>
>> s.say
I am S
=> nil
Для получения дополнительной информации (и небольшой библиотеки, которая сделает ее менее запутанной) прочитайте это:
http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
Кстати, если вы программист на Ruby и НЕ читали это, сделайте это прямо сейчас~!
Другие советы
Object#define_singleton_method
кстати, было добавлено в Ruby-1.9.2:
def define_say(obj, msg)
obj.define_singleton_method(:say) do
puts msg
end
end