Kernel#qualified_const_get
The question of how to get a class by name comes up with some regularity on the ruby-talk and rails mailing lists. The first response is usually to use Object::const_get. The response to that is that it doesn't handle classes within namespaces, e.g. Foo::Bar. I might argue that Object::const_get("Foo::Bar") should do the right thing and retrieve the value of Bar from the Foo class/module, but the fact of the matter is that it does not. Having an itch to scratch, I wrote Kernel#qualified_const_get:
module Kernel def qualified_const_get(str) path = str.to_s.split('::') from_root = path[0].empty? if from_root from_root = [] path = path[1..-1] else start_ns = ((Class === self)||(Module === self)) ? self : self.class from_root = start_ns.to_s.split('::') end until from_root.empty? begin return (from_root+path).inject(Object) { |ns,name| ns.const_get(name) } rescue NameError from_root.delete_at(-1) end end path.inject(Object) { |ns,name| ns.const_get(name) } end end
One of the advantages of this usage is that it handles partially qualified constant names. The following does the right thing in both cases:
require 'qualified_const_get' module Foo module Bar class Baz def initialize puts 'You found me!' end end end def self.find_it klass = qualified_const_get("Bar::Baz") klass.new end module Quux def self.find_it klass = qualified_const_get("Bar::Baz") klass.new end end end Foo::find_it Foo::Quux::find_itEnjoy!
2 Comments:
At 6/30/2006 03:16:00 PM, Gregory said…
Of those, only the facets link has comparable functionality, and even that isn't quite as good because it will not attempt to start from the root namespace if it is not found in the relative namespace, though it will respect an initial ::. Also, you got the link slightly wrong. It should be:
http://facets.rubyforge.org/doc/api/core/classes/Kernel.html#M000405
At 12/02/2011 09:34:00 AM, Lukáš Zapletal said…
Your code contains a bug, try it with two classes with the same name (but different module). Returns the top level one.
Post a Comment
<< Home