Question

Is there a way in Ruby to take a symbol or string and turn it into a class of the same name?

For instance, if I have a class such as

class Bob
  def talk
     puts "Hi, I'm bob"
  end
end

And a method I have somewhere else in the code is passed a symbol :bob, can I in some way turn that into the class Bob? Maybe something like

b = :Bob.new
b.talk

Or is there a way to do something similar to this?

Was it helpful?

Solution

There are many ways to do this. Your lack of context makes it impossible to elect a "best" way. Here's a few ayways.

Kernel.const_get(:Bob)

eval(:Bob.to_s)

Kernel.const_get(:bob.to_s.capitalize)

OTHER TIPS

Rails

For use with Rails only.

With a string:

"Module".constantize #=> Module
"Class".constantize #=> Class

With a symbol:

:module.to_s.classify.constantize #=> Module
:open_struct.to_s.classify.constantize #=> OpenStruct

If you are dealing with a multi-word symbol, then you'll want to add #classify to the chain to properly handle the capitalization of all the parts of the constant.

http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-constantize

None of the solutions I've seen work if you want to turn :foo_bar into FooBar. If that's what you're looking for:

:foo_bar.to_s.split("_").collect(&:capitalize).join.constantize
=> FooBar

hope that helps someone.

NameSpace.const_get(classname) will return the class object (assuming that classname contains the name of a class - if it contains the name of a constant that is not a class, it will return the value of that constant). The toplevel namespace is Object, so you can do Object.const_get(:Bob).new

class Bob
end

def create(name)
  return eval("#{name}.new")
end

b = create(:Bob)
puts b.class

Here is something that I came up with while looking for something similar that included module/namespace support:

['foo', 'bar'].inject {|r,e| "#{r.classify}::#{e.classify}"}.constantize

Produces

=> Foo::Bar

However this requires Rails and of course it only works where the array has more than one element.

This seems rather simple so I'm sure I'm missing something out, would anyone care to advise why this wouldn't be a good approach?

Thanks!

in my case, both example below worked, but you also have not to forget namespace:

  Object.const_get("ModuleName::#{class_model_name}")

or

  Kernel.const_get("ModuleName::#{class_model_name}").
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top