Module: Im::Loader::EagerLoad

Included in:
Im::Loader
Defined in:
lib/im/loader/eager_load.rb

Instance Method Summary collapse

Instance Method Details

#eager_load(force: false) ⇒ Object

Eager loads all files in the root directories, recursively. Files do not need to be in ‘$LOAD_PATH`, absolute file names are used. Ignored and shadowed files are not eager loaded. You can opt-out specifically in specific files and directories with `do_not_eager_load`, and that can be overridden passing `force: true`.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/im/loader/eager_load.rb', line 9

def eager_load(force: false)
  mutex.synchronize do
    break if @eager_loaded
    raise Im::SetupRequired unless @setup

    log("eager load start") if logger

    actual_roots.each do |root_dir|
      actual_eager_load_dir(root_dir, self, force: force)
    end

    autoloaded_dirs.each do |autoloaded_dir|
      Im::Registry.unregister_autoload(autoloaded_dir)
    end
    autoloaded_dirs.clear

    @eager_loaded = true

    log("eager load end") if logger
  end
end

#eager_load_dir(path) ⇒ Object

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/im/loader/eager_load.rb', line 32

def eager_load_dir(path)
  raise Im::SetupRequired unless @setup

  abspath = File.expand_path(path)

  raise Im::Error.new("#{abspath} is not a directory") unless dir?(abspath)

  cnames = []

  found_root = false
  walk_up(abspath) do |dir|
    return if ignored_path?(dir)
    return if eager_load_exclusions.member?(dir)

    break if found_root = root_dirs.include?(dir)

    unless collapse?(dir)
      basename = File.basename(dir)
      cnames << inflector.camelize(basename, dir).to_sym
    end
  end

  raise Im::Error.new("I do not manage #{abspath}") unless found_root

  return if @eager_loaded

  namespace = self
  cnames.reverse_each do |cname|
    # Can happen if there are no Ruby files. This is not an error condition,
    # the directory is actually managed. Could have Ruby files later.
    return unless cdef?(namespace, cname)
    namespace = cget(namespace, cname)
  end

  # A shortcircuiting test depends on the invocation of this method. Please
  # keep them in sync if refactored.
  actual_eager_load_dir(abspath, namespace)
end

#eager_load_namespace(mod) ⇒ Object

Raises:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/im/loader/eager_load.rb', line 72

def eager_load_namespace(mod)
  raise Im::SetupRequired unless @setup

  unless mod.is_a?(Module)
    raise Im::Error, "#{mod.inspect} is not a class or module object"
  end

  return if @eager_loaded

  mod_name = Im.cpath(mod)

  actual_roots.each do |root_dir|
    if mod.equal?(self)
      # A shortcircuiting test depends on the invocation of this method.
      # Please keep them in sync if refactored.
      actual_eager_load_dir(root_dir, self)
    else
      eager_load_child_namespace(mod, mod_name, root_dir)
    end
  end
end

#load_file(path) ⇒ Object

Loads the given Ruby file.

Raises if the argument is ignored, shadowed, or not managed by the receiver.

The method is implemented as ‘constantize` for files, in a sense, to be able to descend orderly and make sure the file is loadable.

Raises:



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/im/loader/eager_load.rb', line 102

def load_file(path)
  abspath = File.expand_path(path)

  raise Im::Error.new("#{abspath} does not exist") unless File.exist?(abspath)
  raise Im::Error.new("#{abspath} is not a Ruby file") if dir?(abspath) || !ruby?(abspath)
  raise Im::Error.new("#{abspath} is ignored") if ignored_path?(abspath)

  basename = File.basename(abspath, ".rb")
  base_cname = inflector.camelize(basename, abspath).to_sym

  root_included = false
  cnames = []

  walk_up(File.dirname(abspath)) do |dir|
    raise Im::Error.new("#{abspath} is ignored") if ignored_path?(dir)

    break if root_included = root_dirs.include?(dir)

    unless collapse?(dir)
      basename = File.basename(dir)
      cnames << inflector.camelize(basename, dir).to_sym
    end
  end

  raise Im::Error.new("I do not manage #{abspath}") unless root_included

  namespace = self
  cnames.reverse_each do |cname|
    namespace = cget(namespace, cname)
  end

  raise Im::Error.new("#{abspath} is shadowed") if shadowed_file?(abspath)

  cget(namespace, base_cname)
end