Module | Merb::Slices |
In: |
merb-slices/lib/merb-slices/module.rb
merb-slices/lib/merb-slices/controller_mixin.rb merb-slices/lib/merb-slices/module_mixin.rb |
VERSION | = | "0.9.8" |
activate_by_file | -> | register_and_load |
Retrieve a slice module by name
@param <to_s> The slice module to check for. @return <Module> The slice module itself.
# File merb-slices/lib/merb-slices/module.rb, line 12 12: def [](module_name) 13: Object.full_const_get(module_name.to_s) if exists?(module_name) 14: end
Activate a Slice module at runtime
Looks for previously registered slices; then searches :search_path for matches.
@param slice_module<to_s> Usually a string of version of the slice module name.
# File merb-slices/lib/merb-slices/module.rb, line 91 91: def activate(slice_module) 92: unless slice_file = self.files[slice_module.to_s] 93: module_name_underscored = slice_module.to_s.snake_case.escape_regexp 94: module_name_dasherized = module_name_underscored.tr('_', '-').escape_regexp 95: regexp = Regexp.new(/\/(#{module_name_underscored}|#{module_name_dasherized})\/lib\/(#{module_name_underscored}|#{module_name_dasherized})\.rb$/) 96: slice_file = slice_files_from_search_path.find { |path| path.match(regexp) } # from search path(s) 97: end 98: activate_by_file(slice_file) if slice_file 99: rescue => e 100: Merb.logger.error!("Failed to activate slice #{slice_module} (#{e.message})") 101: end
Register a Slice by its gem/lib init file path and activate it at runtime
Normally slices are loaded using BootLoaders on application startup. This method gives you the possibility to add slices at runtime, all without restarting your app. Together with deactivate it allows you to enable/disable slices at any time. The router is reloaded to incorporate any changes. Disabled slices will be skipped when routes are regenerated.
@param slice_file<String> The path of the gem ‘init file‘
@example Merb::Slices.activate_by_file(’/path/to/gems/slice-name/lib/slice-name.rb’)
# File merb-slices/lib/merb-slices/module.rb, line 115 115: def activate_by_file(slice_file) 116: Merb::Slices::Loader.load_classes(slice_file) 117: slice = register(slice_file, false) # just to get module by slice_file 118: slice.load_slice # load the slice 119: Merb::Slices::Loader.reload_router! 120: slice.init if slice.respond_to?(:init) 121: slice.activate if slice.respond_to?(:activate) && slice.routed? 122: slice 123: rescue 124: Merb::Slices::Loader.reload_router! 125: end
@return <Hash>
The configuration loaded from Merb.root / "config/slices.yml" or, if the load fails, an empty hash.
# File merb-slices/lib/merb-slices/module.rb, line 194 194: def config 195: @config ||= begin 196: empty_hash = Hash.new { |h,k| h[k] = {} } 197: if File.exists?(Merb.root / "config" / "slices.yml") 198: require "yaml" 199: YAML.load(File.read(Merb.root / "config" / "slices.yml")) || empty_hash 200: else 201: empty_hash 202: end 203: end 204: end
Deactivate a Slice module at runtime
@param slice_module<to_s> The Slice module to unregister.
# File merb-slices/lib/merb-slices/module.rb, line 131 131: def deactivate(slice_module) 132: if slice = self[slice_module] 133: slice.deactivate if slice.respond_to?(:deactivate) && slice.routed? 134: unregister(slice) 135: end 136: end
Deactivate a Slice module at runtime by specifying its slice file
@param slice_file<String> The Slice location of the slice init file to unregister.
# File merb-slices/lib/merb-slices/module.rb, line 141 141: def deactivate_by_file(slice_file) 142: if slice = self.slices.find { |s| s.file == slice_file } 143: deactivate(slice.name) 144: end 145: end
Iterate over all registered slices
By default iterates alphabetically over all registered modules. If Merb::Plugins.config[:merb_slices][:queue] is set, only the defined modules are loaded in the given order. This can be used to selectively load slices, and also maintain load-order for slices that depend on eachother.
@yield Iterate over known slices and pass in the slice module. @yieldparam module<Module> The Slice module.
# File merb-slices/lib/merb-slices/module.rb, line 256 256: def each_slice(&block) 257: loadable_slices = Merb::Plugins.config[:merb_slices].key?(:queue) ? Merb::Plugins.config[:merb_slices][:queue] : slice_names 258: loadable_slices.each do |module_name| 259: if mod = self[module_name] 260: block.call(mod) 261: end 262: end 263: end
Check whether a Slice exists
@param <to_s> The slice module to check for.
# File merb-slices/lib/merb-slices/module.rb, line 225 225: def exists?(module_name) 226: const_name = module_name.to_s.camel_case 227: slice_names.include?(const_name) && Object.const_defined?(const_name) 228: end
Helper method to transform a slice filename to a module Symbol
# File merb-slices/lib/merb-slices/module.rb, line 17 17: def filename2module(slice_file) 18: File.basename(slice_file, '.rb').gsub('-', '_').camel_case.to_sym 19: end
Register a Slice by its gem/lib path for loading at startup
This is referenced from gems/<slice-gem-x.x.x>/lib/<slice-gem>.rb Which gets loaded for any gem. The name of the file is used to extract the Slice module name.
@param slice_file<String> The path of the gem ‘init file’ @param force<Boolean> Whether to overwrite currently registered slice or not.
@return <Module> The Slice module that has been setup.
@example Merb::Slices::register(FILE) @example Merb::Slices::register(’/path/to/my-slice/lib/my-slice.rb’)
# File merb-slices/lib/merb-slices/module.rb, line 34 34: def register(slice_file, force = true) 35: # do what filename2module does, but with intermediate variables 36: identifier = File.basename(slice_file, '.rb') 37: underscored = identifier.gsub('-', '_') 38: module_name = underscored.camel_case 39: slice_path = File.expand_path(File.dirname(slice_file) + '/..') 40: # check if slice_path exists instead of just the module name - more flexible 41: if !self.paths.include?(slice_path) || force 42: Merb.logger.verbose!("Registered slice '#{module_name}' located at #{slice_path}") if force 43: self.files[module_name] = slice_file 44: self.paths[module_name] = slice_path 45: slice_mod = setup_module(module_name) 46: slice_mod.identifier = identifier 47: slice_mod.identifier_sym = underscored.to_sym 48: slice_mod.root = slice_path 49: slice_mod.file = slice_file 50: slice_mod.registered 51: slice_mod 52: else 53: Merb.logger.info!("Already registered slice '#{module_name}' located at #{slice_path}") 54: Object.full_const_get(module_name) 55: end 56: end
Look for any slices in Merb.root / ‘slices’ (the default) or if given, Merb::Plugins.config[:merb_slices][:search_path] (String/Array)
# File merb-slices/lib/merb-slices/module.rb, line 60 60: def register_slices_from_search_path! 61: slice_files_from_search_path.each do |slice_file| 62: absolute_path = File.expand_path(slice_file) 63: Merb.logger.info!("Found slice '#{File.basename(absolute_path, '.rb')}' in search path at #{absolute_path.relative_path_from(Merb.root)}") 64: Merb::Slices::Loader.load_classes(absolute_path) 65: end 66: end
Reload a Slice at runtime by specifying its slice file
@param slice_file<String> The Slice location of the slice init file to reload.
# File merb-slices/lib/merb-slices/module.rb, line 160 160: def reload_by_file(slice_file) 161: if slice = self.slices.find { |s| s.file == slice_file } 162: reload(slice.name) 163: end 164: end
Slice file locations from all search paths; this default to host-app/slices.
Look for any slices in those default locations or if given, Merb::Plugins.config[:merb_slices][:search_path] (String/Array). Specify files, glob patterns or paths containing slices.
# File merb-slices/lib/merb-slices/module.rb, line 270 270: def slice_files_from_search_path 271: search_paths = Array(Merb::Plugins.config[:merb_slices][:search_path] || [Merb.root / "slices"]) 272: search_paths.inject([]) do |files, path| 273: # handle both Pathname and String 274: path = path.to_s 275: if File.file?(path) && File.extname(path) == ".rb" 276: files << path 277: elsif path.include?("*") 278: files += glob_search_path(path) 279: elsif File.directory?(path) 280: files += glob_search_path(path / "**/lib/*.rb") 281: end 282: files 283: end 284: end
All registered Slice modules
@return <Array[Module]> A sorted array of all slice modules.
# File merb-slices/lib/merb-slices/module.rb, line 209 209: def slices 210: slice_names.map do |name| 211: Object.full_const_get(name) rescue nil 212: end.compact 213: end
Watch all specified search paths to dynamically load/unload slices at runtime
If a valid slice is found it‘s automatically registered and activated; once a slice is removed (or renamed to not match the convention), it will be unregistered and deactivated. Runs in a Thread.
@example Merb::BootLoader.after_app_loads { Merb::Slices.start_dynamic_loader! }
@param interval<Numeric>
The interval in seconds of checking the search path(s) for changes.
# File merb-slices/lib/merb-slices/module.rb, line 176 176: def start_dynamic_loader!(interval = nil) 177: DynamicLoader.start(interval) 178: end
Unregister a Slice at runtime
This clears the slice module from ObjectSpace and reloads the router. Since the router doesn‘t add routes for any disabled slices this will correctly reflect the app‘s routing state.
@param slice_module<to_s> The Slice module to unregister.
# File merb-slices/lib/merb-slices/module.rb, line 75 75: def unregister(slice_module) 76: if (slice = self[slice_module]) && self.paths.delete(module_name = slice.name) 77: slice.loadable_files.each { |file| Merb::Slices::Loader.remove_classes_in_file file } 78: Object.send(:remove_const, module_name) 79: unless Object.const_defined?(module_name) 80: Merb.logger.info!("Unregistered slice #{module_name}") 81: Merb::Slices::Loader.reload_router! 82: end 83: end 84: end
Glob slice files
@param glob_pattern<String> A glob path with pattern @return <Array> Valid slice file paths.
# File merb-slices/lib/merb-slices/module.rb, line 304 304: def glob_search_path(glob_pattern) 305: # handle both Pathname and String 306: glob_pattern = glob_pattern.to_s 307: Dir[glob_pattern].inject([]) do |files, libfile| 308: basename = File.basename(libfile, '.rb') 309: files << libfile if File.basename(File.dirname(File.dirname(libfile))) == basename 310: files 311: end 312: end
Prepare a module to be a proper Slice module
@param module_name<to_s> The name of the module to prepare
@return <Module> The module that has been setup
# File merb-slices/lib/merb-slices/module.rb, line 293 293: def setup_module(module_name) 294: Object.make_module(module_name) 295: slice_mod = Object.full_const_get(module_name) 296: slice_mod.extend(ModuleMixin) 297: slice_mod 298: end