Можно ли определить одноэлементный метод Ruby, используя блок? - PullRequest
11 голосов
/ 26 сентября 2008

Итак, я хочу определить одноэлементный метод для объекта, но я хочу сделать это с помощью замыкания.

Например,

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 в классе Module, но, насколько я могу судить, это можно использовать только для определения метода в классе ... но я хочу Синглтон метод ...

Итак, я хотел бы написать что-то вроде этого:

def define_say(obj, msg)
  obj.define_singleton_method(:say) {
    puts msg
  }
end

Кто-нибудь знает, как мне этого добиться, не создавая метод для хранения Proc, а затем использовать Proc в одноэлементном методе? (в основном я хочу чистый, не хакерский способ сделать это)

Ответы [ 2 ]

14 голосов
/ 23 июня 2011

Object#define_singleton_method был добавлен в ruby-1.9.2 следующим образом:

def define_say(obj, msg)
  obj.define_singleton_method(:say) do
    puts msg
  end
end
8 голосов
/ 26 сентября 2008

Вот ответ, который делает то, что вы ищете

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 ​​и не читали этого, то сделайте это сейчас!

...