module Eco module API module Common module ClassHelpers def class_resolver(name, klass) define_singleton_method(name) { resolve_class(klass) } define_method(name) { self.class.resolve_class(klass) } end def resolve_class(klass, exception: true) @resolved ||= {} @resolved[klass] ||= case klass when Class klass when String begin Kernel.const_get(klass) rescue NameError => e raise if exception end when Symbol resolve_class(self.send(klass)) else raise "Unknown class: #{klass}" if exception end end # Helper to normalize `key` into a correct `ruby` **constant name** # @param key [String, Symbol] to be normalized # @return [String] a correct constant name def to_constant(key) str_name = key.to_s.strip.split(/[\-\_ ]/i).compact.map do |str| str.slice(0).upcase + str.slice(1..-1).downcase end.join("") end # If the class for `name` exists, it returns it. Otherwise it generates it. # @param name [String, Symbol] the name of the new class # @param inherits [Class] the parent class to _inherit_ from # @param parent_space [String] parent namespace of the generated class, if not given: `self` # @yield [child_class] configure the new class # @yieldparam child_class [Class] the new class # @return [Class] the new generated class def new_class(name, inherits:, parent_space: nil) name = name.to_sym.freeze class_name = to_constant(name) parent_space = parent_space ? resolve_class(parent_space) : self full_class_name = "#{parent_space}::#{class_name}" unless target_class = resolve_class(full_class_name, exception: false) target_class = Class.new(inherits) parent_space.const_set class_name, target_class end target_class.tap do |klass| yield(klass) if block_given? end end end end end end