pancake 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +95 -0
- data/Rakefile +56 -0
- data/TODO +17 -0
- data/bin/jeweler +19 -0
- data/bin/pancake-gen +17 -0
- data/bin/rubyforge +19 -0
- data/lib/pancake/bootloaders.rb +180 -0
- data/lib/pancake/configuration.rb +145 -0
- data/lib/pancake/constants.rb +5 -0
- data/lib/pancake/core_ext/class.rb +44 -0
- data/lib/pancake/core_ext/object.rb +22 -0
- data/lib/pancake/core_ext/symbol.rb +15 -0
- data/lib/pancake/defaults/configuration.rb +22 -0
- data/lib/pancake/defaults/middlewares.rb +1 -0
- data/lib/pancake/errors.rb +61 -0
- data/lib/pancake/generators/base.rb +12 -0
- data/lib/pancake/generators/micro_generator.rb +17 -0
- data/lib/pancake/generators/short_generator.rb +17 -0
- data/lib/pancake/generators/stack_generator.rb +17 -0
- data/lib/pancake/generators/templates/common/dotgitignore +22 -0
- data/lib/pancake/generators/templates/common/dothtaccess +17 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/%stack_name%.rb.tt +8 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/config.ru.tt +12 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/pancake.init.tt +1 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/public/.empty_directory +0 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/tmp/.empty_directory +0 -0
- data/lib/pancake/generators/templates/micro/%stack_name%/views/root.html.haml +1 -0
- data/lib/pancake/generators/templates/short/%stack_name%/LICENSE.tt +20 -0
- data/lib/pancake/generators/templates/short/%stack_name%/README.tt +7 -0
- data/lib/pancake/generators/templates/short/%stack_name%/Rakefile.tt +50 -0
- data/lib/pancake/generators/templates/short/%stack_name%/VERSION.tt +1 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/%stack_name%.rb.tt +6 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config.ru.tt +10 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/views/root.html.haml +2 -0
- data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%.rb.tt +5 -0
- data/lib/pancake/generators/templates/short/%stack_name%/pancake.init.tt +1 -0
- data/lib/pancake/generators/templates/short/%stack_name%/spec/%stack_name%_spec.rb.tt +7 -0
- data/lib/pancake/generators/templates/short/%stack_name%/spec/spec_helper.rb.tt +9 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/LICENSE.tt +20 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/README.tt +7 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/Rakefile.tt +50 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/VERSION.tt +1 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/environments/development.rb.tt +18 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/environments/production.rb.tt +18 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/router.rb.tt +6 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config.ru.tt +12 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/gems/cache/.empty_directory +0 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%.rb.tt +3 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/pancake.init.tt +1 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/spec/%stack_name%_spec.rb.tt +7 -0
- data/lib/pancake/generators/templates/stack/%stack_name%/spec/spec_helper.rb.tt +9 -0
- data/lib/pancake/generators.rb +8 -0
- data/lib/pancake/hooks/inheritable_inner_classes.rb +60 -0
- data/lib/pancake/hooks/on_inherit.rb +34 -0
- data/lib/pancake/logger.rb +200 -0
- data/lib/pancake/master.rb +123 -0
- data/lib/pancake/middleware.rb +347 -0
- data/lib/pancake/middlewares/logger.rb +16 -0
- data/lib/pancake/middlewares/static.rb +38 -0
- data/lib/pancake/mime_types.rb +265 -0
- data/lib/pancake/mixins/publish/action_options.rb +104 -0
- data/lib/pancake/mixins/publish.rb +125 -0
- data/lib/pancake/mixins/render/render.rb +168 -0
- data/lib/pancake/mixins/render/template.rb +23 -0
- data/lib/pancake/mixins/render/view_context.rb +21 -0
- data/lib/pancake/mixins/render.rb +109 -0
- data/lib/pancake/mixins/request_helper.rb +100 -0
- data/lib/pancake/mixins/stack_helper.rb +46 -0
- data/lib/pancake/mixins/url.rb +10 -0
- data/lib/pancake/paths.rb +218 -0
- data/lib/pancake/router.rb +99 -0
- data/lib/pancake/stack/app.rb +10 -0
- data/lib/pancake/stack/bootloader.rb +79 -0
- data/lib/pancake/stack/configuration.rb +44 -0
- data/lib/pancake/stack/middleware.rb +0 -0
- data/lib/pancake/stack/router.rb +21 -0
- data/lib/pancake/stack/stack.rb +66 -0
- data/lib/pancake/stacks/short/bootloaders.rb +13 -0
- data/lib/pancake/stacks/short/controller.rb +116 -0
- data/lib/pancake/stacks/short/default/views/base.html.haml +5 -0
- data/lib/pancake/stacks/short/stack.rb +187 -0
- data/lib/pancake/stacks/short.rb +3 -0
- data/lib/pancake.rb +58 -0
- data/spec/helpers/helpers.rb +20 -0
- data/spec/helpers/matchers.rb +25 -0
- data/spec/pancake/bootloaders_spec.rb +109 -0
- data/spec/pancake/configuration_spec.rb +177 -0
- data/spec/pancake/constants_spec.rb +7 -0
- data/spec/pancake/defaults/configuration_spec.rb +58 -0
- data/spec/pancake/fixtures/foo_stack/pancake.init +0 -0
- data/spec/pancake/fixtures/middlewares/other_public/two.html +1 -0
- data/spec/pancake/fixtures/middlewares/public/foo#bar.html +1 -0
- data/spec/pancake/fixtures/middlewares/public/one.html +1 -0
- data/spec/pancake/fixtures/paths/controllers/controller1.rb +0 -0
- data/spec/pancake/fixtures/paths/controllers/controller2.rb +0 -0
- data/spec/pancake/fixtures/paths/controllers/controller3.rb +0 -0
- data/spec/pancake/fixtures/paths/models/model1.rb +0 -0
- data/spec/pancake/fixtures/paths/models/model2.rb +0 -0
- data/spec/pancake/fixtures/paths/models/model3.rb +0 -0
- data/spec/pancake/fixtures/paths/stack/controllers/controller1.rb +0 -0
- data/spec/pancake/fixtures/paths/stack/models/model3.rb +0 -0
- data/spec/pancake/fixtures/paths/stack/views/view1.erb +0 -0
- data/spec/pancake/fixtures/paths/stack/views/view1.rb +0 -0
- data/spec/pancake/fixtures/paths/stack/views/view2.erb +0 -0
- data/spec/pancake/fixtures/paths/stack/views/view2.haml +0 -0
- data/spec/pancake/fixtures/render_templates/context_template.html.erb +2 -0
- data/spec/pancake/fixtures/render_templates/erb_template.html.erb +1 -0
- data/spec/pancake/fixtures/render_templates/erb_template.json.erb +1 -0
- data/spec/pancake/fixtures/render_templates/haml_template.html.haml +1 -0
- data/spec/pancake/fixtures/render_templates/haml_template.xml.haml +1 -0
- data/spec/pancake/fixtures/render_templates/templates/context.erb +2 -0
- data/spec/pancake/fixtures/render_templates/view_context/capture_erb.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/capture_haml.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/concat_erb.erb +2 -0
- data/spec/pancake/fixtures/render_templates/view_context/concat_haml.haml +2 -0
- data/spec/pancake/fixtures/render_templates/view_context/context.erb +3 -0
- data/spec/pancake/fixtures/render_templates/view_context/context2.erb +3 -0
- data/spec/pancake/fixtures/render_templates/view_context/helper_methods.erb +3 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_erb_from_haml.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_erb_level_0.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_erb_level_1.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_haml_from_erb.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_haml_level_0.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/inherited_haml_level_1.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/nested_content_level_0.haml +6 -0
- data/spec/pancake/fixtures/render_templates/view_context/nested_content_level_1.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/nested_inner.erb +1 -0
- data/spec/pancake/fixtures/render_templates/view_context/nested_outer.erb +3 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_erb_from_erb_0.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_erb_from_erb_1.erb +6 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_erb_from_haml_0.erb +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_erb_from_haml_1.erb +6 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_haml_from_erb_0.haml +4 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_haml_from_erb_1.haml +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_haml_from_haml_0.haml +5 -0
- data/spec/pancake/fixtures/render_templates/view_context/super_haml_from_haml_1.haml +5 -0
- data/spec/pancake/fixtures/stacks/short/foobar/other_root/views/base.html.haml +4 -0
- data/spec/pancake/fixtures/stacks/short/foobar/views/basic.html.haml +1 -0
- data/spec/pancake/fixtures/stacks/short/foobar/views/inherited_from_base.html.haml +5 -0
- data/spec/pancake/hooks/on_inherit_spec.rb +65 -0
- data/spec/pancake/inheritance_spec.rb +100 -0
- data/spec/pancake/middleware_spec.rb +401 -0
- data/spec/pancake/middlewares/logger_spec.rb +29 -0
- data/spec/pancake/middlewares/static_spec.rb +83 -0
- data/spec/pancake/mime_types_spec.rb +234 -0
- data/spec/pancake/mixins/publish_spec.rb +94 -0
- data/spec/pancake/mixins/render/template_spec.rb +69 -0
- data/spec/pancake/mixins/render/view_context_spec.rb +248 -0
- data/spec/pancake/mixins/render_spec.rb +56 -0
- data/spec/pancake/mixins/request_helper_spec.rb +27 -0
- data/spec/pancake/mixins/stack_helper_spec.rb +46 -0
- data/spec/pancake/pancake_spec.rb +90 -0
- data/spec/pancake/paths_spec.rb +210 -0
- data/spec/pancake/stack/app_spec.rb +28 -0
- data/spec/pancake/stack/bootloader_spec.rb +41 -0
- data/spec/pancake/stack/middleware_spec.rb +0 -0
- data/spec/pancake/stack/router_spec.rb +282 -0
- data/spec/pancake/stack/stack_configuration_spec.rb +101 -0
- data/spec/pancake/stack/stack_spec.rb +60 -0
- data/spec/pancake/stacks/short/controller_spec.rb +322 -0
- data/spec/pancake/stacks/short/middlewares_spec.rb +22 -0
- data/spec/pancake/stacks/short/router_spec.rb +136 -0
- data/spec/pancake/stacks/short/stack_spec.rb +64 -0
- data/spec/spec_helper.rb +23 -0
- metadata +294 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
module Pancake
|
2
|
+
class Stack
|
3
|
+
inheritable_inner_classes :BootLoader
|
4
|
+
|
5
|
+
# The default bootloader is where the stack default bootloaders are stored
|
6
|
+
# These are shared across all bootloaders
|
7
|
+
class BootLoader # :nodoc:
|
8
|
+
extend ::Pancake::BootLoaderMixin
|
9
|
+
end
|
10
|
+
|
11
|
+
end # Stack
|
12
|
+
end # Pancake
|
13
|
+
|
14
|
+
#################### Define the bootloaders here #############################
|
15
|
+
# :level => :init bootloaders only have the stack class available
|
16
|
+
# They do not have :stack available
|
17
|
+
# These are not run directly, but are run from inherited stacks
|
18
|
+
Pancake::Stack::BootLoader.add(:mount_applications, :level => :init) do
|
19
|
+
def run!
|
20
|
+
# Mount any stacks this stack may have in it.
|
21
|
+
stack_class.roots.each do |root|
|
22
|
+
Dir["#{root}/mounts/*/pancake.init"].each{|f| load f if File.exists?(f)}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Pancake::Stack::BootLoader.add(:load_configuration, :level => :init) do
|
28
|
+
def run!
|
29
|
+
stack_class.roots.each do |root|
|
30
|
+
stack_class.paths_for(:config).each{|f| require f.join}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Pancake::Stack::BootLoader.add(:load_application, :level => :init) do
|
36
|
+
def run!
|
37
|
+
stack_class.roots.each do |root|
|
38
|
+
[:models, :controllers].each do |type|
|
39
|
+
stack_class.paths_for(type).each{|f| require f.join}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Pancake::Stack::BootLoader.add(:load_routes, :level => :init) do
|
46
|
+
def run!
|
47
|
+
stack_class.roots.each do |root|
|
48
|
+
stack_class.paths_for(:router).each{|f| require f.join}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
###### -================== Stack Building BootLoaders
|
54
|
+
# Pancake stacks need to be built with the following options
|
55
|
+
# MyApp::BootLoader.run!({
|
56
|
+
# :stack_class => self.class,
|
57
|
+
# :stack => self,
|
58
|
+
# :app => app,
|
59
|
+
# :app_name => app_name,
|
60
|
+
# })
|
61
|
+
#
|
62
|
+
#
|
63
|
+
|
64
|
+
Pancake::Stack::BootLoader.add(:initialize_application) do
|
65
|
+
def run!
|
66
|
+
config[:app] ||= stack_class.new_app_instance
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Pancake::Stack::BootLoader.add(:build_stack) do
|
71
|
+
def run!
|
72
|
+
mwares = stack_class.middlewares(Pancake.stack_labels)
|
73
|
+
app = Pancake::Middleware.build(config[:app], mwares)
|
74
|
+
app_config = Pancake.configuration.configs(config[:app_name])
|
75
|
+
app_config.app = app
|
76
|
+
app_config.stack = stack_class
|
77
|
+
app_config.router.configuration = app_config
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Pancake
|
2
|
+
class Stack
|
3
|
+
|
4
|
+
class Configuration < Pancake::Configuration::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
# Provides access to the configuration block for the stack.
|
8
|
+
# If a block is provided, it opens the specific configuration instances anonymous class
|
9
|
+
# and allows you to edit it.
|
10
|
+
# If no block is provided, it just returns the configuration object.
|
11
|
+
#
|
12
|
+
# :api: public
|
13
|
+
def self.configuration(label = self, &block)
|
14
|
+
config = Pancake.configuration.configs[label] ||= self::Configuration.new
|
15
|
+
config.class.class_eval(&block) if block
|
16
|
+
config
|
17
|
+
end
|
18
|
+
|
19
|
+
def configuration(label = self.class)
|
20
|
+
yield self.class.configuration(label) if block_given?
|
21
|
+
self.class.configuration(label)
|
22
|
+
end
|
23
|
+
|
24
|
+
end # Stack
|
25
|
+
end # Pancake
|
26
|
+
|
27
|
+
####################
|
28
|
+
# Setup the default configuration for each stack
|
29
|
+
class Pancake::Stack::Configuration
|
30
|
+
default :router, lambda{ _router }, "The router for this stack"
|
31
|
+
|
32
|
+
def _router
|
33
|
+
@_router ||= begin
|
34
|
+
unless stack.nil?
|
35
|
+
r = stack.router.dup
|
36
|
+
r.configuration = self
|
37
|
+
r.app = app
|
38
|
+
r.configuration = self
|
39
|
+
r
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pancake
|
2
|
+
class Stack
|
3
|
+
class Router < Pancake::Router; end
|
4
|
+
inheritable_inner_classes :Router
|
5
|
+
|
6
|
+
class_inheritable_accessor :_router
|
7
|
+
@_router = self::Router.new
|
8
|
+
|
9
|
+
def self.router
|
10
|
+
yield _router if block_given?
|
11
|
+
_router
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.with_router
|
15
|
+
yield router if block_given?
|
16
|
+
router
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Pancake
|
2
|
+
class Stack
|
3
|
+
attr_accessor :app_name
|
4
|
+
|
5
|
+
# extend Hooks::InheritableInnerClasses
|
6
|
+
extend Hooks::OnInherit
|
7
|
+
extend Pancake::Middleware
|
8
|
+
extend Pancake::Paths
|
9
|
+
|
10
|
+
# Push the default paths in for this stack
|
11
|
+
push_paths(:config, "config", "config.rb")
|
12
|
+
push_paths(:config, "config/environments", "#{Pancake.env}.rb")
|
13
|
+
push_paths(:models, "app/models", "**/*.rb")
|
14
|
+
push_paths(:controllers, "app/controllers", "**/*.rb")
|
15
|
+
push_paths(:router, "config", "router.rb")
|
16
|
+
|
17
|
+
#Iterates the list of roots in the stack, and initializes the app found their
|
18
|
+
def self.initialize_stack
|
19
|
+
raise "Application root not set" if roots.empty?
|
20
|
+
|
21
|
+
# Run any :init level bootloaders for this stack
|
22
|
+
self::BootLoader.run!(:stack_class => self, :only => {:level => :init})
|
23
|
+
|
24
|
+
@initialized = true
|
25
|
+
end # initiailze stack
|
26
|
+
|
27
|
+
# Adds the file to the stack root.
|
28
|
+
#
|
29
|
+
# @param file - The file identifier
|
30
|
+
# @example
|
31
|
+
# MyStack.add_root(__FILE__) # in a file in the root of the stack
|
32
|
+
def self.add_root(*args)
|
33
|
+
roots << Pancake.get_root(*args)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.initialized?
|
37
|
+
!!@initialized
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(app = nil, opts = {})
|
41
|
+
@app_name = opts.delete(:app_name) || self.class
|
42
|
+
self.class.initialize_stack unless self.class.initialized?
|
43
|
+
Pancake.configuration.stacks[@app_name] = self
|
44
|
+
|
45
|
+
# setup the configuration for this stack
|
46
|
+
Pancake.configuration.configs[@app_name] = opts[:config] if opts [:config]
|
47
|
+
self.configuration(@app_name)
|
48
|
+
yield self.configuration(@app_name) if block_given?
|
49
|
+
|
50
|
+
self.class::BootLoader.run!({
|
51
|
+
:stack_class => self.class,
|
52
|
+
:stack => self,
|
53
|
+
:app => app,
|
54
|
+
:app_name => @app_name,
|
55
|
+
:except => {:level => :init}
|
56
|
+
}.merge(opts))
|
57
|
+
end
|
58
|
+
|
59
|
+
# Construct a stack using the application, wrapped in the middlewares
|
60
|
+
# :api: public
|
61
|
+
def self.stackup(opts = {}, &block)
|
62
|
+
app = new(nil, opts, &block)
|
63
|
+
Pancake.configuration.configs[app.app_name].router
|
64
|
+
end # stackup
|
65
|
+
end # Stack
|
66
|
+
end # Pancake
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Pancake::Stacks::Short::BootLoader.add(:paths) do
|
2
|
+
def run!
|
3
|
+
stack_class.push_paths :public, "public"
|
4
|
+
|
5
|
+
stack_class::Controller.push_paths :views, ["app/views", "views"], "**/*"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Pancake::Stacks::Short::BootLoader.add(:default_middlewares, :before => :build_stack) do
|
10
|
+
def run!
|
11
|
+
stack_class.stack(:static_files).use(Pancake::Middlewares::Static, stack_class)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Pancake
|
2
|
+
module Stacks
|
3
|
+
class Short
|
4
|
+
inheritable_inner_classes :Controller
|
5
|
+
|
6
|
+
class Controller
|
7
|
+
extend Mixins::Publish
|
8
|
+
include Mixins::Render
|
9
|
+
include Mixins::RequestHelper
|
10
|
+
include Mixins::StackHelper
|
11
|
+
|
12
|
+
class_inheritable_accessor :_handle_exception
|
13
|
+
|
14
|
+
|
15
|
+
DEFAULT_EXCEPTION_HANDLER = lambda do |error|
|
16
|
+
"#{error.name}: #{error.description}"
|
17
|
+
end unless defined?(DEFAULT_EXCEPTION_HANDLER)
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def self.call(env)
|
21
|
+
app = new(env)
|
22
|
+
app.dispatch!
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api public
|
26
|
+
attr_accessor :status
|
27
|
+
|
28
|
+
def initialize(env)
|
29
|
+
@env, @request = env, Rack::Request.new(env)
|
30
|
+
@status = 200
|
31
|
+
end
|
32
|
+
|
33
|
+
# Provides access to the request params
|
34
|
+
# @api public
|
35
|
+
def params
|
36
|
+
request.params
|
37
|
+
end
|
38
|
+
|
39
|
+
# Dispatches to an action based on the params["action"] parameter
|
40
|
+
def dispatch!
|
41
|
+
params["action"] ||= params[:action]
|
42
|
+
params[:format] ||= params["format"]
|
43
|
+
|
44
|
+
if logger
|
45
|
+
logger.info "Request: #{request.path}"
|
46
|
+
logger.info "Params: #{params.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check that the action is available
|
50
|
+
raise Errors::NotFound, "No Action Found" unless allowed_action?(params["action"])
|
51
|
+
|
52
|
+
@action_opts = actions[params["action"]]
|
53
|
+
if params[:format]
|
54
|
+
@content_type, ct, @mime_type = Pancake::MimeTypes.negotiate_by_extension(params[:format].to_s, @action_opts.formats)
|
55
|
+
else
|
56
|
+
@content_type, ct, @mime_type = Pancake::MimeTypes.negotiate_accept_type(env["HTTP_ACCEPT"], @action_opts.formats)
|
57
|
+
end
|
58
|
+
|
59
|
+
raise Errors::NotAcceptable unless @content_type
|
60
|
+
|
61
|
+
logger.info "Dispatching to #{params["action"].inspect}" if logger
|
62
|
+
|
63
|
+
# set the response header
|
64
|
+
headers["Content-Type"] = ct
|
65
|
+
Rack::Response.new(self.send(params["action"]), status, headers).finish
|
66
|
+
|
67
|
+
rescue Errors::HttpError => e
|
68
|
+
if logger
|
69
|
+
logger.error "Exception: #{e.message}"
|
70
|
+
logger.error e.backtrace.join("\n")
|
71
|
+
end
|
72
|
+
handle_request_exception(e)
|
73
|
+
rescue Exception => e
|
74
|
+
server_error = Errors::Server.new
|
75
|
+
server_error.exceptions << e
|
76
|
+
handle_request_exception(server_error)
|
77
|
+
end
|
78
|
+
|
79
|
+
def content_type
|
80
|
+
@content_type
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.handle_exception(&block)
|
84
|
+
if block_given?
|
85
|
+
self._handle_exception = block
|
86
|
+
else
|
87
|
+
self._handle_exception || DEFAULT_EXCEPTION_HANDLER
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def handle_request_exception(error)
|
92
|
+
raise error unless Pancake.handle_errors?
|
93
|
+
self.status = error.code
|
94
|
+
result = instance_exec error, &self.class.handle_exception
|
95
|
+
Rack::Response.new(result, status, headers).finish
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def allowed_action?(action)
|
100
|
+
self.class.actions.include?(action.to_s)
|
101
|
+
end
|
102
|
+
|
103
|
+
public
|
104
|
+
def self.roots
|
105
|
+
stack_class.roots
|
106
|
+
end
|
107
|
+
|
108
|
+
def _tempate_name_for(name, opts)
|
109
|
+
opts[:format] ||= content_type
|
110
|
+
"#{name}.#{opts[:format]}"
|
111
|
+
end
|
112
|
+
end # Controller
|
113
|
+
|
114
|
+
end # Short
|
115
|
+
end # Stacks
|
116
|
+
end # Pancake
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module Pancake
|
2
|
+
module Stacks
|
3
|
+
class Short < Pancake::Stack
|
4
|
+
add_root(__FILE__, "default")
|
5
|
+
|
6
|
+
def self.new_app_instance
|
7
|
+
self::Controller
|
8
|
+
end
|
9
|
+
|
10
|
+
# Marks a method as published.
|
11
|
+
# This is done implicitly when using the get, post, put, delete methods on a Stacks::Short
|
12
|
+
# But can be done explicitly
|
13
|
+
#
|
14
|
+
# @see Pancake::Mixins::Publish#publish
|
15
|
+
# @api public
|
16
|
+
def self.publish(*args)
|
17
|
+
@published = true
|
18
|
+
self::Controller.publish(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @see Pancake::Mixins::Publish#as
|
22
|
+
def self.as(*args)
|
23
|
+
self::Controller.as(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @see Pancake::Mixins::Publish#provides
|
27
|
+
def self.provides(*formats)
|
28
|
+
self::Controller.provides(*formats)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.handle_exception(*args, &block)
|
32
|
+
self::Controller.handle_exception(*args, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Gets a resource at a given path
|
36
|
+
#
|
37
|
+
# The block should finish with the final result of the action
|
38
|
+
#
|
39
|
+
# @param [String] path - a url path that conforms to Usher match path.
|
40
|
+
# @param block - the contents of the block are executed when the path is matched.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# get "/posts(/:year(/:month(/:date))" do
|
44
|
+
# # do stuff to get posts and render them
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @see Usher
|
48
|
+
# @api public
|
49
|
+
# @author Daniel Neighman
|
50
|
+
def self.get(path, opts = {}, &block)
|
51
|
+
define_published_action(:get, path, opts, block)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Posts a resource to a given path
|
55
|
+
#
|
56
|
+
# The block should finish with the final result of the action
|
57
|
+
#
|
58
|
+
# @param [String] path - a url path that conforms to Usher match path.
|
59
|
+
# @param block - the contents of the block are executed when the path is matched.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# post "/posts" do
|
63
|
+
# # do stuff to post /posts and render them
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @see Usher
|
67
|
+
# @api public
|
68
|
+
# @author Daniel Neighman
|
69
|
+
def self.post(path, opts = {}, &block)
|
70
|
+
define_published_action(:post, path, opts, block)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Puts a resource to a given path
|
74
|
+
#
|
75
|
+
# The block should finish with the final result of the action
|
76
|
+
#
|
77
|
+
# @param [String] path - a url path that conforms to Usher match path.
|
78
|
+
# @param block - the contents of the block are executed when the path is matched.
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# put "/posts" do
|
82
|
+
# # do stuff to post /posts and render them
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @see Usher
|
86
|
+
# @api public
|
87
|
+
# @author Daniel Neighman
|
88
|
+
def self.put(path, opts = {}, &block)
|
89
|
+
define_published_action(:put, path, opts, block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Deletes the resource at a given path
|
93
|
+
#
|
94
|
+
# The block should finish with the final result of the action
|
95
|
+
#
|
96
|
+
# @param [String] path - a url path that conforms to Usher match path.
|
97
|
+
# @param block - the contents of the block are executed when the path is matched.
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# delete "/posts/foo-is-post" do
|
101
|
+
# # do stuff to post foo-is-post and render the result
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# @see Usher
|
105
|
+
# @api public
|
106
|
+
# @author Daniel Neighman
|
107
|
+
def self.delete(path, opts = {}, &block)
|
108
|
+
define_published_action(:delete, path, opts, block)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
# Defines an action on the inner Controller class of this stack.
|
113
|
+
# Also sets it as published if it's not already published.
|
114
|
+
#
|
115
|
+
# @param [Symbol] method - a smbol specifying the HTTP method
|
116
|
+
# @param [String] path - a string specifying the path to map the url to
|
117
|
+
# @api private
|
118
|
+
# @author Daniel Neighman
|
119
|
+
def self.define_published_action(method, path, opts, block)
|
120
|
+
self::Controller.publish unless @published
|
121
|
+
@published = nil
|
122
|
+
|
123
|
+
action_name = controller_method_name(method,path)
|
124
|
+
attach_action(action_name, block)
|
125
|
+
|
126
|
+
attach_route(method, path, action_name, opts)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Does the work of actually defining the action on the Controller Class
|
130
|
+
#
|
131
|
+
# @param [String] - the name of the method to create on the Controller class
|
132
|
+
# @api private
|
133
|
+
# @author Daniel Neighman
|
134
|
+
def self.attach_action(method_name, block)
|
135
|
+
self::Controller.class_eval do
|
136
|
+
define_method(method_name, &block)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Supplies the path as a route to the stack router
|
141
|
+
#
|
142
|
+
# @param method [Symbol]
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# attach_route(:get, "/foo/bar", "get__foo_bar")
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
# @author Daniel Neighman
|
149
|
+
def self.attach_route(method, path, action_name, options)
|
150
|
+
name = options.delete(:_name)
|
151
|
+
options[:conditions] ||= {}
|
152
|
+
options[:conditions][:request_method] = method.to_s.upcase
|
153
|
+
options[:default_values] ||= {}
|
154
|
+
options[:default_values][:action] = action_name
|
155
|
+
r = router.add(path, options)
|
156
|
+
r.name(name) if name
|
157
|
+
r
|
158
|
+
end
|
159
|
+
|
160
|
+
# provides for methods of the following form on Controller
|
161
|
+
# :<method>_<sanitized_path>
|
162
|
+
#
|
163
|
+
# @param [Symbol] method - the HTTP method to look for
|
164
|
+
# @param [String] path - the url path expression to encode into the method name
|
165
|
+
#
|
166
|
+
# @return [String] - The actual controller method name to use for the action
|
167
|
+
#
|
168
|
+
# @api private
|
169
|
+
# @author Daniel Neighman
|
170
|
+
def self.controller_method_name(method, path)
|
171
|
+
"#{method}_#{sanitize_path(path)}"
|
172
|
+
end
|
173
|
+
|
174
|
+
# sanitizes a path so it's able to be used as a method name
|
175
|
+
#
|
176
|
+
# @param [String] path - the path to sanitize
|
177
|
+
#
|
178
|
+
# @return [String] the sanitized version of the path safe to use as a method name
|
179
|
+
# @api private
|
180
|
+
# @author Daniel Neighman
|
181
|
+
def self.sanitize_path(path)
|
182
|
+
path.gsub(/\W/, "_")
|
183
|
+
end
|
184
|
+
|
185
|
+
end # Short
|
186
|
+
end # Stacks
|
187
|
+
end # Pancake
|
data/lib/pancake.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'extlib/class'
|
3
|
+
require 'extlib/boolean'
|
4
|
+
require 'extlib/module'
|
5
|
+
require 'extlib/nil'
|
6
|
+
require 'extlib/numeric'
|
7
|
+
require 'extlib/object'
|
8
|
+
require 'extlib/symbol'
|
9
|
+
require 'extlib/blank'
|
10
|
+
require "extlib/dictionary"
|
11
|
+
require 'extlib/logger'
|
12
|
+
require 'usher'
|
13
|
+
require 'usher/interface/rack_interface'
|
14
|
+
require 'tilt'
|
15
|
+
|
16
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
17
|
+
|
18
|
+
module Pancake
|
19
|
+
autoload :Logger, "pancake/logger"
|
20
|
+
autoload :Constants, "pancake/constants"
|
21
|
+
|
22
|
+
module Stacks
|
23
|
+
autoload :Short, "pancake/stacks/short"
|
24
|
+
end
|
25
|
+
|
26
|
+
module Mixins
|
27
|
+
autoload :Publish, "pancake/mixins/publish"
|
28
|
+
autoload :Render, "pancake/mixins/render"
|
29
|
+
autoload :StackHelper, "pancake/mixins/stack_helper"
|
30
|
+
end
|
31
|
+
|
32
|
+
module Middlewares
|
33
|
+
autoload :Static, "pancake/middlewares/static"
|
34
|
+
autoload :Logger, "pancake/middlewares/logger"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'pancake/paths'
|
39
|
+
require 'pancake/hooks/on_inherit'
|
40
|
+
require 'pancake/hooks/inheritable_inner_classes'
|
41
|
+
require 'pancake/core_ext/class'
|
42
|
+
require 'pancake/core_ext/object'
|
43
|
+
require 'pancake/core_ext/symbol'
|
44
|
+
require 'pancake/configuration'
|
45
|
+
require 'pancake/bootloaders'
|
46
|
+
require 'pancake/mime_types'
|
47
|
+
require 'pancake/middleware'
|
48
|
+
require 'pancake/router'
|
49
|
+
require 'pancake/master'
|
50
|
+
require 'pancake/errors'
|
51
|
+
require 'pancake/stack/stack'
|
52
|
+
require 'pancake/stack/configuration'
|
53
|
+
require 'pancake/stack/router'
|
54
|
+
require 'pancake/stack/bootloader'
|
55
|
+
require 'pancake/stack/app'
|
56
|
+
require 'pancake/mixins/request_helper'
|
57
|
+
require 'pancake/defaults/middlewares'
|
58
|
+
require 'pancake/defaults/configuration'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Pancake
|
2
|
+
module Spec
|
3
|
+
module Helpers
|
4
|
+
def clear_constants(*classes)
|
5
|
+
classes.flatten.each do |klass|
|
6
|
+
begin
|
7
|
+
Object.class_eval do
|
8
|
+
remove_const klass
|
9
|
+
end
|
10
|
+
rescue => e
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end # clear_constnat3
|
14
|
+
|
15
|
+
def env_for(path = "/", opts = {})
|
16
|
+
Rack::MockRequest.env_for(path, opts)
|
17
|
+
end
|
18
|
+
end # Helpers
|
19
|
+
end # Spec
|
20
|
+
end # Pancake
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pancake
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class InheritFrom
|
5
|
+
def initialize(expected)
|
6
|
+
@expected = expected
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(target)
|
10
|
+
@target = target
|
11
|
+
@target.ancestors.include?(@expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message
|
15
|
+
"expected #{@target} to inherit from #{@expected} but did not"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def inherit_from(expected)
|
20
|
+
InheritFrom.new(expected)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
end # Matchers
|
25
|
+
end # Pancake
|