Class: Pancake::Stack

Inherits:
Object show all
Extended by:
Hooks::OnInherit, Middleware, Paths
Defined in:
lib/pancake/stack/app.rb,
lib/pancake/stack/stack.rb,
lib/pancake/stack/router.rb,
lib/pancake/stack/bootloader.rb,
lib/pancake/stack/configuration.rb

Direct Known Subclasses

Pancake::Stacks::Short

Defined Under Namespace

Classes: BootLoader, Configuration, Router

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Hooks::OnInherit

extended, inherited, on_inherit

Methods included from Middleware

build, extended, middlewares, stack, use

Methods included from Paths

dirs_and_glob_for, dirs_for, extended, paths_for, push_paths, unique_paths_for

Constructor Details

#initialize(app = nil, opts = {}) {|self.configuration(@app_name)| ... } ⇒ Stack

Returns a new instance of Stack.

Yields:



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/pancake/stack/stack.rb', line 49

def initialize(app = nil, opts = {})
  @app_name = opts.delete(:app_name) || self.class

  master = opts.delete(:master)
  self.class.initialize_stack(:master => master) unless self.class.initialized?
  self.class.set_as_master! if master
  Pancake.configuration.stacks[@app_name] = self

  # setup the configuration for this stack
  Pancake.configuration.configs[@app_name] = opts[:config] if opts[:config]
  self.configuration(@app_name)
  yield self.configuration(@app_name) if block_given?

  self.class::BootLoader.run!({
    :stack_class  => self.class,
    :stack        => self,
    :app          => app,
    :app_name     => @app_name,
    :except       => {:level => :init}
  }.merge(opts))
end

Instance Attribute Details

#app_nameObject

Returns the value of attribute app_name.



3
4
5
# File 'lib/pancake/stack/stack.rb', line 3

def app_name
  @app_name
end

Class Method Details

._routerObject



9
10
11
12
13
14
15
16
17
# File 'lib/pancake/stack/router.rb', line 9

def self._router
  @_router ||= begin
    r = self::Router.new
    unless self == Pancake::Stack
      r.router = superclass._router.router.dup
    end
    r
  end
end

.add_root(*args) ⇒ Object

Adds the file to the stack root.

Examples:

MyStack.add_root(__FILE__) # in a file in the root of the stack

Parameters:

  • file
    • The file identifier



39
40
41
# File 'lib/pancake/stack/stack.rb', line 39

def self.add_root(*args)
  roots << Pancake.get_root(*args)
end

.base_template_nameObject

Raises:

  • (Errors::NotImplemented)


153
154
155
# File 'lib/pancake/stack/stack.rb', line 153

def self.base_template_name
  raise Errors::NotImplemented, "Stack may not be used for templates until it implements a base_template_name method"
end

.configuration(label = self, &block) ⇒ Object

Provides access to the configuration block for the stack. If a block is provided, it opens the specific configuration instances anonymous class and allows you to edit it. If no block is provided, it just returns the configuration object.

:api: public



14
15
16
17
18
# File 'lib/pancake/stack/configuration.rb', line 14

def self.configuration(label = self, &block)
  config = Pancake.configuration.configs[label] ||= self::Configuration.new
  config.class.class_eval(&block) if block
  config
end

.create_bootloader_hook(*hooks) ⇒ Object

Creates a bootloader hook(s) of the given name. That are inheritable This will create hooks for use in a bootloader (but will not create the bootloader itself!)

Examples:

MyStack.create_bootloader_hook(:before_stuff, :after_stuff)

MyStack.before_stuff do
  # stuff to do before stuff
end

MyStack.after_stuff do
  # stuff to do after stuff
enc

MyStack.before_stuff.each{|blk| blk.call}


174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/pancake/stack/stack.rb', line 174

def self.create_bootloader_hook(*hooks)
  hooks.each do |hook|
    class_inheritable_reader "_#{hook}"
    instance_variable_set("@_#{hook}", [])

    class_eval <<-RUBY
      def self.#{hook}(&blk)
        _#{hook} << blk if blk
        _#{hook}
      end
    RUBY
  end
end

.initialize_stack(opts = {}) ⇒ Object

Iterates the list of roots in the stack, and initializes the app found their



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/pancake/stack/stack.rb', line 22

def self.initialize_stack(opts = {})
  raise "Stack root not set" if roots.empty?
  master = opts.delete(:master)
  set_as_master! if master
  # Run any :init level bootloaders for this stack
  self::BootLoader.run!(:stack_class => self, :only => {:level => :init})
  # Pick up any new stacks added during the boot process.
  set_as_master! if master

  @initialized = true
end

.initialized?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/pancake/stack/stack.rb', line 45

