Merb::Slices::ModuleMixin

Public Class Methods

extended(slice_module) click to toggle source
# File lib/merb-slices/module_mixin.rb, line 8
def self.extended(slice_module)
  slice_module.meta_class.module_eval do
    attr_accessor :identifier, :identifier_sym, :root, :file
    attr_accessor :description, :version, :author
  end
end

Public Instance Methods

[](key) click to toggle source

@param <Symbol> The configuration key. @return <Object> The configuration value.

# File lib/merb-slices/module_mixin.rb, line 53
def [](key)
  self.config[key]
end
[]=(key, value) click to toggle source

@param <Symbol> The configuration key. @param <Object> The configuration value.

# File lib/merb-slices/module_mixin.rb, line 59
def []=(key, value)
  self.config[key] = value
end
activate() click to toggle source

Stub activation hook - runs after AfterAppLoads BootLoader.

# File lib/merb-slices/module_mixin.rb, line 28
def activate; end
app_components() click to toggle source

Return all application path component types

@return <Array> Component types.

# File lib/merb-slices/module_mixin.rb, line 257
def app_components
  [:view, :model, :controller, :helper, :mailer, :part]
end
app_dir_for(type) click to toggle source

Retrieve the absolute path to a app-level directory.

@param type<Symbol> The type of path to retrieve directory for, e.g. :view.

@return <String> The directory for the requested type.

# File lib/merb-slices/module_mixin.rb, line 147
def app_dir_for(type) self.app_paths[type].first end
app_glob_for(type) click to toggle source

@param type<Symbol> The type of path to retrieve glob for, e.g. :view.

@return <String> The pattern with which to match files within the type directory.

# File lib/merb-slices/module_mixin.rb, line 152
def app_glob_for(type) self.app_paths[type][1] end
app_paths() click to toggle source

The app-level load paths to use when loading the slice.

@return <Hash> The load paths which make up the app-level structure.

# File lib/merb-slices/module_mixin.rb, line 119
def app_paths
  @app_paths ||= Hash.new { [Merb.root] }
end
clone_slice!() click to toggle source

Clone all files from the slice to their app-level location; this will also copy /lib, causing merb-slices to pick up the slice there.

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.
# File lib/merb-slices/module_mixin.rb, line 314
def clone_slice!
  app_slice_root = app_dir_for(:root)
  copied, duplicated = [], []
  manifest.each do |source, relative_path|
    mirror_file(source, app_slice_root / relative_path, copied, duplicated)
  end
  [copied, duplicated]
end
collected_app_paths() click to toggle source

The app-level load paths that have been used when the slice was loaded.

This may be a subset of app_paths, which includes any path to look for.

@return <Array> Application load paths (with glob pattern)

# File lib/merb-slices/module_mixin.rb, line 105
def collected_app_paths
  @collected_app_paths ||= []
end
collected_slice_paths() click to toggle source

The slice-level load paths that have been used when the slice was loaded.

This may be a subset of app_paths, which includes any path to look for.

@return <Array> load paths (with glob pattern)

# File lib/merb-slices/module_mixin.rb, line 96
def collected_slice_paths
  @collected_slice_paths ||= []
end
config() click to toggle source

@return <Hash> The configuration for this slice.

# File lib/merb-slices/module_mixin.rb, line 64
def config
  Merb::Slices::config[self.identifier_sym] ||= {}
end
deactivate() click to toggle source

Stub deactivation method - not triggered automatically.

# File lib/merb-slices/module_mixin.rb, line 31
def deactivate; end
dir_for(type) click to toggle source

Retrieve the absolute path to a slice-level directory.

@param type<Symbol> The type of path to retrieve directory for, e.g. :view.

@return <String> The absolute path for the requested type.

# File lib/merb-slices/module_mixin.rb, line 135
def dir_for(type) self.slice_paths[type].first end
glob_for(type) click to toggle source

@param type<Symbol> The type of path to retrieve glob for, e.g. :view.

@return <String> The pattern with which to match files within the type directory.

# File lib/merb-slices/module_mixin.rb, line 140
def glob_for(type) self.slice_paths[type][1] end
init() click to toggle source

Stub initialization hook - runs before AfterAppLoads BootLoader.

# File lib/merb-slices/module_mixin.rb, line 25
def init; end
load_slice() click to toggle source

Load slice and it’s classes located in the slice-level load paths.

Assigns collected_slice_paths and collected_app_paths, then loads the collected_slice_paths and triggers the loaded hook method.

# File lib/merb-slices/module_mixin.rb, line 77
def load_slice
  # load application.rb (or similar) for thin slices
  Merb::Slices::Loader.load_file self.dir_for(:application) if File.file?(self.dir_for(:application))
  # assign all relevant paths for slice-level and app-level
  self.collect_load_paths
  # load all slice-level classes from paths
  Merb::Slices::Loader.load_classes self.collected_slice_paths
  # call hook if available
  self.loaded if self.respond_to?(:loaded)
  Merb.logger.info!("Loaded slice '#{self}' ...")
