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



8
9
10
11
12
13
# 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

Instance Method Details

#[](key) ⇒ Object



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

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

#[]=(key, value) ⇒ Object



59
60
61
# File 'lib/merb-slices/module_mixin.rb', line 59

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

#activateObject

Stub activation hook - runs after AfterAppLoads BootLoader.



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

def activate; end

#app_componentsArray[Symbol]

Return all application path component types



257
258
259
# File 'lib/merb-slices/module_mixin.rb', line 257

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

#app_dir_for(type) ⇒ String

Retrieve the absolute path to a app-level directory.



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

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

#app_glob_for(type) ⇒ String



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

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

#app_path_for(type, *segments) ⇒ String

Construct an app-level path.



183
184
185
186
# File 'lib/merb-slices/module_mixin.rb', line 183

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.



119
120
121
# File 'lib/merb-slices/module_mixin.rb', line 119

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.



314
315
316
317
318
319
320
321
# 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_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.



105
106
107
# File 'lib/merb-slices/module_mixin.rb', line 105

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.



96
97
98
# File 'lib/merb-slices/module_mixin.rb', line 96

def collected_slice_paths
  @collected_slice_paths ||= []
end

#configHash



64
65
66
# File 'lib/merb-slices/module_mixin.rb', line 64

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

#deactivateObject

Stub deactivation method - not triggered automatically.



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

def deactivate; end

#dir_for(type) ⇒ String

Retrieve the absolute path to a slice-level directory.



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

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

#glob_for(type) ⇒ String



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

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

#initObject

Stub initialization hook - runs before AfterAppLoads BootLoader.



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

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.



77
78
79
80
81
82
83
84
85
86
87
88
89
# 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_filesArray

Return all *.rb files from valid component paths



246
247
248
249
250
251
252
# 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

#loadedObject

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



22
# File '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



296
297
298
299
300
301
302
303
304
305
306
# 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!Array[Array]

Copies all files from mirrored_components to their app-level location

This includes application and public components.



348
349
350
# File 'lib/merb-slices/module_mixin.rb', line 348

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



366
367
368
369
370
# 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) ⇒ 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.



393
394
395
396
397
398
399
400
401
402
403
404
405
# 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!Array[Array]

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



377
378
379
# File 'lib/merb-slices/module_mixin.rb', line 377

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



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

def mirror_stubs!
  mirror_files_for :stub
end

#mirrored_app_componentsArray[Symbol]

Return all application path component types to mirror



281
282
283
# File 'lib/merb-slices/module_mixin.rb', line 281

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.



273
274
275
276
# 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_componentsArray[Symbol]

Return all public path component types to mirror



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

def mirrored_public_components
  mirrored_components & public_components
end

#named_routesHash



69
70
71
# File 'lib/merb-slices/module_mixin.rb', line 69

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

#public_componentsArray[Symbol]

Return all public path component types



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

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

#public_dir_for(type) ⇒ String

Retrieve the relative path to a public directory.



159
160
161
162
163
# 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

#public_path_for(type, *segments) ⇒ String

Construct a path relative to the public directory



172
173
174
# File 'lib/merb-slices/module_mixin.rb', line 172

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.



227
228
229
230
231
232
233
# 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") ⇒ Object

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



206
207
208
209
# 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

#registeredObject

Note:

This is rarely needed but still provided for edge cases.

Stub that gets triggered when a slice has been registered.



18
# File '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.



239
240
241
# File 'lib/merb-slices/module_mixin.rb', line 239

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.



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

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

#root_path(*path) ⇒ String



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

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

#routed?Boolean

Check if there have been any routes setup.



37
38
39
# File '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 the push_path and push_app_paths. By default this setup matches what the merb-gen slice generator creates.



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# 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) ⇒ Object

Stub to setup routes inside the host application.



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

def setup_router(scope); end

#slice_path_for(type, *segments) ⇒ String

Construct a slice-level path.



195
196
197
198
# File 'lib/merb-slices/module_mixin.rb', line 195

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.



112
113
114
# File 'lib/merb-slices/module_mixin.rb', line 112

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 '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 '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.



331
332
333
334
335
336
337
338
339
# 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