开发者

How to set "dynamically" variable values?

I am using Ruby on Rails 3.0.9 and I am trying to set "dynamically" some variable values. That is...

... in my model file I have:

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 开发者_Python百科set something like "prefix_#{':variable1'.to_s}_suffix".

end

How can I set those variable values to true?


I tried to use the self.send(...) method, but I did not succeed (but, probably, I don't know how to use at all that send method... is it possible do to that I need by using the send method?!).


attr_accessor :variable1, :variable2, :variable3

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


Here's the benchmark comparison of 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

And the timings are:

      user     system      total        real
send                   1.000000   0.020000   1.020000 (  1.025247)
instance_variable_set  0.370000   0.000000   0.370000 (  0.377150)

(measured using 1.9.2)

It should be noted that only in certain situations (like this one, with accessor defined using attr_accessor) are send and instance_variable_set functionally equivalent. If there is some logic in the accessor involved, there would be a difference, and you would have to decide which variant you would need of the two. instance_variable_set just sets the ivar, while send actually executes the accessor method, whatever it does.

Another remark - the two methods behave differently in another aspect: if you instance_variable_set an ivar which doesn't exist yet, it will be created. If you call an accessor which doesn't exist using send, an exception would be raised.


The method you're after is instance_variable_set so in your case:

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

Remember that setter method names end with = in Ruby.


I know the question was for Rails 3, but the question came up when searching for Rails 4 answers about "how to dynamically access variable values". I tested this on my model and it worked great as an alternative to the proposed solutions:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