Setting instance variable "dynamically"

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

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 :slight_smile:

Cheers,
Martin

···

On Sunday 18 January 2004 17:29, Bauduin Raphael wrote:

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 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 A; end; a = A.new
=> #<A:0x401ff0d8>
a.instance_variable_set :@foo, “foo”
=> “foo”
a
=> #<A:0x401ff0d8 @foo=“foo”>
a.instance_variable_get :@foo
=> “foo”

···

On Mon, Jan 19, 2004 at 02:29:59AM +0900, Bauduin Raphael wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
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

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
=> #<C:0x2810628 @b=20, @a=10>
c.send(“a”,10)
NoMethodError: undefined method a' for #<C:0x2810628 @b=20, @a=10> from (irb):8:in send’
from (irb):8
class C
def initialize
@a,@b=10,20
end
attr_accessor :a, :b
end
=> nil
c.send(“a”,10)
ArgumentError: wrong number of arguments(1 for 0)
from (irb):15:in a' from (irb):15:in send’
from (irb):15
c.send(“a”+“=”,10)
=> 10
c.a
=> 10

you may even use instance_eval(“@a=”+value.to_s)

···

il Sun, 18 Jan 2004 18:26:22 +0100, Bauduin Raphael rb@raphinou.com ha scritto::

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?

Using the following

class Q
attr_accessor :field
end
q = Q.new

here are some times for looping 1000000 times setting the index:
i.e. 1.upto(1000000){|i| }

q.send(“field=”, i) took 2.203 seconds
q.send(:field=, i) took 1.251 seconds
q.instance_eval{field = i} took 4.187 seconds
q.instance_variable_set “@field”, i took 2.032 seconds
q.instance_variable_set :@field, i took 1.072 seconds
q.field = i took 0.921 seconds

P.S. These timings are for the PragProg installer
ruby 1.8.0 (2003-08-04) [i386-mswin32]

Walt

···

Walter Szewelanczyk
IS Director
M.W. Sewall & CO. email : walter@mwsewall.com
259 Front St. Phone : (207) 442-7994 x 128
Bath, ME 04530 Fax : (207) 443-6284


Thanks for the answers!

In my class I now use this :

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

Raph

Mauricio Fernández wrote:

···

On Mon, Jan 19, 2004 at 02:29:59AM +0900, Bauduin Raphael wrote:

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 A; end; a = A.new

=> #<A:0x401ff0d8>

a.instance_variable_set :@foo, “foo”

=> “foo”

a

=> #<A:0x401ff0d8 @foo=“foo”>

a.instance_variable_get :@foo

=> “foo”

gabriele renzi wrote:

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?”

···


– Jim Weirich jweirich@one.net http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

“Bauduin Raphael” rb@raphinou.com schrieb im Newsbeitrag
news:400ad514$0$1128$6c56d894@feed0.news.be.easynet.net

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

“Jim Weirich” jweirich@one.net schrieb im Newsbeitrag
news:400BD300.3010906@one.net

gabriele renzi wrote:

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)

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
=> #<Foo:0x10197f08 @x=“xx”, @y=“hu!”>
irb(main):014:0>

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

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

···

On Monday 19 January 2004 14:10, Robert Klemme wrote:

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. :-))


Martin Hart
Arnclan Limited
53 Union Street
Dunstable, Beds
LU6 1EX
http://www.arnclanit.com

“Martin Hart” martin@zsdfherg.com schrieb im Newsbeitrag
news:200401191504.29943.martin@zsdfherg.com

···

On Monday 19 January 2004 14:10, Robert Klemme wrote:

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. :-))

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