Как установить «динамически» значения переменных? - PullRequest
20 голосов
/ 16 августа 2011

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

Ответы [ 5 ]

60 голосов
/ 16 августа 2011
attr_accessor :variable1, :variable2, :variable3

def set_variables(*attributes)
  attributes.each {|attribute| self.send("#{attribute}=", true)}
end
9 голосов
/ 27 октября 2012

Вот сравнительное сравнение send против 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 просто устанавливает ивар, в то время как send фактически выполняет метод доступа, что бы он ни делал.

Еще одно замечание - оба метода ведут себя по-разному в другом аспекте: если вы instance_variable_set ивар, который не 'пока не существует, оно будет создано.Если вы вызываете метод доступа, который не существует с помощью send, возникнет исключение.

4 голосов
/ 16 августа 2011

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

def set_variables(*attributes)
  attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end
3 голосов
/ 16 августа 2011
def set_attributes(*attributes)
  attributes.each do |attr|
    self.send "#{attr}=", true
  end
end

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

1 голос
/ 19 февраля 2016

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

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