Module: Merb::Slices::ModuleMixin

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(slice_module) ⇒ Object



8
9
10
11
12
13
# File 'merb-slices/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

Instance Method Details

#[](key) ⇒ Object



54
55
56
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 54

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

#[]=(key, value) ⇒ Object



61
62
63
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 61

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

#activateObject

Stub activation hook - runs after AfterAppLoads BootLoader.



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

def activate; end

#app_componentsArray<Symbol>

Return all application path component types.



271
272
273
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 271

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

#app_dir_for(type) ⇒ String

Retrieve the absolute path to a app-level directory.



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

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

#app_glob_for(type) ⇒ String



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

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

#app_path_for(type, *segments) ⇒ String

Construct an app-level path.



192
193
194
195
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 192

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.



121
122
123
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 121

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.



329
330
331
332
333
334
335
336
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 329

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.



107
108
109
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 107

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.



98
99
100
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 98

def collected_slice_paths
  @collected_slice_paths ||= []
end

#configHash



66
67
68
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 66

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

#deactivateObject

Stub deactivation method - not triggered automatically.



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

def deactivate; end

#dir_for(type) ⇒ String

Retrieve the absolute path to a slice-level directory.



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

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

#glob_for(type) ⇒ String



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

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

#initObject

Stub initialization hook - runs before AfterAppLoads BootLoader.



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

def init; end

#load_sliceObject

Load slice and its 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.



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 79

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<String>

Return all *.rb files from valid component paths.



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

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.



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

def loaded; end

#manifest(type = :root) ⇒ Array<Array>

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



311
312
313
314
315
316
317
318
319
320
321
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 311

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.



358
359
360
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 358

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.



374
375
376
377
378
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 374

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.



402
403
404
405
406
407
408
409
410
411
412
413
414
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 402

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.



384
385
386
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 384

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



366
367
368
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 366

def mirror_stubs!
  mirror_files_for :stub
end

#mirrored_app_componentsArray<Symbol>

Return all application path component types to mirror.



296
297
298
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 296

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.



288
289
290
291
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 288

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

#mirrored_public_componentsArraySymbol

Return all public path component types to mirror.



303
304
305
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 303

def mirrored_public_components
  mirrored_components & public_components
end

#named_routesHash



71
72
73
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 71

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

#public_componentsArray<Symbol>

Return all public path component types.



278
279
280
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 278

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

#public_dir_for(type) ⇒ String

Retrieve the relative path to a public directory.



168
169
170
171
172
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 168

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.



181
182
183
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 181

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

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

Note:

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

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



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

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

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



216
217
218
219
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 216

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.



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

def registered; end

#remove_app_paths(*args) ⇒ Object

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



253
254
255
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 253

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.



226
227
228
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 226

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

#root_path(*path) ⇒ String



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

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

#routed?Boolean

Check if there have been any routes setup.



37
38
39
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 37

def routed?
  self.named_routes && !self.named_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 #push_path and #push_app_path. By default this setup matches what the merb-gen slice generator creates.



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

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.



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

def setup_router(scope); end

#slice_path_for(type, *segments) ⇒ String

Construct a slice-level path.



204
205
206
207
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 204

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.



114
115
116
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 114

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

#standalone?Boolean

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



42
43
44
# File 'merb-slices/lib/merb-slices/module_mixin.rb', line 42

def standalone?
  Merb.root == self.root
end

#to_paramObject

Return a value suitable for routes/urls.



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

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.



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

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