Module: Merb::Slices
- Defined in:
- lib/merb-slices/module.rb,
lib/merb-slices/module_mixin.rb,
lib/merb-slices/controller_mixin.rb
Defined Under Namespace
Modules: ControllerMixin, ModuleMixin Classes: Activate, DynamicLoader, Initialize, Loader
Constant Summary collapse
- VERSION =
"0.9.4"
Class Method Summary collapse
-
.[](module_name) ⇒ Module
Retrieve a slice module by name.
-
.activate(slice_module) ⇒ Object
Activate a Slice module at runtime.
-
.activate_by_file(slice_file) ⇒ Object
(also: register_and_load)
Register a Slice by its gem/lib init file path and activate it at runtime.
-
.config ⇒ Hash
The configuration loaded from Merb.root / “config/slices.yml” or, if the load fails, an empty hash.
-
.deactivate(slice_module) ⇒ Object
Deactivate a Slice module at runtime.
-
.deactivate_by_file(slice_file) ⇒ Object
Deactivate a Slice module at runtime by specifying its slice file.
-
.each_slice {|module| ... } ⇒ Object
Iterate over all registered slices.
-
.exists?(module_name) ⇒ Boolean
Check whether a Slice exists.
-
.filename2module(slice_file) ⇒ Object
Helper method to transform a slice filename to a module Symbol.
-
.files ⇒ Hash
A lookup for finding a Slice module’s slice file path.
-
.paths ⇒ Hash
A lookup for finding a Slice module’s path.
-
.register(slice_file, force = true) ⇒ Module
Register a Slice by its gem/lib path for loading at startup.
-
.register_slices_from_search_path! ⇒ Object
Look for any slices in Merb.root / ‘slices’ (the default) or if given, Merb::Plugins.config[:search_path] (String/Array).
-
.reload(slice_module) ⇒ Object
Reload a Slice at runtime.
-
.reload_by_file(slice_file) ⇒ Object
Reload a Slice at runtime by specifying its slice file.
-
.slice_files_from_search_path ⇒ Object
Slice file locations from all search paths; this default to host-app/slices.
-
.slice_names ⇒ Array[String]
All registered Slice module names.
-
.slices ⇒ Array[Module]
All registered Slice modules.
-
.start_dynamic_loader!(interval = nil) ⇒ Object
Watch all specified search paths to dynamically load/unload slices at runtime.
-
.stop_dynamic_loader! ⇒ Object
Stop watching search paths to dynamically load/unload slices at runtime.
-
.unregister(slice_module) ⇒ Object
Unregister a Slice at runtime.
Class Method Details
.[](module_name) ⇒ Module
Retrieve a slice module by name
12 13 14 |
# File 'lib/merb-slices/module.rb', line 12 def [](module_name) Object.full_const_get(module_name.to_s) if exists?(module_name) end |
.activate(slice_module) ⇒ Object
Activate a Slice module at runtime
Looks for previously registered slices; then searches :search_path for matches.
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/merb-slices/module.rb', line 91 def activate(slice_module) unless slice_file = self.files[slice_module.to_s] module_name_underscored = slice_module.to_s.snake_case.escape_regexp module_name_dasherized = module_name_underscored.tr('_', '-').escape_regexp regexp = Regexp.new(/\/(#{module_name_underscored}|#{module_name_dasherized})\/lib\/(#{module_name_underscored}|#{module_name_dasherized})\.rb$/) slice_file = slice_files_from_search_path.find { |path| path.match(regexp) } # from search path(s) end activate_by_file(slice_file) if slice_file rescue => e Merb.logger.error!("Failed to activate slice #{slice_module} (#{e.})") end |
.activate_by_file(slice_file) ⇒ Object Also known as: register_and_load
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.
115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/merb-slices/module.rb', line 115 def activate_by_file(slice_file) Merb::Slices::Loader.load_classes(slice_file) slice = register(slice_file, false) # just to get module by slice_file slice.load_slice # load the slice Merb::Slices::Loader.reload_router! slice.init if slice.respond_to?(:init) slice.activate if slice.respond_to?(:activate) && slice.routed? slice rescue Merb::Slices::Loader.reload_router! end |
.config ⇒ Hash
Returns The configuration loaded from Merb.root / “config/slices.yml” or, if the load fails, an empty hash.
188 189 190 191 192 193 |
# File 'lib/merb-slices/module.rb', line 188 def config @config ||= begin empty_hash = Hash.new { |h,k| h[k] = {} } File.exists?(Merb.root / "config" / "slices.yml") ? YAML.load(File.read(Merb.root / "config" / "slices.yml")) || empty_hash : empty_hash end end |
.deactivate(slice_module) ⇒ Object
Deactivate a Slice module at runtime
131 132 133 134 135 136 |
# File 'lib/merb-slices/module.rb', line 131 def deactivate(slice_module) if slice = self[slice_module] slice.deactivate if slice.respond_to?(:deactivate) && slice.routed? unregister(slice) end end |
.deactivate_by_file(slice_file) ⇒ Object
Deactivate a Slice module at runtime by specifying its slice file
141 142 143 144 145 |
# File 'lib/merb-slices/module.rb', line 141 def deactivate_by_file(slice_file) if slice = self.slices.find { |s| s.file == slice_file } deactivate(slice.name) end end |
.each_slice {|module| ... } ⇒ Object
Iterate over all registered slices
By default iterates alphabetically over all registered modules. If Merb::Plugins.config[: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.
244 245 246 247 248 249 250 251 |
# File 'lib/merb-slices/module.rb', line 244 def each_slice(&block) loadable_slices = Merb::Plugins.config[:merb_slices].key?(:queue) ? Merb::Plugins.config[:merb_slices][:queue] : slice_names loadable_slices.each do |module_name| if mod = self[module_name] block.call(mod) end end end |
.exists?(module_name) ⇒ Boolean
Check whether a Slice exists
214 215 216 |
# File 'lib/merb-slices/module.rb', line 214 def exists?(module_name) slice_names.include?(module_name.to_s) && Object.const_defined?(module_name.to_s) end |
.filename2module(slice_file) ⇒ Object
Helper method to transform a slice filename to a module Symbol
17 18 19 |
# File 'lib/merb-slices/module.rb', line 17 def filename2module(slice_file) File.basename(slice_file, '.rb').gsub('-', '_').camel_case.to_sym end |
.files ⇒ Hash
This is unaffected by deactivating a slice; used to reload slices by name.
A lookup for finding a Slice module’s slice file path
230 231 232 |
# File 'lib/merb-slices/module.rb', line 230 def files @files ||= {} end |
.paths ⇒ Hash
Whenever a slice is deactivated, its path is removed from the lookup.
A lookup for finding a Slice module’s path
222 223 224 |
# File 'lib/merb-slices/module.rb', line 222 def paths @paths ||= {} end |
.register(slice_file, force = true) ⇒ Module
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.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/merb-slices/module.rb', line 34 def register(slice_file, force = true) # do what filename2module does, but with intermediate variables identifier = File.basename(slice_file, '.rb') underscored = identifier.gsub('-', '_') module_name = underscored.camel_case slice_path = File.(File.dirname(slice_file) + '/..') # check if slice_path exists instead of just the module name - more flexible if !self.paths.include?(slice_path) || force Merb.logger.info!("Registered slice '#{module_name}' located at #{slice_path}") if force self.files[module_name] = slice_file self.paths[module_name] = slice_path slice_mod = setup_module(module_name) slice_mod.identifier = identifier slice_mod.identifier_sym = underscored.to_sym slice_mod.root = slice_path slice_mod.file = slice_file slice_mod.registered slice_mod else Merb.logger.info!("Already registered slice '#{module_name}' located at #{slice_path}") Object.full_const_get(module_name) end end |
.register_slices_from_search_path! ⇒ Object
Look for any slices in Merb.root / ‘slices’ (the default) or if given, Merb::Plugins.config[:search_path] (String/Array)
60 61 62 63 64 65 66 |
# File 'lib/merb-slices/module.rb', line 60 def register_slices_from_search_path! slice_files_from_search_path.each do |slice_file| absolute_path = File.(slice_file) Merb.logger.info!("Found slice '#{File.basename(absolute_path, '.rb')}' in search path at #{absolute_path.relative_path_from(Merb.root)}") Merb::Slices::Loader.load_classes(absolute_path) end end |
.reload(slice_module) ⇒ Object
Reload a Slice at runtime
150 151 152 153 154 155 |
# File 'lib/merb-slices/module.rb', line 150 def reload(slice_module) if slice = self[slice_module] deactivate slice.name activate_by_file slice.file end end |
.reload_by_file(slice_file) ⇒ Object
Reload a Slice at runtime by specifying its slice file
160 161 162 163 164 |
# File 'lib/merb-slices/module.rb', line 160 def reload_by_file(slice_file) if slice = self.slices.find { |s| s.file == slice_file } reload(slice.name) end end |
.slice_files_from_search_path ⇒ Object
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[:search_path] (String/Array). Specify files, glob patterns or paths containing slices.
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/merb-slices/module.rb', line 258 def slice_files_from_search_path search_paths = Array(Merb::Plugins.config[:merb_slices][:search_path] || [Merb.root / "slices"]) search_paths.inject([]) do |files, path| # handle both Pathname and String path = path.to_s if File.file?(path) && File.extname(path) == ".rb" files << path elsif path.include?("*") files += glob_search_path(path) elsif File.directory?(path) files += glob_search_path(path / "**/lib/*.rb") end files end end |
.slice_names ⇒ Array[String]
All registered Slice module names
207 208 209 |
# File 'lib/merb-slices/module.rb', line 207 def slice_names self.paths.keys.sort end |
.slices ⇒ Array[Module]
All registered Slice modules
198 199 200 201 202 |
# File 'lib/merb-slices/module.rb', line 198 def slices slice_names.map do |name| Object.full_const_get(name) rescue nil end.compact end |
.start_dynamic_loader!(interval = nil) ⇒ Object
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.
176 177 178 |
# File 'lib/merb-slices/module.rb', line 176 def start_dynamic_loader!(interval = nil) DynamicLoader.start(interval) end |
.stop_dynamic_loader! ⇒ Object
Stop watching search paths to dynamically load/unload slices at runtime
181 182 183 |
# File 'lib/merb-slices/module.rb', line 181 def stop_dynamic_loader! DynamicLoader.stop end |
.unregister(slice_module) ⇒ Object
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.
75 76 77 78 79 80 81 82 83 84 |
# File 'lib/merb-slices/module.rb', line 75 def unregister(slice_module) if (slice = self[slice_module]) && self.paths.delete(module_name = slice.name) slice.loadable_files.each { |file| Merb::Slices::Loader.remove_file file } Object.send(:remove_const, module_name) unless Object.const_defined?(module_name) Merb.logger.info!("Unregistered slice #{module_name}") Merb::Slices::Loader.reload_router! end end end |