How do I get class-object from string “A::B::C” in

2019-03-19 20:13发布

问题:

The following example fails

class A
  class B
  end
end
p Object.const_get 'A' # => A
p Object.const_get 'A::B' # => NameError: wrong constant name A::B

UPDATE

Questions about the topic asked earlier:

  1. Cast between String and Classname
  2. Ruby String#to_class
  3. Get a class by name in Ruby?

The last one gives a nice solution which can be evolved into

class String
  def to_class
    self.split('::').inject(Object) do |mod, class_name|
      mod.const_get(class_name)
    end
  end
end

class A
  class B
  end
end
p "A::B".to_class # => A::B

回答1:

You'll have to manually "parse" the colons yourself and call const_get on the parent module/class:

ruby-1.9.1-p378 > class A
ruby-1.9.1-p378 ?>  class B
ruby-1.9.1-p378 ?>    end
ruby-1.9.1-p378 ?>  end
 => nil 
ruby-1.9.1-p378 > A.const_get 'B'
 => A::B 

Someone has written a qualified_const_get that may be of interest.



回答2:

Here is Rails' constantize method:

def constantize(camel_cased_word)
  names = camel_cased_word.split('::')
  names.shift if names.empty? || names.first.empty?

  constant = Object
  names.each do |name|
    constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
  end
  constant
end

See, it starts at the Object on top of it all, then uses each name in between the double semicolons as a stepping stone to get to the constant you want.



回答3:

Extlib provides a full_const_get method, which does just this.

http://github.com/datamapper/extlib/blob/master/lib/extlib/object.rb#L67

You could either include extlib, or copy this implementation and use it yourself (assuming the licensing is compatible with whatever you're using it for)



回答4:

You can do this with eval also which works in some cases where const_get won't. There's a good article on this here: http://blog.sidu.in/2008/02/loading-classes-from-strings-in-ruby.html#.T8j88HlYtXc