module Builder
Implements creation of module instances
Private Class Methods
Adds all or part of a module's constants to a target object If no symbols are given, all constants are added @param mod [Module] imported module @param target [Object] object to add constants to @param symbols [Array<Symbol>] list of constants to add @return [void]
# 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
Adds all or part of a module's methods to a target object If no symbols are given, all methods are added @param mod [Module] imported module @param target [Object] object to add methods to @param symbols [Array<Symbol>] list of methods to add @return [void]
# 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
Removes methods and constants from module @param mod [Module] module @return [void]
# 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
Initializes a new module ready to evaluate a file module @note The given block is used to pass the value given to `export_default` @param info [Hash] module info @return [Module] new module
# 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
Defines a const_missing method used for auto-importing on a given object @param receiver [Object] object to receive the const_missing method call @param auto_import_hash [Hash] a hash mapping constant names to a source
file and a caller location
@return [void]
# 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
# 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
# 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
Loads a source file or a block into the given module @param mod [Module] module @param info [Hash] module info @return [void]
# 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
Loads a module from file or block, wrapping it in a module facade @param info [Hash] module info @param block [Proc] module block @return [Class] module facade
# 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
Loads code for a module being reloaded, turning warnings off in order to not generate warnings upon re-assignment of constants
# 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
# 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