Converting a string to a class


#1

Take the following snippet:

module SomeModule
class SomeClass
SomeConstant = 3.1415
end
end

var = “SomeModule::SomeClass”
print(var::SomeConstant)

This raises TypeError. So far, the only way I’ve found to do this (and
let me warn you, I’m quite new to Ruby so I may just be missing
something right in front of me) is like this:

var = “SomeModule::SomeClass”
eval "var = " + var
print(var::SomeConstant)

which does indeed work, but I figure there has got to be a better way
than using eval.


#2

On 2/22/06, Anthony DeRobertis removed_email_address@domain.invalid wrote:

Take the following snippet:

why do string conversion?

You can pass constants around in ruby just fine.

D:\Documents and Settings\Administrator>irb
irb(main):001:0> a = String
=> String
irb(main):002:0> a.new
=> “”
irb(main):003:0>

also, to get at a constant within a class, you just do
SomeClass::SomeConstant

D:\Documents and Settings\Administrator>irb
irb(main):001:0> class A
irb(main):002:1> B = “hi”
irb(main):003:1> end
=> “hi”
irb(main):004:0> A::B
=> “hi”


#3

On Feb 22, 2006, at 4:03 PM, Anthony DeRobertis wrote:

This raises TypeError. So far, the only way I’ve found to do this (and
let me warn you, I’m quite new to Ruby so I may just be missing
something right in front of me) is like this:

var = “SomeModule::SomeClass”
eval "var = " + var
print(var::SomeConstant)

which does indeed work, but I figure there has got to be a better way
than using eval.

The usual idiom for this is const_get(). It’s a little tricky in
this case, because of the nesting though:

module SomeModule
class SomeClass
SomeConstant = 3.1415
end
end
=> 3.1415

var = “SomeModule::SomeClass”
=> “SomeModule::SomeClass”

consts = var.split("::")
=> [“SomeModule”, “SomeClass”]

cls = consts.inject(Object) { |last, cur| last.const_get(cur) }
=> SomeModule::SomeClass

puts cls::SomeConstant
3.1415
=> nil

Hope this gives you some fresh ideas.

James Edward G. II


#4

James Edward G. II wrote:

cls = consts.inject(Object) { |last, cur| last.const_get(cur) }
=> SomeModule::SomeClass

Thanks! That’ll work great, especially since the SomeModule:: part is
constant, so I can just do SomeModule.const_get(name).

Thank you very much.


#5

Gregory B. wrote:

On 2/22/06, Anthony DeRobertis removed_email_address@domain.invalid wrote:

Take the following snippet:

why do string conversion?

You can pass constants around in ruby just fine.

I’m scanning a directory for plugins and loading them. When I load a
file called, for example, some_plugin.rb, I assume it creates a class
Whatever::Plugins::SomePlugin, which I naturally only have as a
string…


#6

Just learning, but what’s wrong with eval? I do something like the
following in order to convert from a string to an object of the type
specified by the string:

a = “MyClass”
my_class = eval(a)
my_class.to_s

Michael


#7

On Feb 23, 2006, at 9:37 AM, Michael T. wrote:

Just learning, but what’s wrong with eval? I do something like the
following in order to convert from a string to an object of the type
specified by the string:

a = “MyClass”
my_class = eval(a)
my_class.to_s

eval() is a very powerful tool that we probably shouldn’t use unless
we absolutely need too. What if the String contains typos or
malicious code? Also, it should be slower to compile and run some
code that to just do a constant lookup. Probably better to use the
tools intended for the operation is all.

James Edward G. II


#8

On Feb 23, 2006, at 9:07 AM, Anthony DeRobertis wrote:

file called, for example, some_plugin.rb, I assume it creates a class
Whatever::Plugins::SomePlugin, which I naturally only have as a
string…

You can do this without using the name assumptions in Ruby, if you
give them a class to inherit from. Classes get notified when they
are subclassed:

class Plugin
def self.inherited( plugin_class )
(@@plugins ||= Array.new) << plugin_class
end
def self.loaded
@@plugins || Array.new
end
end
=> nil

class FirstPlugin < Plugin; end
=> nil

class SecondPlugin < Plugin; end
=> nil

Plugin.loaded
=> [FirstPlugin, SecondPlugin]

Hope that gives you some fresh ideas.

James Edward G. II


#9

Thanks for the info. I’ll have to keep that in mind.

Michael


#10

On Fri, 24 Feb 2006, James Edward G. II wrote:

(@@plugins ||= Array.new) << plugin_class

Plugin.loaded
=> [FirstPlugin, SecondPlugin]

Hope that gives you some fresh ideas.

i’ve abstracted this pattern as the ‘dynaload’ library here

http://rubyforge.org/frs/?group_id=1024&release_id=3786

regards.

-a