Variables in Ruby Method Names

I have the following code:

for attribute in site.device_attributes device.attribute end 

where I would like the code to replace the "attribute" value for the method name.

I tried device."#{attribute}" and various permutations.

Is it really impossible? Did I miss something?

I looked at overriding the missing method, but I can't figure out how this really helps me when my problem is that I need to call an "unknown" method.

+44
ruby ruby-on-rails
Nov 19 '08 at 0:52
source share
4 answers

You can use the #send method to call an object method by the method name:

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

You can pass arguments when calling a method:

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

So, if you have the attribute name in the variable "attribute", you can read the attribute of the object with

 object.send(attribute.to_sym) 

and write the attribute value with

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

In Ruby 1.8.6, the #send method can execute any method of an object, regardless of its visibility (you can, for example, call private methods). This may be changed in future versions of Ruby, and you should not rely on it. To execute private methods, use #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 

Update

You can use public_send to call methods regarding visibility rules.

 object.public_send :public_foo # ok object.public_send :private_bar # exception 
+78
Nov 19 '08 at 13:14
source share

The send method should do what you are looking for:

 object = "upcase me!" method = "upcase" object.send(method.to_sym) # => "UPCASE ME!" 
+19
Nov 19 '08 at 1:01
source share

Matt and Maxim are both correct, but do not leave details that can help you understand the syntax of #send: in Ruby, a method call does send a message. Softies on Rails has a relatively direct explanation for this .

+7
Nov 23 '08 at 18:00
source share

you can also do

 device.instance_eval(attribute) 
+2
Nov 19 '08 at 2:03
source share



All Articles