Переменные в именах методов ruby - PullRequest
46 голосов
/ 19 ноября 2008

У меня есть следующий код:

for attribute in site.device_attributes
  device.attribute
end

где я хотел бы, чтобы код подставил значение «атрибута» для имени метода.

Я пробовал device."#{attribute}" и различные перестановки.

Это совершенно невозможно? Я что-то упустил?

Я рассмотрел переопределение method_missing, но не могу понять, как это на самом деле поможет мне, когда моя проблема заключается в том, что мне нужно вызвать «неизвестный» метод.

Ответы [ 4 ]

83 голосов
/ 19 ноября 2008

Вы можете использовать метод #send для вызова метода объекта по имени метода:

object.send(:foo) # same as object.foo

Вы можете передавать аргументы вызываемому методу:

object.send(:foo, 1, "bar", 1.23) # same as object.foo(1, "bar", 1.23)

Итак, если у вас есть имя атрибута в переменной "attribute", вы можете прочитать атрибут объекта с помощью

object.send(attribute.to_sym)

и запишите значение атрибута с

object.send("#{attribute}=".to_sym, value)

В Ruby 1.8.6 метод #send может выполнять любой метод объекта независимо от его видимости (вы можете, например, вызывать закрытые методы). Это может измениться в будущих версиях Ruby, и вы не должны на это полагаться. Для выполнения приватных методов используйте #instance_eval:

object.instance_eval {
  # code as block, can reference variables in current scope
}

# or

object.instance_eval <<-CODE
  # code as string, can generate any code text
CODE

Обновление

Вы можете использовать public_send для вызова методов с учетом правил видимости.

object.public_send :public_foo # ok
object.public_send :private_bar # exception
19 голосов
/ 19 ноября 2008

Метод send должен делать то, что вы ищете:

object = "upcase me!"
method = "upcase"
object.send(method.to_sym) # => "UPCASE ME!"
7 голосов
/ 23 ноября 2008

Мэтт и Максим оба являются правильными, но пропустите детали, которые могут помочь вам разобраться в синтаксисе #send: В Ruby вызов метода действительно отправляет сообщение. относительно простое объяснение этого .

2 голосов
/ 19 ноября 2008

Вы также можете сделать

device.instance_eval(attribute)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...