Module: Merb::Slices::ModuleMixin

Defined in:
lib/merb-slices/module_mixin.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(slice_module) ⇒ Object



5
6
7
8
9
10
11
# File 'lib/merb-slices/module_mixin.rb', line 5

def self.extended(slice_module)
  slice_module.meta_class.module_eval do
    attr_accessor :identifier, :identifier_sym, :root, :file
    attr_accessor :routes, :named_routes
    attr_accessor :description, :version, :author
  end
end

Instance Method Details

#[](key) ⇒ Object

Returns The configuration value.

Parameters:

  • The (Symbol)

    configuration key.

Returns:

  • (Object)

    The configuration value.



46
47
48
# File 'lib/merb-slices/module_mixin.rb', line 46

def [](key)
  self.config[key]
end

#[]=(key, value) ⇒ Object

Parameters:

  • The (Symbol)

    configuration key.

  • The (Object)

    configuration value.



52
53
54
# File 'lib/merb-slices/module_mixin.rb', line 52

def []=(key, value)
  self.config[key] = value
end

#activateObject

Stub activation hook - runs after AfterAppLoads BootLoader.



26
# File 'lib/merb-slices/module_mixin.rb', line 26

def activate; end

#app_componentsArray[Symbol]

Return all application path component types

Returns:

  • (Array[Symbol])

    Component types.



269
270
271
# File 'lib/merb-slices/module_mixin.rb', line 269

def app_components
  [:view, :model, :controller, :helper, :mailer, :part]
end

#app_dir_for(type) ⇒ String

Retrieve the absolute path to a app-level directory.

Parameters:

  • type (Symbol)

    The type of path to retrieve directory for, e.g. :view.

Returns:

  • (String)

    The directory for the requested type.



164
# File 'lib/merb-slices/module_mixin.rb', line 164

def app_dir_for(type) self.app_paths[type].first end

#app_glob_for(type) ⇒ String

Returns The pattern with which to match files within the type directory.

Parameters:

  • type (Symbol)

    The type of path to retrieve glob for, e.g. :view.

Returns:

  • (String)

    The pattern with which to match files within the type directory.



169
# File 'lib/merb-slices/module_mixin.rb', line 169

def app_glob_for(type) self.app_paths[type][1] end

#app_path_for(type, *segments) ⇒ String

Construct an app-level path.

