Class: Syntropy::ModuleLoader

Inherits:
Object
  • Object
show all
Defined in:
lib/syntropy/module_loader.rb

Overview

The ModuleLoader class implemenets a module loader. It handles loading of modules, tracking of dependencies between modules, and invalidation of loaded modules (following a change to the module file).

A module may implement a route endpoint, a layout template, utility methods, classes, or any other functionality needed by the web app.

Modules are Ruby files that can import other modules as dependencies. A module must export a single value, which can be a class, a template, a proc, or any other Ruby object. A module can also export itself by calling ‘export self`.

Modules are referenced relative to the web app’s root directory, without the ‘.rb` extension. For example, for a site residing in `/my_site`, the reference `_lib/foo` will point to a module residing in `/my_site/_lib/foo.rb`.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, extensions: nil) ⇒ void

Instantiates a module loader

Parameters:

  • env (Hash)

    environment hash

  • extensions (Module, Array<Module>) (defaults to: nil)

    extension module(s)



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/syntropy/module_loader.rb', line 31

def initialize(env, extensions: nil)
  @env = env
  @machine = env[:machine]
  @app_root = env[:app_root]
  @modules = {} # maps ref to module entry
  @fn_map = {} # maps filename to ref
  @extensions = extensions
  @loading = Set.new
  @lock = UM::Mutex.new
  @lock_holder = nil
end

Instance Attribute Details

#app_rootObject (readonly)

Returns the value of attribute app_root.



24
25
26
# File 'lib/syntropy/module_loader.rb', line 24

def app_root
  @app_root
end

#modulesObject (readonly)

Returns the value of attribute modules.



24
25
26
# File 'lib/syntropy/module_loader.rb', line 24

def modules
  @modules
end

Instance Method Details

#invalidate_fn(fn) ⇒ void

This method returns an undefined value.

Invalidates a module by its filename, normally following a change to the underlying file (in order to cause reloading of the module). The module will be removed from the modules map, as well as modules dependending on it.

Parameters:

  • fn (String)

    module filename



78
79
80
81
82
83
84
# File 'lib/syntropy/module_loader.rb', line 78

def invalidate_fn(fn)
  lock do
    ref = @fn_map[fn]
    invalidate_ref(ref) if ref
    invalidate_collection_modules
  end
end

#list(dir) ⇒ Array<String>

Returns a list of modules found in the given relative path. The module references are returned as absolute paths (relative to the module loader root directory).

Parameters:

  • dir (String)

    relative module directory

Returns:

  • (Array<String>)

    list of modules



66
67
68
69
# File 'lib/syntropy/module_loader.rb', line 66

def list(dir)
  fns = Dir[File.join(@app_root, dir, '*.rb')]
  fns.map { it.match(/^#{@app_root}\/(.+)\.rb$/)[1] }.sort
end

#load(ref, raise_on_missing: true) ⇒ any

Loads a module (if not already loaded) and returns its export value.

Parameters:

  • ref (String)

    module reference

Returns:

  • (any)

    export value



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/syntropy/module_loader.rb', line 47

def load(ref, raise_on_missing: true)
  lock do
    ref = "/#{ref}" if ref !~ /^\//
    if !(entry = @modules[ref])
      entry = load_module(ref, raise_on_missing:)
      return if !entry

      @modules[ref] = entry
    end
    entry[:export_value]
  end
end