루비 스트링#to_class
-
11-09-2019 - |
문제
a 이전 응답 할 수있는 수정 사항이 있습니다 SEPP2K네임 스페이스에 대한 주석은 문자열#to_class 메소드를 구현했습니다. 나는 여기서 코드를 공유하고 있으며, 그것이 "I"카운터를 특별히 재현 할 수 있다고 생각합니다. 귀하의 의견은 감사합니다.
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's 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
해결책
호기심으로 벤치 마크를 실행했으며 내 솔루션은 매우 느립니다! 다음은 벤치 마크가있는 리팩토링 된 솔루션입니다.
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's 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)
다른 팁
나는 볼 것이다 ActiveSupport::CoreExtensions::String::Inflections
구체적으로 그것은입니다 constantize
방법:
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
재귀를 사용할 수 있습니다.
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
제휴하지 않습니다 StackOverflow