rescue => e
  Merb.logger.warn!("Failed loading #{self} (#{e.message})")
end
loadable_files() click to toggle source

Return all *.rb files from valid component paths

@return <Array> Full paths to loadable ruby files.

# File lib/merb-slices/module_mixin.rb, line 246
def loadable_files
  app_components.inject([]) do |paths, type|
    paths += Dir[dir_for(type) / '**/*.rb'] if slice_paths.key?(type)
    paths += Dir[app_dir_for(type) / '**/*.rb'] if app_paths.key?(type)
    paths
  end        
end
loaded() click to toggle source

Stub classes loaded hook - runs before LoadClasses BootLoader right after a slice’s classes have been loaded internally.

# File lib/merb-slices/module_mixin.rb, line 22
def loaded; end
manifest(type = :root) click to toggle source

Return all slice files mapped from the source to their relative path

@param type<Symbol> Which type to use; defaults to :root (all) @return <Array> An array of arrays [abs. source, relative dest.]

# File lib/merb-slices/module_mixin.rb, line 296
def manifest(type = :root)
  files = if type == :root
    Dir.glob(self.root / "**/*")
  elsif slice_paths.key?(type)
    glob = ((type == :view) ? view_templates_glob : glob_for(type) || "**/*")
    Dir.glob(dir_for(type) / glob)
  else 
    []
  end
  files.map { |source| [source, source.relative_path_from(root)] }
end
mirror_all!() click to toggle source

Copies all files from mirrored_components to their app-level location

This includes application and public components.

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.
# File lib/merb-slices/module_mixin.rb, line 348
def mirror_all!
  mirror_files_for mirrored_components + mirrored_public_components
end
mirror_app!() click to toggle source

Copies all application files from mirrored_components to their app-level location

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.
# File lib/merb-slices/module_mixin.rb, line 366
def mirror_app!
  components = mirrored_app_components
  components << :application if application_file?
  mirror_files_for components
end
mirror_files_for(*types) click to toggle source

Copy files from specified component path types to their app-level location

App-level overrides are preserved by creating duplicates before writing gem-level files. Because of their _override postfix they will load after their original implementation. In the case of views, this won’t work, but the user override is preserved nonetheless.

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.

@note Only explicitly defined component paths will be taken into account to avoid

cluttering the app's Merb.root by mistake - since undefined paths default to that.
# File lib/merb-slices/module_mixin.rb, line 393
def mirror_files_for(*types)
  seen, copied, duplicated = [], [], [] # keep track of files we copied
  types.flatten.each do |type|
    if app_paths.key?(type) && (source_path = dir_for(type)) && (destination_path = app_dir_for(type))
      manifest(type).each do |source, relative_path| # this relative path is not what we need here
        next if seen.include?(source)
        mirror_file(source, destination_path / source.relative_path_from(source_path), copied, duplicated)
        seen << source
      end
    end
  end
  [copied, duplicated]
end
mirror_public!() click to toggle source

Copies all application files from mirrored_components to their app-level location

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.
# File lib/merb-slices/module_mixin.rb, line 377
def mirror_public!
  mirror_files_for mirrored_public_components
end
mirror_stubs!() click to toggle source

Copies all files from the (optional) stubs directory to their app-level location

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.
# File lib/merb-slices/module_mixin.rb, line 357
def mirror_stubs!
  mirror_files_for :stub
end
mirrored_app_components() click to toggle source

Return all application path component types to mirror

@return <Array> Component types.

# File lib/merb-slices/module_mixin.rb, line 281
def mirrored_app_components
  mirrored_components & app_components
end
mirrored_components() click to toggle source

Return all path component types to mirror

If config option :mirror is set return a subset, otherwise return all types.

@return <Array> Component types.

# File lib/merb-slices/module_mixin.rb, line 273
def mirrored_components
  all = slice_paths.keys
  config[:mirror].is_a?(Array) ? config[:mirror] & all : all
end
mirrored_public_components() click to toggle source

Return all public path component types to mirror

@return <Array> Component types.

# File lib/merb-slices/module_mixin.rb, line 288
def mirrored_public_components
  mirrored_components & public_components
end
named_routes() click to toggle source

@return <Hash> The named routes for this slice.

# File lib/merb-slices/module_mixin.rb, line 69
def named_routes
  Merb::Slices.named_routes[self.identifier_sym] ||= {}
end
public_components() click to toggle source

Return all public path component types

@return <Array> Component types.

# File lib/merb-slices/module_mixin.rb, line 264
def public_components
  [:stylesheet, :javascript, :image]
end
public_dir_for(type) click to toggle source

Retrieve the relative path to a public directory.

