Ruby String # to_class

Taken from a previous post with some changes, to implement the sepp2k comment about namespaces, I implemented the String # to_class method. I am sharing the code here, and I believe that it can be reorganized in some way specifically for the "i" counter. Your comments are appreciated.

class String def to_class chain = self.split "::" i=0 res = chain.inject(Module) do |ans,obj| break if ans.nil? i+=1 klass = ans.const_get(obj) # Make sure the current obj is a valid class # Or it a module but not the last element, # as the last element should be a class klass.is_a?(Class) || (klass.is_a?(Module) and i != chain.length) ? klass : nil end rescue NameError nil end end #Tests that should be passed. assert_equal(Fixnum,"Fixnum".to_class) assert_equal(M::C,"M::C".to_class) assert_nil "Math".to_class assert_nil "Math::PI".to_class assert_nil "Something".to_class 
+2
ruby metaprogramming introspection
Sep 19 '09 at 14:36
source share
3 answers

I did some tests of curiosity, and my solution is very slow! there is a reorganized solution with benchmarks, I hope this helps.

 require "benchmark" class String def to_class_recursive chain = self.split "::" klass = parent.const_get chain.shift return chain.size < 1 ? (klass.is_a?(Class) ? klass : nil) : chain.join("::").to_class(klass) rescue nil end def to_class_original chain = self.split "::" i=0 res = chain.inject(Module) do |ans,obj| break if ans.nil? i+=1 klass = ans.const_get(obj) # Make sure the current obj is a valid class # Or it a module but not the last element, # as the last element should be a class klass.is_a?(Class) || (klass.is_a?(Module) and i != chain.length) ? klass : nil end rescue NameError nil end def to_class_refactored chain = self.split "::" klass = Kernel chain.each do |klass_string| klass = klass.const_get klass_string end klass.is_a?(Class) ? klass : nil rescue NameError nil end end module M class C end end n = 100000 class_string = "M::C" Benchmark.bm(20) do |x| x.report("to_class_recursive") { n.times { class_string.to_class_recursive } } x.report("to_class_original") { n.times { class_string.to_class_original } } x.report("to_class_refactored") { n.times { class_string.to_class_refactored } } end # user system total real # to_class_recursive 2.430000 0.170000 2.600000 ( 2.701991) # to_class_original 1.000000 0.010000 1.010000 ( 1.049478) # to_class_refactored 0.570000 0.000000 0.570000 ( 0.587346) 
+4
Sep 20 '09 at 8:59
source share

I would look ActiveSupport::CoreExtensions::String::Inflections in particular on the 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 
+6
Sep 19 '09 at 15:11
source share

You can use recursion:

 class String def to_class(parent = Kernel) chain = self.split "::" klass = parent.const_get chain.shift return chain.size < 1 ? (klass.is_a?(Class) ? klass : nil) : chain.join("::").to_class(klass) rescue nil end end 
+2
Sep 19 '09 at 21:25
source share



All Articles