Module: Ecoportal::API::Common::Content::ClassHelpers

Includes:
BaseClass
Included in:
DoubleModel
Defined in:
lib/ecoportal/api/common/content/class_helpers.rb

Constant Summary collapse

NOT_USED =
"no_used!".freeze

Instance Method Summary collapse

Instance Method Details

#inheritable_attrs(*attrs) ⇒ Object

Builds the attr_reader and attr_writer of attrs and registers the associated instance variable as inheritable.



134
135
136
137
138
139
140
141
142
143
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 134

def inheritable_attrs(*attrs)
  attrs.each do |attr|
    class_eval <<-DEF_CLSS_ATTR, __FILE__, __LINE__ + 1
      class << self            # class << self
        attr_accessor :#{attr} #   attr_accessor :coolio
      end                      # end
    DEF_CLSS_ATTR
  end
  inheritable_class_vars(*attrs)
end

#inheritable_class_vars(*vars) ⇒ Object

Note:

Keeps track on class instance variables that should be inherited by child classes. TODO: this separates the logic of the method to the instance var. Think if would be possible to join them somehow.



128
129
130
131
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 128

def inheritable_class_vars(*vars)
  @inheritable_class_vars ||= [:inheritable_class_vars]
  @inheritable_class_vars += vars
end

#inherited(subclass) ⇒ Object

Note:
  • values of the instance variables are copied as they are (no dups or clones)
  • the above means: avoid methods that change the state of the mutable object on it
  • mutating methods would reflect the changes on other classes as well
  • therefore, freeze will be called on the values that are inherited.

This callback method is called whenever a subclass of the current class is created.



151
152
153
154
155
156
157
158
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 151

def inherited(subclass)
  super
  inheritable_class_vars.each do |var|
    instance_var = instance_variable_name(var)
    value        = instance_variable_get(instance_var)
    subclass.instance_variable_set(instance_var, value.freeze)
  end
end

#instance_variable_name(name) ⇒ Object

Helper to create an instance variable name

Parameters:

  • the (String, Symbol)

    name of the variable



54
55
56
57
58
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 54

def instance_variable_name(name)
  str = name.to_s
  str = "@#{str}" unless str.start_with?("@")
  str
end

#new_class(name = "Child#{uid}", inherits: self, namespace: inherits) {|child_class| ... } ⇒ Class

If the class for name exists, it returns it. Otherwise it generates it.

Parameters:

  • name (String, Symbol) (defaults to: "Child#{uid}")

    the name of the new class

  • inherits (Class) (defaults to: self)

    the parent class to inherit from

  • namespace (Class, String) (defaults to: inherits)

    an existing constant (class or module) the new class will be namespaced on

Yields:

  • (child_class)

    configure the new class

Yield Parameters:

  • child_class (Class)

    the new class

Returns:

  • (Class)

    the new generated class



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 75

def new_class(name = "Child#{uid}", inherits: self, namespace: inherits)
  name         = name.to_s.to_sym.freeze
  class_name   = to_constant(name)
  target_class = resolve_class("#{namespace}::#{class_name}", exception: false)

  unless target_class
    target_class = Class.new(inherits)
    Kernel.const_get(namespace.to_s).const_set class_name, target_class
  end

  target_class.tap do |klass|
    yield(klass) if block_given?
  end
end

#resolve_class(klass, source_class: self, exception: true) ⇒ Class

Note:

it caches the resolved klasses

Class resolver

Parameters:

  • klass (Class, String, Symbol)

    the class to resolve

  • source_class (Class) (defaults to: self)

    when the reference to klass belongs to a different inheritance chain.

  • exception (Boolean) (defaults to: true)

    if it should raise exception when could not resolve

Returns:

  • (Class)

    the Class constant

Raises:

  • (Exception)

    when could not resolve if exception is true



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 17

def resolve_class(klass, source_class: self, exception: true)
  @resolved ||= {}
  @resolved[klass] ||=
    case klass
    when Class
      klass
    when String
      begin
        Kernel.const_get(klass)
      rescue NameError
        raise if exception
      end
    when Symbol
      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

#to_constant(key) ⇒ String

Note:

it removes namespace syntax ::

Helper to normalize key into a correct ruby constant name

Parameters:

  • key (String, Symbol)

    to be normalized

Returns:

  • (String)

    a correct constant name



43
44
45
46
47
48
49
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 43

def to_constant(key)
  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

#to_time(value, exception: true) ⇒ Object

Helper to parse a value into a Time object.

Parameters:

  • value (String, Date)

    the value to convert to Time

  • exception (Boolean) (defaults to: true)

    if should raise Exception when could not convert

Returns:

Raises:

  • (Exception)

    if exception is true and could not convert



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 95

def to_time(value, exception: true)
  case value
  when Time, NilClass
    value
  when String
    begin
      Time.parse(value)
    rescue ArgumentArgument
      raise if exception
      nil
    end
  when Date
    Time.parse(value.to_s)
  else
    to_time(value.to_s) if value.respond_to?(:to_s)
  end
end

#uid(len = 8) ⇒ String

Generates random ids in hexadecimal to use in class name generation.

Parameters:

  • len (Integeter) (defaults to: 8)

    length of the uid

Returns:

  • (String)

    a random unique id of length len



63
64
65
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 63

def uid(len = 8)
  SecureRandom.hex(len/2)
end

#used_param?(val) ⇒ Boolean

Note:

to effectivelly use this helper, you should initialize your target paramters with the constant NOT_USED

Helper to determine if a paramter has been used

Parameters:

  • val

    [] the value of the paramter

Returns:

  • (Boolean)

    true if value other than NOT_USED, false otherwise



118
119
120
# File 'lib/ecoportal/api/common/content/class_helpers.rb', line 118

def used_param?(val)
  val != NOT_USED
end