lib/ecoportal/api/common/content/class_helpers.rb in ecoportal-api-v2-0.8.30 vs lib/ecoportal/api/common/content/class_helpers.rb in ecoportal-api-v2-0.8.31
- old
+ new
@@ -1,5 +1,6 @@
+require 'securerandom'
module Ecoportal
module API
module Common
module Content
module ClassHelpers
@@ -8,13 +9,14 @@
# Class resolver
# @note it caches the resolved `klass`es
# @raise [Exception] when could not resolve if `exception` is `true`
# @param klass [Class, String, Symbol] the class to resolve
+ # @param source_class [Class] when the reference to `klass` belongs to a different inheritance chain.
# @param exception [Boolean] if it should raise exception when could not resolve
# @return [Class] the `Class` constant
- def resolve_class(klass, exception: true)
+ def resolve_class(klass, source_class: self, exception: true)
@resolved ||= {}
@resolved[klass] ||=
case klass
when Class
klass
@@ -23,22 +25,28 @@
Kernel.const_get(klass)
rescue NameError => e
raise if exception
end
when Symbol
- resolve_class(self.send(klass))
+ source_class.resolve_class(source_class.send(klass))
+ when Hash
+ referrer, referred = klass.first
+ resolve_class(referred, source_class: referrer, exception: exception)
else
raise "Unknown class: #{klass}" if exception
end
end
# Helper to normalize `key` into a correct `ruby` **constant name**
+ # @note it removes namespace syntax `::`
# @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
+ str_name = key.to_s.strip.split(/::/).compact.map do |str|
+ str.slice(0).upcase + str.slice(1..-1)
+ end.join("").split(/[\-\_ :]+/i).compact.map do |str|
+ str.slice(0).upcase + str.slice(1..-1)
end.join("")
end
# Helper to create an instance variable `name`
# @param [String, Symbol] the name of the variable
@@ -47,24 +55,31 @@
str = name.to_s
str = "@#{str}" unless str.start_with?("@")
str
end
+ # Generates random ids in hexadecimal to use in class name generation.
+ # @param len [Integeter] length of the `uid`
+ # @return [String] a random unique id of length `len`
+ def uid(len = 8);
+ SecureRandom.hex(len/2)
+ 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 namespace [Class, String] an existing `constant` (class or module) the new class will be namespaced on
# @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:)
+ def new_class(name = "Child#{uid}", inherits: self, namespace: inherits)
name = name.to_sym.freeze
class_name = to_constant(name)
- full_class_name = "#{inherits}::#{class_name}"
- unless target_class = resolve_class(full_class_name, exception: false)
+ unless target_class = resolve_class("#{namespace}::#{class_name}", exception: false)
target_class = Class.new(inherits)
- self.const_set class_name, target_class
+ Kernel.const_get(namespace.to_s).const_set class_name, target_class
end
target_class.tap do |klass|
yield(klass) if block_given?
end
@@ -136,10 +151,9 @@
instance_var = instance_variable_name(var)
value = instance_variable_get(instance_var)
subclass.instance_variable_set(instance_var, value.freeze)
end
end
-
end
end
end
end
end