hassox-pancake 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. data/LICENSE +20 -0
  2. data/README.textile +95 -0
  3. data/Rakefile +56 -0
  4. data/TODO +18 -0
  5. data/bin/jeweler +19 -0
  6. data/bin/pancake-gen +17 -0
  7. data/bin/rubyforge +19 -0
  8. data/lib/pancake.rb +48 -0
  9. data/lib/pancake/bootloaders.rb +180 -0
  10. data/lib/pancake/configuration.rb +140 -0
  11. data/lib/pancake/core_ext/class.rb +44 -0
  12. data/lib/pancake/core_ext/object.rb +22 -0
  13. data/lib/pancake/core_ext/symbol.rb +15 -0
  14. data/lib/pancake/errors.rb +61 -0
  15. data/lib/pancake/generators.rb +8 -0
  16. data/lib/pancake/generators/base.rb +12 -0
  17. data/lib/pancake/generators/flat_generator.rb +17 -0
  18. data/lib/pancake/generators/short_generator.rb +17 -0
  19. data/lib/pancake/generators/stack_generator.rb +17 -0
  20. data/lib/pancake/generators/templates/common/dotgitignore +22 -0
  21. data/lib/pancake/generators/templates/common/dothtaccess +17 -0
  22. data/lib/pancake/generators/templates/flat/%stack_name%/%stack_name%.rb.tt +8 -0
  23. data/lib/pancake/generators/templates/flat/%stack_name%/.gitignore +21 -0
  24. data/lib/pancake/generators/templates/flat/%stack_name%/config.ru.tt +12 -0
  25. data/lib/pancake/generators/templates/flat/%stack_name%/pancake.init.tt +1 -0
  26. data/lib/pancake/generators/templates/flat/%stack_name%/public/.empty_directory +0 -0
  27. data/lib/pancake/generators/templates/flat/%stack_name%/tmp/.empty_directory +0 -0
  28. data/lib/pancake/generators/templates/short/%stack_name%/.gitignore +21 -0
  29. data/lib/pancake/generators/templates/short/%stack_name%/LICENSE.tt +20 -0
  30. data/lib/pancake/generators/templates/short/%stack_name%/README.tt +7 -0
  31. data/lib/pancake/generators/templates/short/%stack_name%/Rakefile.tt +48 -0
  32. data/lib/pancake/generators/templates/short/%stack_name%/VERSION.tt +1 -0
  33. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%.rb.tt +5 -0
  34. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/%stack_name%.rb.tt +6 -0
  35. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config.ru.tt +12 -0
  36. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/gems/cache/.empty_directory +0 -0
  37. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
  38. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
  39. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
  40. data/lib/pancake/generators/templates/short/%stack_name%/pancake.init.tt +1 -0
  41. data/lib/pancake/generators/templates/short/%stack_name%/spec/%stack_name%_spec.rb.tt +7 -0
  42. data/lib/pancake/generators/templates/short/%stack_name%/spec/spec_helper.rb.tt +9 -0
  43. data/lib/pancake/generators/templates/stack/%stack_name%/.gitignore +21 -0
  44. data/lib/pancake/generators/templates/stack/%stack_name%/LICENSE.tt +20 -0
  45. data/lib/pancake/generators/templates/stack/%stack_name%/README.tt +7 -0
  46. data/lib/pancake/generators/templates/stack/%stack_name%/Rakefile.tt +48 -0
  47. data/lib/pancake/generators/templates/stack/%stack_name%/VERSION.tt +1 -0
  48. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%.rb.tt +3 -0
  49. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config.ru.tt +12 -0
  50. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/environments/development.rb.tt +18 -0
  51. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/environments/production.rb.tt +18 -0
  52. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/config/router.rb.tt +6 -0
  53. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/gems/cache/.empty_directory +0 -0
  54. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
  55. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
  56. data/lib/pancake/generators/templates/stack/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
  57. data/lib/pancake/generators/templates/stack/%stack_name%/pancake.init.tt +1 -0
  58. data/lib/pancake/generators/templates/stack/%stack_name%/spec/%stack_name%_spec.rb.tt +7 -0
  59. data/lib/pancake/generators/templates/stack/%stack_name%/spec/spec_helper.rb.tt +9 -0
  60. data/lib/pancake/hooks/inheritable_inner_classes.rb +60 -0
  61. data/lib/pancake/hooks/on_inherit.rb +34 -0
  62. data/lib/pancake/master.rb +87 -0
  63. data/lib/pancake/middleware.rb +354 -0
  64. data/lib/pancake/mime_types.rb +265 -0
  65. data/lib/pancake/mixins/publish.rb +125 -0
  66. data/lib/pancake/mixins/publish/action_options.rb +104 -0
  67. data/lib/pancake/mixins/render.rb +61 -0
  68. data/lib/pancake/mixins/request_helper.rb +92 -0
  69. data/lib/pancake/mixins/stack_helper.rb +44 -0
  70. data/lib/pancake/mixins/url.rb +10 -0
  71. data/lib/pancake/more/controller.rb +4 -0
  72. data/lib/pancake/more/controller/base.rb +34 -0
  73. data/lib/pancake/paths.rb +218 -0
  74. data/lib/pancake/router.rb +99 -0
  75. data/lib/pancake/stack/app.rb +10 -0
  76. data/lib/pancake/stack/bootloader.rb +79 -0
  77. data/lib/pancake/stack/configuration.rb +44 -0
  78. data/lib/pancake/stack/middleware.rb +0 -0
  79. data/lib/pancake/stack/router.rb +18 -0
  80. data/lib/pancake/stack/stack.rb +57 -0
  81. data/lib/pancake/stacks/short.rb +2 -0
  82. data/lib/pancake/stacks/short/controller.rb +105 -0
  83. data/lib/pancake/stacks/short/stack.rb +194 -0
  84. data/spec/helpers/helpers.rb +20 -0
  85. data/spec/helpers/matchers.rb +25 -0
  86. data/spec/pancake/bootloaders_spec.rb +109 -0
  87. data/spec/pancake/configuration_spec.rb +177 -0
  88. data/spec/pancake/fixtures/foo_stack/pancake.init +0 -0
  89. data/spec/pancake/fixtures/paths/controllers/controller1.rb +0 -0
  90. data/spec/pancake/fixtures/paths/controllers/controller2.rb +0 -0
  91. data/spec/pancake/fixtures/paths/controllers/controller3.rb +0 -0
  92. data/spec/pancake/fixtures/paths/models/model1.rb +0 -0
  93. data/spec/pancake/fixtures/paths/models/model2.rb +0 -0
  94. data/spec/pancake/fixtures/paths/models/model3.rb +0 -0
  95. data/spec/pancake/fixtures/paths/stack/controllers/controller1.rb +0 -0
  96. data/spec/pancake/fixtures/paths/stack/models/model3.rb +0 -0
  97. data/spec/pancake/fixtures/paths/stack/views/view1.erb +0 -0
  98. data/spec/pancake/fixtures/paths/stack/views/view1.rb +0 -0
  99. data/spec/pancake/fixtures/paths/stack/views/view2.erb +0 -0
  100. data/spec/pancake/fixtures/paths/stack/views/view2.haml +0 -0
  101. data/spec/pancake/fixtures/render_templates/context_template.html.erb +1 -0
  102. data/spec/pancake/fixtures/render_templates/erb_template.html.erb +1 -0
  103. data/spec/pancake/fixtures/render_templates/erb_template.json.erb +1 -0
  104. data/spec/pancake/fixtures/render_templates/haml_template.html.haml +1 -0
  105. data/spec/pancake/fixtures/render_templates/haml_template.xml.haml +1 -0
  106. data/spec/pancake/hooks/on_inherit_spec.rb +65 -0
  107. data/spec/pancake/inheritance_spec.rb +100 -0
  108. data/spec/pancake/middleware_spec.rb +401 -0
  109. data/spec/pancake/mime_types_spec.rb +234 -0
  110. data/spec/pancake/mixins/publish_spec.rb +94 -0
  111. data/spec/pancake/mixins/render_spec.rb +55 -0
  112. data/spec/pancake/mixins/stack_helper_spec.rb +46 -0
  113. data/spec/pancake/pancake_spec.rb +31 -0
  114. data/spec/pancake/paths_spec.rb +210 -0
  115. data/spec/pancake/stack/app_spec.rb +28 -0
  116. data/spec/pancake/stack/bootloader_spec.rb +41 -0
  117. data/spec/pancake/stack/middleware_spec.rb +0 -0
  118. data/spec/pancake/stack/router_spec.rb +266 -0
  119. data/spec/pancake/stack/stack_configuration_spec.rb +101 -0
  120. data/spec/pancake/stack/stack_spec.rb +55 -0
  121. data/spec/pancake/stacks/short/controller_spec.rb +287 -0
  122. data/spec/pancake/stacks/short/router_spec.rb +132 -0
  123. data/spec/pancake/stacks/short/stack_spec.rb +40 -0
  124. data/spec/spec_helper.rb +21 -0
  125. metadata +238 -0