def self.initialized?
  !!@initialized
end

.load_rake_tasks!(opts = {}) ⇒ Object

Loads the rake task for this stack, and all mounted stacks

To have your rake task loaded include a “tasks” director in the stack root

Tasks found in all stack roots are loaded in the order of the stack roots declearations



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/pancake/stack/stack.rb', line 85

def self.load_rake_tasks!(opts={})
  stackup(opts) # load the application
  master = opts.delete(:master) # Don't get the other stacks to boot as master
  opts[:_rake_files_loaded] ||= []
  # For each mounted application, load the rake tasks
  self::Router.mounted_applications.each do |app|
    if app.mounted_app.respond_to?(:load_rake_tasks!)
      app.mounted_app.load_rake_tasks!(opts)
    end
  end
  paths_for(:rake_tasks).each do |f|
    path = File.join(*f)
    unless opts[:_rake_files_loaded].include?(path)
      load path
      opts[:_rake_files_loaded] << path
    end
  end
end

.new_app_instanceObject

get a new instance of the application for this stack Ovewrite this to provide custom application initialization :api: overwritable



6
7
8
# File 'lib/pancake/stack/app.rb', line 6

def self.new_app_instance
  MISSING_APP
end

.reset_router!Object

Resets the router to use the stacks namespaced router. This allows a router to mixin a module, and have that module mixed in to child stacks/routers. Effectively, this will reset the scope of inheritance so that a stack type can have particular route helpers

When the router is rest, any routes declared in parent stacks will be lost.

Examples:

MyStack.reset_router! # => Replaces the current router with MyStack::Router (instance)


27
28
29
# File 'lib/pancake/stack/router.rb', line 27

def self.reset_router!
  self._router = self::Router.new
end

.router {|_router| ... } ⇒ Object

Yields:



31
32
33
34
# File 'lib/pancake/stack/router.rb', line 31

def self.router
  yield _router if block_given?
  _router
end

.set_as_master!Object

Sets this as a master stack. This means that the “master” directory will be added to all existing stack roots



139
140
141
142
143
144
145
146
147
# File 'lib/pancake/stack/stack.rb', line 139

def self.set_as_master!
  Pancake.master_stack ||= self
  # Want to add master to the roots for this stack only
  roots.dup.each do |root|
    unless root =~ /master\/?$/
      roots << File.join(root, 'master')
    end
  end
end

.stackup(opts = {}, &block) ⇒ Object

Construct a stack using the application, wrapped in the middlewares



73
74
75
76
# File 'lib/pancake/stack/stack.rb', line 73

def self.stackup(opts = {}, &block)
  app = new(nil, opts, &block)
  Pancake.configuration.configs[app.app_name].router
end

Symlinks files in the public roots of this stack and all mounted stacks. Provided a mounted application responds to the symlink_public_files! method then it will be called. symlinks public files from all roots of the stacks to Pancake.root/public

Author:

  • Daniel Neighman



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/pancake/stack/stack.rb', line 110

def self.symlink_public_files!
  raise "Pancake root not set" unless Pancake.root

  public_root = File.join(Pancake.root, "public")
  mount_point = configuration.router.base_url

  unique_paths_for(:public).sort_by{|(r,p)| p}.each do |(r,p)|
    # don't try to symlink the symlinks
    origin_path = File.join(r, p)
    next if r == public_root || FileTest.directory?(origin_path)

    output_path = File.join(public_root, mount_point, p)

    unless File.exists?(File.dirname(output_path))
      FileUtils.mkdir_p(File.dirname(output_path))
    end
    # unless the dir exists... create it
    puts "Linking #{output_path}"
    FileUtils.ln_s(origin_path, output_path, :force => true)
  end

  router.mounted_applications.each do |s|
    if s.mounted_app.respond_to?(:symlink_public_files!)
      s.mounted_app.symlink_public_files!
    end
  end
end

.template(name, opts = {}) ⇒ Object

Raises:

  • (Errors::NotImplemented)


149
150
151
# File 'lib/pancake/stack/stack.rb', line 149

def self.template(name,opts ={})
  raise Errors::NotImplemented, "Stack may not be used for templates until it implements a template method"
end

.with_router {|router| ... } ⇒ Object

Yields:



36
37
38
39
# File 'lib/pancake/stack/router.rb', line 36

def self.with_router
  yield router if block_given?
  router
end

Instance Method Details

#configuration(label = self.class) {|self.class.configuration(label)| ... } ⇒ Object

Yields:



20
21
22
23
# File 'lib/pancake/stack/configuration.rb', line 20

def configuration(label = self.class)
  yield self.class.configuration(label) if block_given?
  self.class.configuration(label)
end