Подтвердить что ты не робот

Как установить "динамически" значения переменных?

Я использую 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?!).

4b9b3361

Ответ 1

attr_accessor :variable1, :variable2, :variable3

def set_variables(*attributes)
  attributes.each {|attribute| self.send("#{attribute}=", true)}
end

Ответ 2

Здесь сравнительное сравнение 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, будет создано исключение.

Ответ 3

Метод, которым вы пользуетесь, instance_variable_set, поэтому в вашем случае:

def set_variables(*attributes)
  attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end

Ответ 4

def set_attributes(*attributes)
  attributes.each do |attr|
    self.send "#{attr}=", true
  end
end

Помните, что имена методов setter заканчиваются на = в Ruby.

Ответ 5

Я знаю, что вопрос был для Rails 3, но вопрос возник при поиске ответов Rails 4 о том, как "динамически получить доступ к значениям переменных". Я тестировал это на своей модели и отлично работал в качестве альтернативы предлагаемым решениям:

def set_variables(*attributes)
  attributes.each {|attribute| self["#{attribute}"] = true}
end