setting instance variable "dynamically"

B

Bauduin Raphael

I saw in the pickaxe there's a way to call methods dynamically, with
send("method_name"):

"test".send("length") # 4

What I want to do is set a variable this way. Is it possible?

I'm working on a translation tool for a website. rows returned
are of the form:
["id", "language", "value"]

the value of the language field is the identical to the member variable
that will contain the row (wrapped in an object actually).

I thought of something like this:

class Term
attr :query, :fr, :nl, :en
def initialize(dbh, id)
@query = "select * from translations where id='#{id}'"
dbh.select_all(query) do |row|
self.send(row[1].to_s)=Translation.new(row)
end
end
def get_french()
@fr.value
end
end

But that isn't accepted.
Does anyone have the solution?

Thanks

Raph
 
M

Martin Hart

I saw in the pickaxe there's a way to call methods dynamically, with
send("method_name"):

"test".send("length") # 4

What I want to do is set a variable this way. Is it possible?

class MyClass
def initialize
@name = "fred"
end
end

m = MyClass.new
m.instance_eval { @name = "freda" }

var = "name"
m.instance_eval("@#{var} = 'frederick'")

the second is a bit messy - I'm sure there is an easier way :)

Cheers,
Martin
 
M

Mauricio Fernández

I saw in the pickaxe there's a way to call methods dynamically, with
send("method_name"):

"test".send("length") # 4

What I want to do is set a variable this way. Is it possible?
=> "foo"

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

No, that's wrong too. Now there's a race condition between the rm and
the mv. Hmm, I need more coffee.
-- Guy Maor on Debian Bug#25228
 
B

Bauduin Raphael

Thanks for the answers!

In my class I now use this :

instance_eval("@#{row[1]}=Translation.new(row)")



Raph
 
G

gabriele renzi

I saw in the pickaxe there's a way to call methods dynamically, with
send("method_name"):

"test".send("length") # 4

What I want to do is set a variable this way. Is it possible?

I'm working on a translation tool for a website. rows returned
are of the form:
["id", "language", "value"]

the value of the language field is the identical to the member variable
that will contain the row (wrapped in an object actually).

I thought of something like this:

class Term
attr :query, :fr, :nl, :en
def initialize(dbh, id)
@query = "select * from translations where id='#{id}'"
dbh.select_all(query) do |row|
self.send(row[1].to_s)=Translation.new(row)
end
end
def get_french()
@fr.value
end
end

But that isn't accepted.
Does anyone have the solution?
class C
def initialize
@a,@b=10,20
end
end => nil
ary=['a','b'] => ["a", "b"]
c=C.new
=> # said:
c.send("a",10)
NoMethodError: undefined method `a' for #<C:0x2810628 @b=20, @a=10>
from (irb):8:in `send'
from (irb):8ArgumentError: wrong number of arguments(1 for 0)
from (irb):15:in `a'
from (irb):15:in `send'
from (irb):15=> 10


you may even use instance_eval("@a="+value.to_s)
 
R

Robert Klemme

Bauduin Raphael said:
Thanks for the answers!

In my class I now use this :

instance_eval("@#{row[1]}=Translation.new(row)")

I'd prefer using "instance_variable_set" because that doesn't require a
setter method to be defined.

irb(main):007:0> class Foo;end
=> nil
irb(main):008:0> f=Foo.new
=> #<Foo:0x10182008>
irb(main):009:0> f.instance_variable_set "@foo", "bar"
=> "bar"
irb(main):010:0> f
=> #<Foo:0x10182008 @foo="bar">
irb(main):011:0>

With your code:

class Term
attr :query, :fr, :nl, :en
def initialize(dbh, id)
@query = "select * from translations where id='#{id}'"
dbh.select_all(query) do |row|
instance_variable_set "@"+row[1], Translation.new(row)
end
end
def get_french()
@fr.value
end
end

Regards

robert
 
J

Jim Weirich

gabriele said:
you may even use instance_eval("@a="+value.to_s)

Be aware that this only works when "value" has valid string
representation that can be reliably converted back to an object. And
then you only get a copy, not the original object.

The following will work with arbitrary objects ...

obj.instance_eval("lambda { |v| @a = v }").call(value)

At this point you must be thinking: "Why don't I just use
instance_variable_set?"
 
R

Robert Klemme

Jim Weirich said:
Be aware that this only works when "value" has valid string
representation that can be reliably converted back to an object. And
then you only get a copy, not the original object.

The following will work with arbitrary objects ...

obj.instance_eval("lambda { |v| @a = v }").call(value)

Well, you can do it simpler, even if you *want* to use instance_eval. No
need for a lambda:

irb(main):001:0> class Foo
irb(main):002:1> def test(obj)
irb(main):003:2> instance_eval("@x=obj")
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> f=Foo.new
=> #<Foo:0x10197f08>
irb(main):007:0> f.test "fff"
=> "fff"
irb(main):008:0> f
=> #<Foo:0x10197f08 @x="fff">
irb(main):009:0> f.test "xx"
=> "xx"
irb(main):010:0> f
=> #<Foo:0x10197f08 @x="xx">
irb(main):011:0> x="hu!"
=> "hu!"
irb(main):012:0> f.instance_eval "@y=x"
=> "hu!"
irb(main):013:0> f
At this point you must be thinking: "Why don't I just use
instance_variable_set?"

I'd love to see the answer to this question you'd suggest. :))

Cheers

robert
 
R

Robert Klemme

Martin Hart said:
running an earlier version of Ruby?
My installation (1.6.8) does not appear to have this function.

That's correctly observed. In that case using instance_eval works better
by an order of magnitude.

Regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top