Module: Modulation::Exports

Defined in:
lib/modulation/exports.rb

Overview

Functionality related to symbol export

Constant Summary collapse

CONST_INSPECT_CODE =
<<~EOF
  def inspect
    "(%s)::%s"
  end
EOF
NOT_FOUND_MSG =
'%s %s not found in module'

Class Method Summary collapse

Class Method Details

.define_const_inspect_methods(mod, sym, value) ⇒ Object



149
150
151
152
153
154
# File 'lib/modulation/exports.rb', line 149

def define_const_inspect_methods(mod, sym, value)
  if value.method(:inspect).source_location.nil?
    code = format(CONST_INSPECT_CODE, mod.inspect, sym)
    value.singleton_class.module_eval(code)
  end
end

.export(mod, *symbols) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/modulation/exports.rb', line 25

def export(mod, *symbols)
  case symbols.first
  when Hash
    symbols = export_hash(mod, symbols.first)
  when Array
    symbols = symbols.first
  end

  validate_exported_symbols(mod, symbols)
  symbols
end

.export_directive(mod, directive) ⇒ Object



19
20
21
22
23
# File 'lib/modulation/exports.rb', line 19

def export_directive(mod, directive)
  send directive[:method], mod, *directive[:args]
rescue NameError => e
  Modulation.raise_error e, directive[:export_caller]
end

.export_from_receiver(mod, name) ⇒ Object



37
38
39
40
41
42
43
# File 'lib/modulation/exports.rb', line 37

def export_from_receiver(mod, name)
  if name !~ Modulation::RE_CONST
    raise 'export_from_receiver expects a const reference'
  end

  ExportFromReceiver.from_const(mod, name)
end

.export_hash(mod, hash) ⇒ Array

Returns array of exported symbols.

Returns:

  • (Array)

    array of exported symbols



65
66
67
68
69
# File 'lib/modulation/exports.rb', line 65

def export_hash(mod, hash)
  singleton = mod.singleton_class
  hash.each { |k, v| export_hash_entry(singleton, k, v) }
  hash.keys
end

.export_hash_entry(singleton, key, value) ⇒ Object



71
72
73
74
75
76
77
78
79
# File 'lib/modulation/exports.rb', line 71

def export_hash_entry(singleton, key, value)
  symbol_value = value.is_a?(Symbol)
  const_value = value =~ Modulation::RE_CONST
  if value && const_value && singleton.const_defined?(value)
    value = singleton.const_get(value)
  end

  generate_exported_hash_entry(singleton, key, value, symbol_value)
end

.expose_exported_constants(mod, singleton, symbols) ⇒ void

This method returns an undefined value.

Copies exported constants from singleton to module

Parameters:

  • mod (Module)

    module with exported symbols

  • singleton (Class)

    sinleton for module

  • symbols (Array)

    array of exported symbols



122
123
124
125
# File 'lib/modulation/exports.rb', line 122

def expose_exported_constants(mod, singleton, symbols)
  defined_constants = singleton.constants(false)
  process_module_constants(mod, singleton, symbols, defined_constants)
end

.generate_exported_hash_entry(singleton, key, value, symbol_value) ⇒ Object



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

def generate_exported_hash_entry(singleton, key, value, symbol_value)
  const_key = key =~ Modulation::RE_CONST
  if const_key
    singleton.const_set(key, value)
  elsif symbol_value && singleton.method_defined?(value)
    singleton.alias_method(key, value)
  else
    value_proc = value.is_a?(Proc) ? value : proc { value }
    singleton.send(:define_method, key, &value_proc)
  end
end

.perform_exports(mod) ⇒ Object

Performs the exporting of symbols after the module has loaded



10
11
12
13
14
15
16
17
# File 'lib/modulation/exports.rb', line 10

def perform_exports(mod)
  directives = mod.__export_directives
  exported_symbols = directives.inject [] do |exported, directive|
    symbols = export_directive mod, directive
    exported + symbols
  end
  set_exported_symbols mod, exported_symbols
end

.privatize_non_exported_methods(singleton, symbols) ⇒ void

This method returns an undefined value.

Sets all non-exported methods as private for given module

Parameters:

  • singleton (Class)

    sinleton for module

  • symbols (Array)

    array of exported symbols



109
110
111
112
113
114
115
# File 'lib/modulation/exports.rb', line 109

def privatize_non_exported_methods(singleton, symbols)
  singleton.instance_methods(false).each do |sym|
    next if symbols.include?(sym)

    singleton.send(:private, sym)
  end
end

.process_module_constants(mod, singleton, symbols, defined_constants) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/modulation/exports.rb', line 127

def process_module_constants(mod, singleton, symbols, defined_constants)
  private_constants = mod.__module_info[:private_constants] = []
  defined_constants.each do |sym|
    next if sym == :MODULE

    value = singleton.const_get(sym)
    define_const_inspect_methods(mod, sym, value) if value.is_a?(Module)

    if symbols.include?(sym)
      mod.const_set(sym, value)
    else
      private_constants << sym
    end
  end
end

.raise_exported_symbol_not_found_error(sym, kind) ⇒ Object

Raises:

  • (NameError)


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

def raise_exported_symbol_not_found_error(sym, kind)
  msg = format(
    NOT_FOUND_MSG, kind == :method ? 'Method' : 'Constant', sym
  )
  raise NameError, msg
end

.set_exported_symbols(mod, symbols) ⇒ void

This method returns an undefined value.

Marks all non-exported methods as private, exposes exported constants

Parameters:

  • mod (Module)

    module with exported symbols

  • symbols (Array)

    array of exported symbols



97
98
99
100
101
102
103
# File 'lib/modulation/exports.rb', line 97

def set_exported_symbols(mod, symbols)
  mod.__module_info[:exported_symbols] = symbols
  singleton = mod.singleton_class

  privatize_non_exported_methods(singleton, symbols)
  expose_exported_constants(mod, singleton, symbols)
end

.validate_exported_symbol(sym, list, kind) ⇒ Object



58
59
60
61
62
# File 'lib/modulation/exports.rb', line 58

def validate_exported_symbol(sym, list, kind)
  return if list.include? sym

  raise_exported_symbol_not_found_error(sym, kind)
end

.validate_exported_symbols(mod, symbols) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/modulation/exports.rb', line 45

def validate_exported_symbols(mod, symbols)
  defined_methods = mod.singleton_class.instance_methods(true)
  defined_constants = mod.singleton_class.constants(false)

  symbols.each do |sym|
    if sym =~ Modulation::RE_CONST
      validate_exported_symbol(sym, defined_constants, :const)
    else
      validate_exported_symbol(sym, defined_methods, :method)
    end
  end
end