Module: Eco::Language::Klass::AutoLoader

Includes:
Hierarchy, Resolver
Included in:
API::Common::People::PersonParser, API::UseCases
Defined in:
lib/eco/language/klass/auto_loader.rb

Overview

Note:
  • this helpers aim to boost the usage of the ruby language in complex integration configurations.

Helpers for dynamic object loading based on class declaration

Instance Method Summary collapse

Methods included from Hierarchy

#descendants, #descendants?

Methods included from Resolver

#class_resolver, #resolve_class

Instance Method Details

#_autoload_namespace(type, *namespaces) ⇒ Object



65
66
67
# File 'lib/eco/language/klass/auto_loader.rb', line 65

def _autoload_namespace(type, *namespaces)
  autoloaded_namespaces(type).concat(namespaces) unless namespaces.empty?
end

#autoload_children!(object) ⇒ Boolean

Note:

This method should be explicitly called.

It loads/creates a new instance of children classes pending to be loaded.

Returns:

  • (Boolean)

    true if there were children loaded, false otherwise.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/eco/language/klass/auto_loader.rb', line 13

def autoload_children!(object)
  return false if @loading_children
  return false unless autoloaded_class

  pending_children = unloaded_children
  return false if pending_children.empty?

  @loading_children = true

  pending_children.each do |klass|
    @child = klass.new(object)
  rescue TypeError => _e
    # Can't create from this class (must be the singleton class)
    # Just ignore
  ensure
    autoloaded_children.push(klass)
  end

  true
ensure
  @loading_children = false
end

#autoload_class?(constant) ⇒ Boolean

Returns determines if a given namespace is entitled for autoloading.

Parameters:

  • constant (Class, String)

    a class or namespace we want to check auto-load entitlement thereof.

Returns:

  • (Boolean)

    determines if a given namespace is entitled for autoloading



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/eco/language/klass/auto_loader.rb', line 71

def autoload_class?(constant)
  constants = constant.to_s.split("::").compact
  autoload  = true

  unless autoloaded_namespaces(:include).empty?
    autoload = autoloaded_namespaces(:include).any? do |ns|
      ns.to_s.split("::").compact.zip(constants).all? {|(r, c)| r == c}
    end
  end

  unless autoloaded_namespaces(:ignore).empty?
    autoload &&= autoloaded_namespaces(:ignore).none? do |ns|
      ns.to_s.split("::").compact.zip(constants).all? {|(r, c)| r == c}
    end
  end

  autoload
end

#autoload_namespace(*namespaces) ⇒ Object

To restrict which namespaces it is allowed to load from



56
57
58
# File 'lib/eco/language/klass/auto_loader.rb', line 56

def autoload_namespace(*namespaces)
  _autoload_namespace(:include, *namespaces)
end

#autoload_namespace_ignore(*namespaces) ⇒ Object

To ignore certain namespaces this class should not autoload from



61
62
63
# File 'lib/eco/language/klass/auto_loader.rb', line 61

def autoload_namespace_ignore(*namespaces)
  _autoload_namespace(:ignore, *namespaces)
end

#autoloaded_childrenObject

As children are loaded as they are declared, we should not load twice same children.



91
92
93
# File 'lib/eco/language/klass/auto_loader.rb', line 91

def autoloaded_children
  @auto_loaded_children ||= [] # rubocop:disable Naming/MemoizedInstanceVariableName
end

#autoloaded_classObject

Resolves the class autoloader_class if it has been defined via autoloads_children_of



43
44
45
46
47
# File 'lib/eco/language/klass/auto_loader.rb', line 43

def autoloaded_class
  return unless @autoloaded_class

  autoloader_class
end

#autoloaded_namespaces(type = :include) ⇒ Object

To which restricted namespaces this class autoloads from



50
51
52
53
# File 'lib/eco/language/klass/auto_loader.rb', line 50

def autoloaded_namespaces(type = :include)
  @autoloaded_namespaces       ||= {}
  @autoloaded_namespaces[type] ||= []
end

#autoloads_children_of(klass) ⇒ Object

To enable the class autoloader, you should use this method



37
38
39
40
# File 'lib/eco/language/klass/auto_loader.rb', line 37

def autoloads_children_of(klass)
  class_resolver :autoloader_class, klass
  @autoloaded_class = klass
end

#known_class!(*classes) ⇒ Object

Add to known namespaces



120
121
122
# File 'lib/eco/language/klass/auto_loader.rb', line 120

def known_class!(*classes)
  known_classes.concat(classes)
end

#known_classesObject

Known namespaces serves the purpose to discover recently added namespaces provided that the namespace discovery is optimized



115
116
117
# File 'lib/eco/language/klass/auto_loader.rb', line 115

def known_classes
  @known_classes ||= []
end

#new_classesObject

List all new namespaces



125
126
127
# File 'lib/eco/language/klass/auto_loader.rb', line 125

def new_classes
  ObjectSpace.each_object(::Class).to_a - known_classes
end

#unloaded_childrenObject

Children classes of autoloader_class that have not been created an instance of.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/eco/language/klass/auto_loader.rb', line 96

def unloaded_children
  return [] unless autoloaded_class

  new_detected = new_classes
  known_class!(*new_detected)

  descendants(
    parent_class: autoloaded_class,
    scope:        new_detected
  ).select do |child_class|
    next false if autoloaded_children.include?(child_class)
    next false unless autoload_class?(child_class)

    true
  end.sort
end