Ответ 1
attr_accessor :variable1, :variable2, :variable3
def set_variables(*attributes)
attributes.each {|attribute| self.send("#{attribute}=", true)}
end
Я использую Ruby on Rails 3.0.9, и я пытаюсь установить "динамически" некоторые значения переменных. Это...
... в моем файле модели у меня есть:
attr_accessor :variable1, :variable2, :variable3
# The 'attributes' argument contains one or more symbols which name is equal to
# one or more of the 'attr_accessor' symbols.
def set_variables(*attributes)
# Here I should set to 'true' all ":variable<N>" attributes passed as symbol
# in the 'attributes' array, but variable names should be interpolated in a
# string.
#
# For example, I should set something like "prefix_#{':variable1'.to_s}_suffix".
end
Как установить эти значения переменных в true
?
Я попытался использовать метод self.send(...)
, но мне это не удалось (но, вероятно, я не знаю, как вообще использовать этот метод send
... возможно ли это сделать с тем, что мне нужно используя метод send
?!).
attr_accessor :variable1, :variable2, :variable3
def set_variables(*attributes)
attributes.each {|attribute| self.send("#{attribute}=", true)}
end
Здесь сравнительное сравнение send
vs instance_variable_set
:
require 'benchmark'
class Test
VAR_NAME = '@foo'
ATTR_NAME = :foo
attr_accessor ATTR_NAME
def set_by_send i
send("#{ATTR_NAME}=", i)
end
def set_by_instance_variable_set i
instance_variable_set(VAR_NAME, i)
end
end
test = Test.new
Benchmark.bm do |x|
x.report('send ') do
1_000_000.times do |i|
test.set_by_send i
end
end
x.report('instance_variable_set') do
1_000_000.times do |i|
test.set_by_instance_variable_set i
end
end
end
И тайминги:
user system total real
send 1.000000 0.020000 1.020000 ( 1.025247)
instance_variable_set 0.370000 0.000000 0.370000 ( 0.377150)
(измерено с использованием 1.9.2)
Следует отметить, что только в определенных ситуациях (например, с аксессуарами, определенными с использованием attr_accessor
), send
и instance_variable_set
функционально эквивалентны. Если в аксессуре есть какая-то логика, будет разница, и вам придется решить, какой вариант вам нужен. instance_variable_set
просто устанавливает ivar, а send
фактически выполняет метод доступа, независимо от того, что он делает.
Еще одно замечание - эти два метода ведут себя по-другому в другом аспекте: если вы instance_variable_set
ивар, который еще не существует, он будет создан. Если вы вызываете аксессор, который не существует с помощью send
, будет создано исключение.
Метод, которым вы пользуетесь, instance_variable_set
, поэтому в вашем случае:
def set_variables(*attributes)
attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end
def set_attributes(*attributes)
attributes.each do |attr|
self.send "#{attr}=", true
end
end
Помните, что имена методов setter заканчиваются на =
в Ruby.
Я знаю, что вопрос был для Rails 3, но вопрос возник при поиске ответов Rails 4 о том, как "динамически получить доступ к значениям переменных". Я тестировал это на своей модели и отлично работал в качестве альтернативы предлагаемым решениям:
def set_variables(*attributes)
attributes.each {|attribute| self["#{attribute}"] = true}
end