Class: Torikago::RootConstantResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/torikago/root_constant_resolver.rb,
sig/torikago.rbs

Overview

Resolves top-level constants from the main Box while keeping constants owned by registered module roots private to their respective module Box.

Constant Summary collapse

UNRESOLVED =

Returns:

  • (Object)
Object.new.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registered_roots:, main_box: Object) ⇒ RootConstantResolver

Returns a new instance of RootConstantResolver.

Parameters:

  • registered_roots: (Array[Pathname | String])
  • main_box: (Object) (defaults to: Object)


11
12
13
14
15
# File 'lib/torikago/root_constant_resolver.rb', line 11

def initialize(registered_roots:, main_box: Object)
  @registered_roots = registered_roots.map { |root| normalize_path(root) }
  @main_box = main_box
  @unresolved = UNRESOLVED
end

Instance Attribute Details

#main_boxObject (readonly)

Returns the value of attribute main_box.

Returns:

  • (Object)


32
33
34
# File 'lib/torikago/root_constant_resolver.rb', line 32

def main_box
  @main_box
end

#registered_rootsArray[String] (readonly)

Returns the value of attribute registered_roots.

Returns:

  • (Array[String])


32
33
34
# File 'lib/torikago/root_constant_resolver.rb', line 32

def registered_roots
  @registered_roots
end

#unresolvedObject (readonly)

Returns the value of attribute unresolved.

Returns:

  • (Object)


9
10
11
# File 'lib/torikago/root_constant_resolver.rb', line 9

def unresolved
  @unresolved
end

Instance Method Details

#normalize_path(path) ⇒ String

Parameters:

  • path (Pathname, String)

Returns:

  • (String)


62
63
64
65
66
67
# File 'lib/torikago/root_constant_resolver.rb', line 62

def normalize_path(path)
  expanded_path = Pathname(path).expand_path
  expanded_path.exist? ? expanded_path.realpath.to_s : expanded_path.to_s
rescue SystemCallError
  expanded_path.to_s
end

#registered_descendant?(namespace, visited = {}) ⇒ Boolean

Parameters:

  • namespace (Module)
  • visited (Hash[Module, bool]) (defaults to: {})

Returns:

  • (Boolean)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/torikago/root_constant_resolver.rb', line 43

def registered_descendant?(namespace, visited = {})
  return false if visited[namespace]

  visited[namespace] = true
  namespace.constants(false).any? do |name|
    autoload_path = namespace.autoload?(name, false)
    next true if registered_source?(autoload_path)

    source_location = namespace.const_source_location(name, false)
    next true if registered_source?(source_location&.first)
    next false if autoload_path

    child = namespace.const_get(name, false)
    child.is_a?(Module) && registered_descendant?(child, visited)
  rescue NameError
    false
  end
end

#registered_source?(source_path) ⇒ Boolean

Parameters:

  • source_path (String, nil)

Returns:

  • (Boolean)


34
35
36
37
38
39
40
41
# File 'lib/torikago/root_constant_resolver.rb', line 34

def registered_source?(source_path)
  return false unless source_path

  normalized_source = normalize_path(source_path)
  registered_roots.any? do |root|
    normalized_source == root || normalized_source.start_with?("#{root}#{File::SEPARATOR}")
  end
end

#resolve(name) ⇒ Object

Parameters:

  • name (Symbol, String)

Returns:

  • (Object)


17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/torikago/root_constant_resolver.rb', line 17

def resolve(name)
  return unresolved unless main_box.const_defined?(name, false)
  return unresolved if registered_source?(main_box.autoload?(name, false))

  source_location = main_box.const_source_location(name, false)
  return unresolved if registered_source?(source_location&.first)

  constant = main_box.const_get(name, false)
  return unresolved if constant.is_a?(Module) && registered_descendant?(constant)

  constant
end