File without changes
@@ -0,0 +1,18 @@
1
+ module Pancake
2
+ class Stack
3
+ class_inheritable_accessor :_router
4
+ @_router = Pancake::Router.new
5
+
6
+ def self.router
7
+ yield _router if block_given?
8
+ _router
9
+ end
10
+
11
+ def self.with_router
12
+ yield router if block_given?
13
+ router
14
+ end
15
+
16
+ end
17
+ end
18
+
@@ -0,0 +1,57 @@
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
+ def self.initialized?
28
+ !!@initialized
29
+ end
30
+
31
+ def initialize(app = nil, opts = {})
32
+ @app_name = opts.delete(:app_name) || self.class
33
+ self.class.initialize_stack unless self.class.initialized?
34
+ Pancake.configuration.stacks[@app_name] = self
35
+
36
+ # setup the configuration for this stack
37
+ Pancake.configuration.configs[@app_name] = opts[:config] if opts [:config]
38
+ self.configuration(@app_name)
39
+ yield self.configuration(@app_name) if block_given?
40
+
41
+ self.class::BootLoader.run!({
42
+ :stack_class => self.class,
43
+ :stack => self,
44
+ :app => app,
45
+ :app_name => @app_name,
46
+ :except => {:level => :init}
47
+ }.merge(opts))
48
+ end
49
+
50
+ # Construct a stack using the application, wrapped in the middlewares
51
+ # :api: public
52
+ def self.stackup(opts = {}, &block)
53
+ app = new(nil, opts, &block)
54
+ Pancake.configuration.configs[app.app_name].router
55
+ end # stackup
56
+ end # Stack
57
+ end # Pancake
@@ -0,0 +1,2 @@
1
+ require 'pancake/stacks/short/stack'
2
+ require 'pancake/stacks/short/controller'
@@ -0,0 +1,105 @@
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
+ push_paths :views, ["app/views", "views"], "**/*"
15
+
16
+ DEFAULT_EXCEPTION_HANDLER = lambda do |error|
17
+ "#{error.name}: #{error.description}"
18
+ end unless defined?(DEFAULT_EXCEPTION_HANDLER)
19
+
20
+ # @api private
21
+ def self.call(env)
22
+ app = new(env)
23
+ app.dispatch!
24
+ end
25
+
26
+ # @api public
27
+ attr_accessor :status
28
+
29
+ def initialize(env)
30
+ @env, @request = env, Rack::Request.new(env)
31
+ @status = 200
32
+ end
33
+
34
+ # Provides access to the request params
35
+ # @api public
36
+ def params
37
+ request.params
38
+ end
39
+
40
+ # Dispatches to an action based on the params["action"] parameter
41
+ def dispatch!
42
+ params["action"] ||= params[:action]
43
+ params[:format] ||= params["format"]
44
+
45
+ # Check that the action is available
46
+ raise Errors::NotFound, "No Action Found" unless allowed_action?(params["action"])
47
+
48
+ @action_opts = actions[params["action"]]
49
+ if params[:format]
50
+ @content_type, ct, @mime_type = Pancake::MimeTypes.negotiate_by_extension(params[:format].to_s, @action_opts.formats)
51
+ else
52
+ @content_type, ct, @mime_type = Pancake::MimeTypes.negotiate_accept_type(env["HTTP_ACCEPT"], @action_opts.formats)
53
+ end
54
+
55
+ raise Errors::NotAcceptable unless @content_type
56
+
57
+ # set the response header
58
+ headers["Content-Type"] = ct
59
+ Rack::Response.new(self.send(params["action"]), status, headers).finish
60
+
61
+ rescue Errors::HttpError => e
62
+ handle_request_exception(e)
63
+ rescue Exception => e
64
+ server_error = Errors::Server.new
65
+ server_error.exceptions << e
66
+ handle_request_exception(server_error)
67
+ end
68
+
69
+ def content_type
70
+ @content_type
71
+ end
72
+
73
+ def self.handle_exception(&block)
74
+ if block_given?
75
+ self._handle_exception = block
76
+ else
77
+ self._handle_exception || DEFAULT_EXCEPTION_HANDLER
78
+ end
79
+ end
80
+
81
+ def handle_request_exception(error)
82
+ self.status = error.code
83
+ result = instance_exec error, &self.class.handle_exception
84
+ Rack::Response.new(result, status, headers).finish
85
+ end
86
+
87
+ private
88
+ def allowed_action?(action)
89
+ self.class.actions.include?(action.to_s)
90
+ end
91
+
92
+ public
93
+ def self.roots
94
+ stack_class.roots
95
+ end
96
+
97
+ def _tempate_name_for(name, opts)
98
+ opts[:format] ||= content_type
99
+ "#{name}.#{opts[:format]}"
100
+ end
101
+ end # Controller
102
+
103
+ end # Short
104
+ end # Stacks
105
+ end # Pancake
@@ -0,0 +1,194 @@
1
+ module Pancake
2
+ module Stacks
3
+ class Short < Pancake::Stack
4
+
5
+ def self.new_app_instance
6
+ self::Controller
7
+ end
8
+
9
+ # Marks a method as published.
10
+ # This is done implicitly when using the get, post, put, delete methods on a Stacks::Short
11
+ # But can be done explicitly
12
+ #
13
+ # @see Pancake::Mixins::Publish#publish
14
+ # @api public
15
+ def self.publish(*args)
16
+ @published = true
17
+ self::Controller.publish(*args)
18
+ end
19
+
20
+ # @see Pancake::Mixins::Publish#as
21
+ def self.as(*args)
22
+ self::Controller.as(*args)
23
+ end
24
+
25
+ # @see Pancake::Mixins::Publish#provides
26
+ def self.provides(*formats)
27
+ self::Controller.provides(*formats)
28
+ end
29
+
30
+ def self.handle_exception(*args, &block)
31
+ self::Controller.handle_exception(*args, &block)
32
+ end
33
+
34
+ # Gets a resource at a given path
35
+ #
36
+ # The block should finish with the final result of the action
37
+ #
38
+ # @param [String] path - a url path that conforms to Rack::Router match path.
39
+ # @param block - the contents of the block are executed when the path is matched.
40
+ #
41
+ # @example
42
+ # get "/posts(/:year(/:month(/:date))" do
43
+ # # do stuff to get posts and render them
44
+ # end
45
+ #
46
+ # @see Rack::Router
47
+ # @api public
48
+ # @author Daniel Neighman
49
+ def self.get(path, opts = {}, &block)
50
+ define_published_action(:get, path, opts, block)
51
+ end
52
+
53
+ # Posts a resource to a given path
54
+ #
55
+ # The block should finish with the final result of the action
56
+ #
57
+ # @param [String] path - a url path that conforms to Rack::Router match path.
58
+ # @param block - the contents of the block are executed when the path is matched.
59
+ #
60
+ # @example
61
+ # post "/posts" do
62
+ # # do stuff to post /posts and render them
63
+ # end
64
+ #
65
+ # @see Rack::Router
66
+ # @api public
67
+ # @author Daniel Neighman
68
+ def self.post(path, opts = {}, &block)
69
+ define_published_action(:post, path, opts, block)
70
+ end
71
+
72
+ # Puts a resource to a given path
73
+ #
74
+ # The block should finish with the final result of the action
75
+ #
76
+ # @param [String] path - a url path that conforms to Rack::Router match path.
77
+ # @param block - the contents of the block are executed when the path is matched.
78
+ #
79
+ # @example
80
+ # put "/posts" do
81
+ # # do stuff to post /posts and render them
82
+ # end
83
+ #
84
+ # @see Rack::Router
85
+ # @api public
86
+ # @author Daniel Neighman
87
+ def self.put(path, opts = {}, &block)
88
+ define_published_action(:put, path, opts, block)
89
+ end
90
+
91
+ # Deletes the resource at a given path
92
+ #
93
+ # The block should finish with the final result of the action
94
+ #
95
+ # @param [String] path - a url path that conforms to Rack::Router match path.
96
+ # @param block - the contents of the block are executed when the path is matched.
97
+ #
98
+ # @example
99
+ # delete "/posts/foo-is-post" do
100
+ # # do stuff to post foo-is-post and render the result
101
+ # end
102
+ #
103
+ # @see Rack::Router
104
+ # @api public
105
+ # @author Daniel Neighman
106
+ def self.delete(path, opts = {}, &block)
107
+ define_published_action(:delete, path, opts, block)
108
+ end
109
+
110
+ private
111
+ # Defines an action on the inner Controller class of this stack.
112
+ # Also sets it as published if it's not already published.
113
+ #
114
+ # @param [Symbol] method - a smbol specifying the HTTP method
115
+ # @param [String] path - a string specifying the path to map the url to
116
+ # @api private
117
+ # @author Daniel Neighman
118
+ def self.define_published_action(method, path, opts, block)
119
+ self::Controller.publish unless @published
120
+ @published = nil
121
+
122
+ action_name = next_action_name(method,path)
123
+ attach_action(action_name, block)
124
+
125
+ attach_route(method, path, action_name, opts)
126
+ end
127
+
128
+ # Does the work of actually defining the action on the Controller Class
129
+ #
130
+ # @param [String] - the name of the method to create on the Controller class
131
+ # @api private
132
+ # @author Daniel Neighman
133
+ def self.attach_action(method_name, block)
134
+ self::Controller.class_eval do
135
+ define_method(method_name, &block)
136
+ end
137
+ end
138
+
139
+ # Supplies the path as a route to the stack router
140
+ #
141
+ # @param method [Symbol]
142
+ #
143
+ # @example
144
+ # attach_route(:get, "/foo/bar", "get_00001__foo_bar")
145
+ #
146
+ # @api private
147
+ # @author Daniel Neighman
148
+ def self.attach_route(method, path, action_name, options)
149
+ name = options.delete(:_name)
150
+ options[:conditions] ||= {}
151
+ options[:conditions][:request_method] = method.to_s.upcase
152
+ options[:default_values] ||= {}
153
+ options[:default_values][:action] = action_name
154
+ options[:_exact] = true unless options[:_exact] == false
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>_<number>_<sanitized_path>
162
+ # where <number> is incremented
163
+ #
164
+ # @param [Symbol] method - the HTTP method to look for
165
+ # @param [String] path - the url path expression to encode into the method name
166
+ #
167
+ # @return [String] - The next method name to use that won't clash with previously configured actions
168
+ #
169
+ # @api private
170
+ # @author Daniel Neighman
171
+ def self.next_action_name(method, path)
172
+ last = self::Controller.public_instance_methods.grep(%r[#{method}_\d+]).sort.reverse.first
173
+ next_method = 0
174
+ unless last.nil?
175
+ last =~ %r[#{method}_(\d+)]
176
+ next_method = $1
177
+ end
178
+ sprintf("#{method}_%04d_#{sanitize_path(path)}", next_method)
179
+ end
180
+
181
+ # sanitizes a path so it's able to be used as a method name
182
+ #
183
+ # @param [String] path - the path to sanitize
184
+ #
185
+ # @return [String] the sanitized version of the path safe to use as a method name
186
+ # @api private
187
+ # @author Daniel Neighman
188
+ def self.sanitize_path(path)
189
+ path.gsub(/\W/, "_")
190
+ end
191
+
192
+ end # Short
193
+ end # Stacks
194
+ end # Pancake
@@ -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
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Pancake::Stack::BootLoader" do
4
+
5
+ before(:each) do
6
+ $captures = []
7
+
8
+ class ::FooStack < Pancake::Stack
9
+ roots << File.join(Pancake.get_root(__FILE__), "..", "fixtures", "foo_stack")
10
+ end
11
+ end
12
+
13
+ after(:each) do
14
+ clear_constants(:FooStack)
15
+ end
16
+
17
+ it "should not add the bootloader without it having a run! method" do
18
+ lambda do
19
+ FooStack::BootLoader.add(:foo){|s,c| :here }
20
+ end.should raise_error
21
+ end
22
+
23
+ it "should allow me to add an application specific BootLoader" do
24
+ FooStack::BootLoader.add(:my_initializer){ def run!; :foo; end}
25
+ FooStack::BootLoader[:my_initializer].call({}).should == :foo
26
+ end
27
+
28
+ it "should provide a bootloader instance" do
29
+ FooStack::BootLoader.add(:my_initializer){ def run!; :foo; end}
30
+ FooStack::BootLoader[:my_initializer].should inherit_from(Pancake::BootLoaderMixin::Base)
31
+ end
32
+
33
+ it "should allow me to add multiple boot loaders" do
34
+ FooStack::BootLoader.add(:foo){ def run!; :foo; end}
35
+ FooStack::BootLoader.add(:bar){ def run!; :bar; end}
36
+ FooStack::BootLoader[:foo].call({}).should == :foo
37
+ FooStack::BootLoader[:bar].call({}).should == :bar
38
+ end
39
+
40
+ it "should allow me to add a bootloader before another" do
41
+ $captures.should be_empty
42
+ FooStack::BootLoader.add(:foo){ def run!; $captures << :foo; end}
43
+ FooStack::BootLoader.add(:bar){ def run!; $captures << :bar; end}
44
+ FooStack::BootLoader.add(:baz, :before => :bar){ def run!; $captures << :baz; end}
45
+ FooStack.new
46
+ $captures.should == [:foo, :baz, :bar]
47
+ end
48
+
49
+ it "should allow me to add a bootloader after another" do
50
+ $captures.should be_empty
51
+ FooStack::BootLoader.add(:foo){ def run!; $captures << :foo; end}
52
+ FooStack::BootLoader.add(:bar){ def run!; $captures << :bar; end}
53
+ FooStack::BootLoader.add(:baz, :after => :foo){ def run!; $captures << :baz; end}
54
+ FooStack.new
55
+ $captures.should == [:foo, :baz, :bar]
56
+ end
57
+
58
+ it "should provide an arbitrarily complex setup" do
59
+ $captures.should be_empty
60
+ FooStack::BootLoader.add(:foo ){ def run!; $captures << :foo; end}
61
+ FooStack::BootLoader.add(:bar ){ def run!; $captures << :bar; end}
62
+ FooStack::BootLoader.add(:baz, :after => :foo ){ def run!; $captures << :baz; end}
63
+ FooStack::BootLoader.add(:paz, :before => :baz ){ def run!; $captures << :paz; end}
64
+ FooStack::BootLoader.add(:fred, :before => :bar ){ def run!; $captures << :fred; end}
65
+ FooStack::BootLoader.add(:barney, :after => :fred ){ def run!; $captures << :barney; end}
66
+
67
+ FooStack.new
68
+ $captures.should == [:foo, :paz, :baz, :fred, :barney, :bar]
69
+ end
70
+
71
+ describe "types" do
72
+
73
+ it "should run bootloaders marked as :init" do
74
+ FooStack::BootLoader.add(:bar, :level => :init ){ def run!; $captures << [:bar, :init ]; end}
75
+ FooStack::BootLoader.add(:baz, :level => :init ){ def run!; $captures << [:baz, :init ]; end}
76
+ FooStack::BootLoader.add(:paz, :level => :init, :before => :baz){ def run!; $captures << [:paz, :init]; end}
77
+
78
+ FooStack::BootLoader.run!(:only => {:level => :init})
79
+ $captures.should == [[:bar, :init], [:paz, :init], [:baz, :init]]
80
+ end
81
+
82
+ it "should run init or then default level bootloaders individually" do
83
+ FooStack::BootLoader.add(:foo ){ def run!; $captures << [:foo, :default]; end}
84
+ FooStack::BootLoader.add(:grh ){ def run!; $captures << [:grh, :default]; end}
85
+ FooStack::BootLoader.add(:bar, :level => :init ){ def run!; $captures << [:bar, :init ]; end}
86
+ FooStack::BootLoader.add(:ptf, :before => :grh ){ def run!; $captures << [:ptf, :default]; end}
87
+ FooStack::BootLoader.add(:baz, :level => :init ){ def run!; $captures << [:baz, :init ]; end}
88
+ FooStack::BootLoader.add(:paz, :level => :init, :before => :baz){ def run!; $captures << [:paz, :init]; end}
89
+
90
+ FooStack.new
91
+ $captures.should == [[:bar, :init], [:paz, :init], [:baz, :init], [:foo, :default], [:ptf, :default], [:grh, :default]]
92
+ end
93
+
94
+ it "should inherit from the default boot loaders" do
95
+ ::Pancake::Stack::BootLoader.add(:default_boot_loader_test){def run!; end}
96
+ class ::Bario < Pancake::Stack; end
97
+ Bario::BootLoader.map{|n,bl| n}.should include(:default_boot_loader_test)
98
+ end
99
+
100
+ it "should let me pass options to the bootloaders and pass them on" do
101
+ FooStack::BootLoader.add(:foo){ def run!; config[:result] << :foo; end}
102
+ FooStack::BootLoader.add(:bar){ def run!; config[:result] << :bar; end}
103
+
104
+ opts = { :result => [] }
105
+ FooStack.new(nil, opts)
106
+ opts[:result].should == [:foo, :bar]
107
+ end
108
+ end
109
+ end