I hope someone can help with this - I am a Ruby newbie.
In my code I want to decide at runtime which type of object to create,
based on a variable holding the name of the class.
So I have classes Foo and Bar and a string todays_class.
If todays_class = “Foo” I want to say my_obj = Foo.new
if todayS_class = “Bar” then my_obj = Bar.new
Except I’ve got a lot more than two classes and I’d prefer not to use an
if or case statement, so that I don’t need to change the code if I add
another one to the list.
Except I’ve got a lot more than two classes and I’d prefer not to
use an
if or case statement, so that I don’t need to change the code if I add
another one to the list.
Any suggestions on a neat way to do this?
class Foo; end
=> nil
class Bar; end
=> nil
cls = “Foo”
=> “Foo”
Object.const_get(cls)
=> Foo
Or, for nested classes…
?> class Foo
class Baz; end
end
=> nil
cls = “Foo::Baz”
=> “Foo::Baz”
cls.split("::").inject(Object) do |parent, constant|
?> parent.const_get(constant)
You can use eval() to do that, like so:
irb(main):001:0> a=‘String’
=> “String”
irb(main):002:0> b=eval("#{a}.new")
=> “”
irb(main):003:0> b.class
=> String
irb(main):004:0>
In the second irb line, the contents of the variable a are substituted
in the string before the .new. It amounts to b=eval(“String.new”).
Regards,
JJ
John - thanks, also a neat solution. Having had experience mainly in
static/compiled languages previously, I am just getting to grips with
Ruby’s nice features for adapting itself as it runs.
static/compiled languages previously, I am just getting to grips with
Ruby’s nice features for adapting itself as it runs.
you might want to check out Hal F.'s article ‘An Exercise in
Metaprogramming with Ruby’, where amongst other things he provides a
solution to your problem:
You can use eval() to do that, like so:
irb(main):001:0> a=‘String’
=> “String”
irb(main):002:0> b=eval(“#{a}.new”)
=> “”
irb(main):003:0> b.class
=> String
irb(main):004:0>
In the second irb line, the contents of the variable a are substituted
in the string before the .new. It amounts to b=eval(“String.new”).
Regards,
JJ
On Friday, April 28, 2006, at 02:55PM, Bill Roberts [email protected] wrote:
Except I’ve got a lot more than two classes and I’d prefer not to use an
Help everyone. If you can’t do that, then at least be nice.
On Mon, May 01, 2006 at 08:52:12PM +0900, Bill Roberts wrote:
} John J. wrote:
} > You can use eval() to do that, like so:
} > irb(main):001:0> a=‘String’
} > => “String”
} > irb(main):002:0> b=eval("#{a}.new")
} > => “”
} > irb(main):003:0> b.class
} > => String
} > irb(main):004:0>
} >
} > In the second irb line, the contents of the variable a are
substituted
} > in the string before the .new. It amounts to b=eval(“String.new”).
} > Regards,
} > JJ
} >
} >
} John - thanks, also a neat solution. Having had experience mainly in
} static/compiled languages previously, I am just getting to grips with
} Ruby’s nice features for adapting itself as it runs.
–Greg
I hope someone can help with this - I am a Ruby newbie.
In my code I want to decide at runtime which type of object to create,
based on a variable holding the name of the class.
It (may be) worth noting that because classes are “first class
objects” in Ruby, you can reference the actual class’s object with a
variable, if you wish:
Hi Greg, would you mind telling me why? is this more expensive? insecure?
I´m another newcomer to Ruby and this kind of tips are gold to me.
Mostly speed, but many people (myself included) find it easier to read.
const_get is about 10 times faster than eval:
ruby eval_bench.rb
user system total real
eval: 1.140000 0.000000 1.140000 ( 1.141000)
const_get: 0.157000 0.000000 0.157000 ( 0.156000)
#eval_bench.rb
require ‘benchmark’
class Foo;end
some_class = ‘Foo’
Benchmark.bm(10) do |b|
b.report(“eval:”) { 100000.times {eval(“#{some_class}.new”)} }
b.report(“const_get:”) {
100000.times{Object.const_get(some_class).new} }
end
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.