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:



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

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
18
# 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.stack = self
    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



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

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

.apply_layout(name = nil, &blk) ⇒ Object

Specify a layout to use for this stack and all children stacks Layouts are provided by Wrapt, and Pancake::Stacks::Short will use the layout when directed to by calling this method. Simply call it to activate layouts with the default options, or provide it with options to direct wrapt.

You can specify a layout to use by name, provide it options or provide a block that you can use to set the layout via the environment.

Examples:

# Direct the short stack to use a layout
layout

# Set the layout to a non-default one
layout "non_standard"

# Directly set the layout via the Wrapt::Layout object
layout do |env|
  r = Rack::Request.new(env)
  l = env['layout']
  if r.params['foo'] == 'bar'
    l.template_name = "foo"
  end
end

See Also:

  • Wrapt
  • Wrapt::Layout


168
169
170
171
# File 'lib/pancake/stack/stack.rb', line 168

def self.apply_layout(name = nil, &blk)
  @use_layout = true
  @default_layout = name
end

.base_template_nameObject

Raises:

  • (Errors::NotImplemented)


204
205
206
# File 'lib/pancake/stack/stack.rb', line 204

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}


225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/pancake/stack/stack.rb', line 225

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

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

.default_layoutObject



181
182
183
184
185
186
187
# File 'lib/pancake/stack/stack.rb', line 181

def self.default_layout
  if @default_layout
    @default_layout
  else
    @default_layout = superclass.respond_to?(:default_layout) && superclass.default_layout
  end
end

.initialize_stack(opts = {}) ⇒ Object

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



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

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)


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

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



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

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)


29
30
31
# File 'lib/pancake/stack/router.rb', line 29

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

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

Yields:



33
34
35
36
# File 'lib/pancake/stack/router.rb', line 33

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



190
191
192
193
194
195
196
197
198
# File 'lib/pancake/stack/stack.rb', line 190

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



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

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



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
137
# File 'lib/pancake/stack/stack.rb', line 111

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)


200
201
202
# File 'lib/pancake/stack/stack.rb', line 200

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

.use_layout?Boolean

Returns:

  • (Boolean)


173
174
175
176
177
178
179
# File 'lib/pancake/stack/stack.rb', line 173

def self.use_layout?
  if @use_layout
    @use_layout
  else
    @use_layout = superclass.respond_to?(:use_layout?) && superclass.use_layout?
  end
end

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

Yields:



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

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