Module: Modulation::Builder

Defined in:
lib/modulation/builder.rb

Overview

Implements creation of module instances

Class Method Summary collapse

Class Method Details

.add_module_constants(mod, target, *symbols) ⇒ void

This method returns an undefined value.

Adds all or part of a module’s constants to a target object If no symbols are given, all constants are added

Parameters:

  • mod (Module)

    imported module

  • target (Object)

    object to add constants to

  • symbols (Array<Symbol>)

    list of constants to add



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/modulation/builder.rb', line 131

def add_module_constants(mod, target, *symbols)
  exported = mod.__module_info[:exported_symbols]
  unless symbols.empty?
    symbols.select! { |s| s =~ Modulation::RE_CONST }
    exported = filter_exported_symbols(exported, symbols)
  end
  mod.singleton_class.constants(false).each do |sym|
    next unless exported.include?(sym)

    target.const_set(sym, mod.singleton_class.const_get(sym))
  end
end

.add_module_methods(mod, target, *symbols) ⇒ void

This method returns an undefined value.

Adds all or part of a module’s methods to a target object If no symbols are given, all methods are added

Parameters:

  • mod (Module)

    imported module

  • target (Object)

    object to add methods to

  • symbols (Array<Symbol>)

    list of methods to add



114
115
116
117
118
119
120
121
122
123
# File 'lib/modulation/builder.rb', line 114

def add_module_methods(mod, target, *symbols)
  methods = mod.singleton_class.instance_methods(false)
  unless symbols.empty?
    symbols.select! { |s| s =~ /^[a-z]/ }
    methods = filter_exported_symbols(methods, symbols)
  end
  methods.each do |sym|
    target.send(:define_method, sym, &mod.method(sym))
  end
end

.cleanup_module(mod) ⇒ void

This method returns an undefined value.

Removes methods and constants from module

Parameters:



97
98
99
100
101
102
103
104
105
106
# File 'lib/modulation/builder.rb', line 97

def cleanup_module(mod)
  mod.constants(false).each { |c| mod.send(:remove_const, c) }
  singleton = mod.singleton_class
  undef_method = singleton.method(:undef_method)

  singleton.instance_methods(false).each(&undef_method)
  singleton.private_instance_methods(false).each(&undef_method)

  mod.__before_reload
end

.create(info) ⇒ Module

Note:

The given block is used to pass the value given to

Initializes a new module ready to evaluate a file module ‘export_default`

Parameters:

  • info (Hash)

    module info

Returns:



31
32
33
34
35
36
37
# File 'lib/modulation/builder.rb', line 31

def create(info)
  Module.new.tap do |mod|
    mod.extend(ModuleMixin)
    mod.__module_info = info
    mod.singleton_class.const_set(:MODULE, mod)
  end
end

.define_auto_import_const_missing_method(receiver, auto_import_hash) ⇒ void

This method returns an undefined value.

Defines a const_missing method used for auto-importing on a given object

Parameters:

  • receiver (Object)

    object to receive the const_missing method call

  • auto_import_hash (Hash)

    a hash mapping constant names to a source file and a caller location



158
159
160
161
162
163
# File 'lib/modulation/builder.rb', line 158

def define_auto_import_const_missing_method(receiver, auto_import_hash)
  receiver.singleton_class.send(:define_method, :const_missing) do |sym|
    (path, caller_location) = auto_import_hash[sym]
    path ? const_set(sym, import(path, caller_location)) : super(sym)
  end
end

.filter_exported_symbols(exported, requested) ⇒ Object



144
145
146
147
148
149
150
151
# File 'lib/modulation/builder.rb', line 144

def filter_exported_symbols(exported, requested)
  not_exported = requested - exported
  unless not_exported.empty?
    raise NameError, "symbol #{not_exported.first.inspect} not exported"
  end

  exported & requested
end

.finalize_module_exports(info, mod) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/modulation/builder.rb', line 61

def finalize_module_exports(info, mod)
  if (default = mod.__export_default_info)
    ExportDefault.set_module_default_value(
      default[:value], info, mod, default[:caller]
    )
  else
    Exports.perform_exports(mod)
    if mod.respond_to?(:call) && !mod.respond_to?(:to_proc)
      def mod.to_proc
        method(:call).to_proc
      end
    end

    mod
  end
end

.load_module_code(mod, info) ⇒ void

This method returns an undefined value.

Loads a source file or a block into the given module

Parameters:

  • mod (Module)

    module

  • info (Hash)

    module info



56
57
58
59
# File 'lib/modulation/builder.rb', line 56

def load_module_code(mod, info)
  path = info[:location]
  mod.instance_eval(info[:source] || IO.read(path), path || '(source)')
end

.make(info) ⇒ Class

Loads a module from file or block, wrapping it in a module facade

Parameters:

  • info (Hash)

    module info

  • block (Proc)

    module block

Returns:

  • (Class)

    module facade



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/modulation/builder.rb', line 14

def make(info)
  # create module object
  mod = create(info)
  track_module_dependencies(mod) do
    # add module to loaded modules hash
    Modulation.loaded_modules[info[:location]] = mod

    load_module_code(mod, info)
    finalize_module_exports(info, mod)
  end
end

.reload_module_code(mod) ⇒ Object

Loads code for a module being reloaded, turning warnings off in order to not generate warnings upon re-assignment of constants



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/modulation/builder.rb', line 80

def reload_module_code(mod)
  orig_verbose = $VERBOSE
  $VERBOSE = nil
  prev_module = Thread.current[:__current_module]
  Thread.current[:__current_module] = mod

  cleanup_module(mod)
  load_module_code(mod, mod.__module_info)
  Exports.perform_exports(mod)
ensure
  Thread.current[:__current_module] = prev_module
  $VERBOSE = orig_verbose
end

.track_module_dependencies(mod) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/modulation/builder.rb', line 39

def track_module_dependencies(mod)
  prev_module = Thread.current[:__current_module]
  Thread.current[:__current_module] = mod

  if prev_module
    prev_module.__add_dependency(mod)
    mod.__add_dependent_module(prev_module)
  end
  yield
ensure
  Thread.current[:__current_module] = prev_module
end