Class: Toys::ModuleLookup

Inherits:
Object
  • Object
show all
Defined in:
lib/toys/module_lookup.rb

Overview

A helper module that provides methods to do module lookups. This is used to obtain named helpers, middleware, and templates from the respective modules.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeModuleLookup

Create an empty ModuleLookup



58
59
60
61
62
# File 'lib/toys/module_lookup.rb', line 58

def initialize
  @mutex = ::Monitor.new
  @paths = []
  @paths_locked = false
end

Class Method Details

.path_to_module(path) ⇒ Module

Given a require path, return the module expected to be defined.

Parameters:

  • path (String)

    File path, delimited by forward slash

Returns:

  • (Module)

    The module loaded from that path



44
45
46
47
48
49
50
51
52
# File 'lib/toys/module_lookup.rb', line 44

def path_to_module(path)
  path.split("/").reduce(::Object) do |running_mod, seg|
    mod_name = to_module_name(seg)
    unless running_mod.constants.include?(mod_name)
      raise ::NameError, "Module #{running_mod.name}::#{mod_name} not found"
    end
    running_mod.const_get(mod_name)
  end
end

.to_module_name(str) ⇒ Symbol

Convert the given string to a module name. Specifically, converts to UpperCamelCase, and then to a symbol.

Parameters:

  • str (String, Symbol)

    String to convert.

Returns:

  • (Symbol)

    Converted name



33
34
35
36
# File 'lib/toys/module_lookup.rb', line 33

def to_module_name(str)
  str = str.to_s.sub(/^_/, "").sub(/_$/, "").gsub(/_+/, "_")
  str.to_s.gsub(/(?:^|_)([a-zA-Z])/) { ::Regexp.last_match(1).upcase }.to_sym
end

.to_path_name(str) ⇒ String

Convert the given string to a path element. Specifically, converts to lower_snake_case.

Parameters:

  • str (String, Symbol)

    String to convert.

Returns:

  • (String)

    Converted string



20
21
22
23
24
# File 'lib/toys/module_lookup.rb', line 20

def to_path_name(str)
  str = str.to_s.sub(/^_/, "").sub(/_$/, "").gsub(/_+/, "_")
  while str.sub!(/([^_])([A-Z])/, "\\1_\\2") do end
  str.downcase
end

Instance Method Details

#add_path(path_base, module_base: nil, high_priority: false) ⇒ self

Add a lookup path for modules.

Parameters:

  • path_base (String)

    The base require path

  • module_base (Module) (defaults to: nil)

    The base module, or nil (the default) to infer a default from the path base.

  • high_priority (Boolean) (defaults to: false)

    If true, add to the head of the lookup path, otherwise add to the end.

Returns:

  • (self)


74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/toys/module_lookup.rb', line 74

def add_path(path_base, module_base: nil, high_priority: false)
  module_base ||= ModuleLookup.path_to_module(path_base)
  @mutex.synchronize do
    raise "You cannot add a path after a lookup has already occurred." if @paths_locked
    if high_priority
      @paths.unshift([path_base, module_base])
    else
      @paths << [path_base, module_base]
    end
  end
  self
end

#lookup(name) ⇒ Module

Obtain a named module. Returns nil if the name is not present.

Parameters:

  • name (String, Symbol)

    The name of the module to return.

Returns:

  • (Module)

    The specified module



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/toys/module_lookup.rb', line 93

def lookup(name)
  @mutex.synchronize do
    @paths_locked = true
    @paths.each do |path_base, module_base|
      path = "#{path_base}/#{ModuleLookup.to_path_name(name)}"
      begin
        require path
      rescue ::LoadError
        next
      end
      mod_name = ModuleLookup.to_module_name(name)
      unless module_base.constants.include?(mod_name)
        raise ::NameError,
              "File #{path.inspect} did not define #{module_base.name}::#{mod_name}"
      end
      return module_base.const_get(mod_name)
    end
  end
  nil
end