@param type<Symbol> The type of path to retrieve directory for, e.g. :view.

@return <String> The relative path to the public directory for the requested type.

# File lib/merb-slices/module_mixin.rb, line 159
def public_dir_for(type)
  dir = type.is_a?(Symbol) ? self.app_dir_for(type) : self.app_dir_for(:public) / type
  dir = dir.relative_path_from(Merb.dir_for(:public)) rescue '.'
  dir == '.' ? '/' : "/#{dir}"
end
push_app_path(type, path, file_glob = "**/*.rb") click to toggle source

This is the core mechanism for setting up your app-level layout.

@param type<Symbol> The type of path being registered (i.e. :view) @param path<String> The full path @param file_glob<String>

A glob that will be used to autoload files under the path. Defaults to "**/*.rb".

@note The :public path is adapted when the slice is run from bin/slice.

# File lib/merb-slices/module_mixin.rb, line 227
def push_app_path(type, path, file_glob = "**/*.rb")
  enforce!(type => Symbol)
  if type == :public && standalone? && $SLICE_MODULE
    path.gsub!(/\/slices\/#{self.identifier}$/, '')
  end
  app_paths[type] = [path, file_glob]
end
push_path(type, path, file_glob = "**/*.rb") click to toggle source

This is the core mechanism for setting up your slice-level layout.

@param type<Symbol> The type of path being registered (i.e. :view) @param path<String> The full path @param file_glob<String>

A glob that will be used to autoload files under the path. Defaults to "**/*.rb".
# File lib/merb-slices/module_mixin.rb, line 206
def push_path(type, path, file_glob = "**/*.rb")
  enforce!(type => Symbol)
  slice_paths[type] = [path, file_glob]
end
registered() click to toggle source

Stub that gets triggered when a slice has been registered.

@note This is rarely needed but still provided for edge cases.

# File lib/merb-slices/module_mixin.rb, line 18
def registered; end
remove_app_paths(*args) click to toggle source
remove_paths(*args) click to toggle source
root_path(*path) click to toggle source

@param *path<to_s>

The relative path (or list of path components) to a directory under the
root of the application.

@return <String> The full path including the root.

# File lib/merb-slices/module_mixin.rb, line 128
def root_path(*path) File.join(self.root, *path) end
routed?() click to toggle source

Check if there have been any routes setup.

# File lib/merb-slices/module_mixin.rb, line 37
def routed?
  self.named_routes && !self.named_routes.empty?
end
setup_default_structure!() click to toggle source

This sets up the default slice-level and app-level structure.

You can create your own structure by implementing setup_structure and using the push_path and push_app_paths. By default this setup matches what the merb-gen slice generator creates.

# File lib/merb-slices/module_mixin.rb, line 412
def setup_default_structure!
  self.push_app_path(:root, Merb.root / 'slices' / self.identifier, nil)
  
  self.push_path(:stub, root_path('stubs'), nil)
  self.push_app_path(:stub, app_dir_for(:root), nil)
  
  self.push_path(:application, root_path('app'), nil)
  self.push_app_path(:application, app_dir_for(:root) / 'app', nil)

  app_components.each do |component|
    self.push_path(component, dir_for(:application) / "#{component}s")
    self.push_app_path(component, app_dir_for(:application) / "#{component}s")
  end

  self.push_path(:public, root_path('public'), nil)
  self.push_app_path(:public,  Merb.dir_for(:public) / 'slices' / self.identifier, nil)

  public_components.each do |component|
    self.push_path(component, dir_for(:public) / "#{component}s", nil)
    self.push_app_path(component, app_dir_for(:public) / "#{component}s", nil)
  end
end
setup_router(scope) click to toggle source

Stub to setup routes inside the host application.

# File lib/merb-slices/module_mixin.rb, line 34
def setup_router(scope); end
slice_paths() click to toggle source

The slice-level load paths to use when loading the slice.

@return <Hash> The load paths which make up the slice-level structure.

# File lib/merb-slices/module_mixin.rb, line 112
def slice_paths
  @slice_paths ||= Hash.new { [self.root] }
end
standalone?() click to toggle source

Whether we’re in an application or running from the slice dir itself.

# File lib/merb-slices/module_mixin.rb, line 42
def standalone?
  Merb.root == self.root
end
to_param() click to toggle source

Return a value suitable for routes/urls.

# File lib/merb-slices/module_mixin.rb, line 47
def to_param
  self.identifier
end
unpack_slice!() click to toggle source

Unpack a subset of files from the slice to their app-level location; this will also copy /lib, causing merb-slices to pick up the slice there.

@return <Array>

Array of two arrays, one for all copied files, the other for overrides 
that may have been preserved to resolve collisions.

@note Files for the :stub component type are skipped.

# File lib/merb-slices/module_mixin.rb, line 331
def unpack_slice!
  app_slice_root = app_dir_for(:root)
  copied, duplicated = mirror_public!
  manifest.each do |source, relative_path|
    next unless unpack_file?(relative_path)
    mirror_file(source, app_slice_root / relative_path, copied, duplicated)
  end
  [copied, duplicated]
end

Protected Instance Methods

application_file?() click to toggle source

Predicate method to check if the :application component is a file

# File lib/merb-slices/module_mixin.rb, line 504
def application_file?
  File.file?(dir_for(:application) / glob_for(:application))
end
collect_load_paths(modify_load_path = true, push_merb_path = true) click to toggle source

Collect slice-level and app-level load paths to load from.

@param modify_load_path<Boolean>

Whether to add certain paths to $LOAD_PATH; defaults to true.

@param push_merb_path<Boolean>

Whether to add app-level paths using Merb.push_path; defaults to true.
# File lib/merb-slices/module_mixin.rb, line 443
def collect_load_paths(modify_load_path = true, push_merb_path = true)
  self.collected_slice_paths.clear; self.collected_app_paths.clear
  Merb.push_path(:"#{self.name.snake_case}_file", File.dirname(self.file), File.basename(self.file))
  self.collected_app_paths << self.file
  self.slice_paths.each do |component, path|
    if File.directory?(component_path = path.first)
      $LOAD_PATH.unshift(component_path) if modify_load_path && component.in?(:model, :controller, :lib) && !$LOAD_PATH.include?(component_path)
      # slice-level component load path - will be preceded by application/app/component - loaded next by Setup.load_classes
      self.collected_slice_paths << path.first / path.last if path.last
      # app-level component load path (override) path - loaded by BootLoader::LoadClasses
      if (app_glob = self.app_glob_for(component)) && File.directory?(app_component_dir = self.app_dir_for(component))
        self.collected_app_paths << app_component_dir / app_glob
        Merb.push_path(:"#{self.name.snake_case}_#{component}", app_component_dir, app_glob) if push_merb_path
      end
    end
  end
end
mirror_file(source, dest, copied = [], duplicated = [], postfix = '_override') click to toggle source

Helper method to copy a source file to destination while resolving any conflicts.

@param source<String> The source path. @param dest<String> The destination path. @param copied<Array> Keep track of all copied files - relative paths. @param duplicated<Array> Keep track of all duplicated files - relative paths. @param postfix<String> The postfix to use for resolving conflicting filenames.

# File lib/merb-slices/module_mixin.rb, line 468
def mirror_file(source, dest, copied = [], duplicated = [], postfix = '_override')
  base, rest = split_name(source)
  dst_dir = File.dirname(dest)
  dup_path = dst_dir / "#{base}#{postfix}.#{rest}"           
  if File.file?(source)
    FileUtils.mkdir_p(dst_dir) unless File.directory?(dst_dir)
    if File.exists?(dest) && !File.exists?(dup_path) && !FileUtils.identical?(source, dest)
      # copy app-level override to *_override.ext
      FileUtils.copy_entry(dest, dup_path, false, false, true)
      duplicated << dup_path.relative_path_from(Merb.root)
    end
    # copy gem-level original to location
    if !File.exists?(dest) || (File.exists?(dest) && !FileUtils.identical?(source, dest))
      FileUtils.copy_entry(source, dest, false, false, true) 
      copied << dest.relative_path_from(Merb.root)
    end
  end
end
split_name(name) click to toggle source

Split a file name so a postfix can be inserted

@return <Array>

The first element will be the name up to the first dot, the second will be the rest.
# File lib/merb-slices/module_mixin.rb, line 517
def split_name(name)
  file_name = File.basename(name)
  mres = /^([^\/\.]+)\.(.+)$/.match(file_name)
  mres.nil? ? [file_name, ''] : [mres[1], mres[2]]
end
unpack_file?(file) click to toggle source

Predicate method to check if a file should be taken into account when unpacking files

By default any public component paths and stubs are skipped; additionally you can set the :skip_files in the slice’s config for other relative paths to skip.

@param file<String> The relative path to test. @return <TrueClass,FalseClass> True if the file may be mirrored.

# File lib/merb-slices/module_mixin.rb, line 494
def unpack_file?(file)
  @mirror_exceptions_regexp ||= begin
    skip_paths = (mirrored_public_components + [:stub]).map { |type| dir_for(type).relative_path_from(self.root) }
    skip_paths += config[:skip_files] if config[:skip_files].is_a?(Array)
    Regexp.new("^(#{skip_paths.join('|')})")
  end
  not file.match(@mirror_exceptions_regexp)
end
view_templates_glob() click to toggle source

Glob pattern matching all valid template extensions

# File lib/merb-slices/module_mixin.rb, line 509
def view_templates_glob
  "**/*.{#{Merb::Template.template_extensions.join(',')}}"
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.