Parameters:

  • The (Symbol)

    type of component.

  • *segments (Array[#to_s])

    Path segments to append.

Returns:

  • (String)

    A path within the host application, with added segments.



200
201
202
203
# File 'lib/merb-slices/module_mixin.rb', line 200

def app_path_for(type, *segments)
  prefix = type.is_a?(Symbol) ? self.app_dir_for(type) : self.app_dir_for(:root) / type
  File.join(prefix, *segments)
end

#app_pathsHash

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

Returns:

  • (Hash)

    The load paths which make up the app-level structure.



136
137
138
# File 'lib/merb-slices/module_mixin.rb', line 136

def app_paths
  @app_paths ||= Hash.new { [Merb.root] }
end

#clone_slice!Array[Array]

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.

Returns:

  • (Array[Array])

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



326
327
328
329
330
331
332
333
# File 'lib/merb-slices/module_mixin.rb', line 326

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_pathsArray[String]

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.

Returns:

  • (Array[String])

    Application load paths (with glob pattern)



93
94
95
# File 'lib/merb-slices/module_mixin.rb', line 93

def collected_app_paths
  @collected_app_paths ||= []
end

#collected_slice_pathsArray[String]

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.

Returns:

  • (Array[String])

    load paths (with glob pattern)



84
85
86
# File 'lib/merb-slices/module_mixin.rb', line 84

def collected_slice_paths
  @collected_slice_paths ||= []
end

#configHash

Returns The configuration for this slice.

Returns:

  • (Hash)

    The configuration for this slice.



57
58
59
# File 'lib/merb-slices/module_mixin.rb', line 57

def config
  Merb::Slices::config[self.identifier_sym] ||= {}
end

#deactivateObject

Stub deactivation method - not triggered automatically.



29
# File 'lib/merb-slices/module_mixin.rb', line 29

def deactivate; end

#dir_for(type) ⇒ String

Retrieve the absolute path to a slice-level directory.

Parameters:

  • type (Symbol)

    The type of path to retrieve directory for, e.g. :view.

Returns:

  • (String)

    The absolute path for the requested type.



152
# File 'lib/merb-slices/module_mixin.rb', line 152

def dir_for(type) self.slice_paths[type].first end

#glob_for(type) ⇒ String

Returns The pattern with which to match files within the type directory.

Parameters:

  • type (Symbol)

    The type of path to retrieve glob for, e.g. :view.

Returns:

  • (String)

    The pattern with which to match files within the type directory.



157
# File 'lib/merb-slices/module_mixin.rb', line 157

def glob_for(type) self.slice_paths[type][1] end

#initObject

Stub initialization hook - runs before AfterAppLoads BootLoader.



23
# File 'lib/merb-slices/module_mixin.rb', line 23

def init; end

#load_sliceObject

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.



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/merb-slices/module_mixin.rb', line 65

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_filesArray

Return all *.rb files from valid component paths

Returns:

  • (Array)

    Full paths to loadable ruby files.



258
259
260
261
262
263
264
# File 'lib/merb-slices/module_mixin.rb', line 258

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

#loadedObject

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



20
# File 'lib/merb-slices/module_mixin.rb', line 20

def loaded; end

#manifest(type = :root) ⇒ Array[Array]

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

Parameters:

  • type (Symbol) (defaults to: :root)

    Which type to use; defaults to :root (all)

Returns:

  • (Array[Array])

    An array of arrays [abs. source, relative dest.]



308
309
310
311
312
313
314
315
316
317
318
# File 'lib/merb-slices/module_mixin.rb', line 308

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!Array[Array]

Copies all files from mirrored_components to their app-level location

This includes application and public components.

Returns:

  • (Array[Array])

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



360
361
362
# File 'lib/merb-slices/module_mixin.rb', line 360

def mirror_all!
  mirror_files_for mirrored_components + mirrored_public_components
end

#mirror_app!Array[Array]

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

Returns:

  • (Array[Array])

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



378
379
380
381
382
# File 'lib/merb-slices/module_mixin.rb', line 378

def mirror_app!
  components = mirrored_app_components
  components << :application if application_file?
  mirror_files_for components
end

#mirror_files_for(*types) ⇒ Array[Array]

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.

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.

Returns:

  • (Array[Array])

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



405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/merb-slices/module_mixin.rb', line 405

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!Array[Array]

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

Returns:

  • (Array[Array])

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



389
390
391
# File 'lib/merb-slices/module_mixin.rb', line 389

def mirror_public!
  mirror_files_for mirrored_public_components
end

#mirror_stubs!Array[Array]

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

Returns:

  • (Array[Array])

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



369
370
371
# File 'lib/merb-slices/module_mixin.rb', line 369

def mirror_stubs!
  mirror_files_for :stub
end

#mirrored_app_componentsArray[Symbol]

Return all application path component types to mirror

Returns:

  • (Array[Symbol])

    Component types.



293
294
295
# File 'lib/merb-slices/module_mixin.rb', line 293

def mirrored_app_components
  mirrored_components & app_components
end

#mirrored_componentsArray[Symbol]

Return all path component types to mirror

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

Returns:

  • (Array[Symbol])

    Component types.



285
286
287
288
# File 'lib/merb-slices/module_mixin.rb', line 285

def mirrored_components
  all = slice_paths.keys
  config[:mirror].is_a?(Array) ? config[:mirror] & all : all
end

#mirrored_public_componentsArray[Symbol]

Return all public path component types to mirror

Returns:

  • (Array[Symbol])

    Component types.



300
301
302
# File 'lib/merb-slices/module_mixin.rb', line 300

def mirrored_public_components
  mirrored_components & public_components
end

#public_componentsArray[Symbol]

Return all public path component types

Returns:

  • (Array[Symbol])

    Component types.



276
277
278
# File 'lib/merb-slices/module_mixin.rb', line 276

def public_components
  [:stylesheet, :javascript, :image]
end

#public_dir_for(type) ⇒ String

Retrieve the relative path to a public directory.

Parameters:

  • type (Symbol)

    The type of path to retrieve directory for, e.g. :view.

Returns:

  • (String)

    The relative path to the public directory for the requested type.



176
177
178
179
180
# File 'lib/merb-slices/module_mixin.rb', line 176

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

#public_path_for(type, *segments) ⇒ String

Construct a path relative to the public directory

Parameters:

  • The (Symbol)

    type of component.

  • *segments (Array[#to_s])

    Path segments to append.

Returns:

  • (String)

    A path relative to the public directory, with added segments.



189
190
191
# File 'lib/merb-slices/module_mixin.rb', line 189

def public_path_for(type, *segments)
  File.join(self.public_dir_for(type), *segments)
end

#push_app_path(type, path, file_glob = "**/*.rb") ⇒ Object

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

Parameters:

  • type (Symbol)

    The type of path being registered (i.e. :view)

  • path (String)

    The full path

  • file_glob (String) (defaults to: "**/*.rb")

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



242
243
244
245
# File 'lib/merb-slices/module_mixin.rb', line 242

def push_app_path(type, path, file_glob = "**/*.rb")
  enforce!(type => Symbol)
  app_paths[type] = [path, file_glob]
end

#push_path(type, path, file_glob = "**/*.rb") ⇒ Object

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

Parameters:

  • type (Symbol)

    The type of path being registered (i.e. :view)

  • path (String)

    The full path

  • file_glob (String) (defaults to: "**/*.rb")

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



223
224
225
226
# File 'lib/merb-slices/module_mixin.rb', line 223

def push_path(type, path, file_glob = "**/*.rb")
  enforce!(type => Symbol)
  slice_paths[type] = [path, file_glob]
end

#registeredObject

Note:

This is rarely needed but still provided for edge cases.

Stub that gets triggered when a slice has been registered.



16
# File 'lib/merb-slices/module_mixin.rb', line 16

def registered; end

#remove_app_paths(*args) ⇒ Object

Removes given types of application components from app-level load path this slice uses for autoloading.

Parameters:

  • *args (Array[Symbol])

    Components names, for instance, :views, :models



251
252
253
# File 'lib/merb-slices/module_mixin.rb', line 251

def remove_app_paths(*args)
  args.each { |arg| self.app_paths.delete(arg) }
end

#remove_paths(*args) ⇒ Object

Removes given types of application components from slice-level load path this slice uses for autoloading.

Parameters:

  • *args (Array[Symbol])

    Components names, for instance, :views, :models



232
233
234
# File 'lib/merb-slices/module_mixin.rb', line 232

def remove_paths(*args)
  args.each { |arg| self.slice_paths.delete(arg) }
end

#root_path(*path) ⇒ String

Returns The full path including the root.

Parameters:

  • *path (#to_s)

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

Returns:

  • (String)

    The full path including the root.



145
# File 'lib/merb-slices/module_mixin.rb', line 145

def root_path(*path) File.join(self.root, *path) end

#routed?Boolean

Check if there have been any routes setup.

Returns:

  • (Boolean)


35
36
37
# File 'lib/merb-slices/module_mixin.rb', line 35

def routed?
  self.routes && !self.routes.empty?
end

#setup_default_structure!Object

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.



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/merb-slices/module_mixin.rb', line 424

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) ⇒ Object

Stub to setup routes inside the host application.



32
# File 'lib/merb-slices/module_mixin.rb', line 32

def setup_router(scope); end

#slice_path_for(type, *segments) ⇒ String

Construct a slice-level path.

Parameters:

  • The (Symbol)

    type of component.

  • *segments (Array[#to_s])

    Path segments to append.

Returns:

  • (String)

    A path within the slice source (Gem), with added segments.



212
213
214
215
# File 'lib/merb-slices/module_mixin.rb', line 212

def slice_path_for(type, *segments)
  prefix = type.is_a?(Symbol) ? self.dir_for(type) : self.dir_for(:root) / type
  File.join(prefix, *segments)
end

#slice_pathsHash

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

Returns:

  • (Hash)

    The load paths which make up the slice-level structure.



129
130
131
# File 'lib/merb-slices/module_mixin.rb', line 129

def slice_paths
  @slice_paths ||= Hash.new { [self.root] }
end

#to_paramObject

Return a value suitable for routes/urls.



40
41
42
# File 'lib/merb-slices/module_mixin.rb', line 40

def to_param
  self.identifier
end

#unpack_slice!Array[Array]

Note:

Files for the :stub component type are skipped.

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.

Returns:

  • (Array[Array])

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



343
344
345
346
347
348
349
350
351
# File 'lib/merb-slices/module_mixin.rb', line 343

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

#url(name, rparams = {}, defaults = {}) ⇒ Object

Generate a url - takes the slice’s :path_prefix into account.

This is only relevant for default routes, as named routes are handled correctly without any special considerations.

Parameters:

  • name (#to_sym, Hash)

    The name of the URL to generate.

  • rparams (Hash) (defaults to: {})

    Parameters for the route generation.

Returns:

  • String The generated URL.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/merb-slices/module_mixin.rb', line 109

def url(name, rparams = {}, defaults = {})
  defaults = rparams if name.is_a?(Hash) && defaults.empty?
  rparams  = name    if name.is_a?(Hash)
  
  if name.is_a?(Symbol)
    raise "Named route not found: #{name}" unless self.named_routes[name]
    uri = Merb::Router.generate(name, rparams, defaults)
  else
    defaults[:controller] = defaults[:controller].gsub(%r|^#{self.identifier_sym}/|, '') if defaults[:controller]
    uri = Merb::Router.generate(name, rparams, defaults)
    uri = self[:path_prefix] / uri unless self[:path_prefix].blank?
    uri = "/#{uri}" unless uri[0,1] == '/'
  end
  
  Merb::Config[:path_prefix] ? Merb::Config[:path_prefix] + uri : uri
end