short_stack 0.1.1

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 (62) hide show
  1. data/.document +5 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +13 -0
  4. data/Gemfile.lock +71 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +17 -0
  7. data/Rakefile +26 -0
  8. data/VERSION +1 -0
  9. data/lib/pancake/generators/global.rb +2 -0
  10. data/lib/pancake/generators/micro_generator.rb +23 -0
  11. data/lib/pancake/generators/short_generator.rb +23 -0
  12. data/lib/pancake/generators/templates/common/Gemfile +7 -0
  13. data/lib/pancake/generators/templates/common/dotgitignore +22 -0
  14. data/lib/pancake/generators/templates/common/dothtaccess +17 -0
  15. data/lib/pancake/generators/templates/micro/%stack_name%/%stack_name%.rb.tt +9 -0
  16. data/lib/pancake/generators/templates/micro/%stack_name%/Rakefile.tt +40 -0
  17. data/lib/pancake/generators/templates/micro/%stack_name%/config.ru.tt +15 -0
  18. data/lib/pancake/generators/templates/micro/%stack_name%/pancake_init.rb.tt +1 -0
  19. data/lib/pancake/generators/templates/micro/%stack_name%/public/.empty_directory +0 -0
  20. data/lib/pancake/generators/templates/micro/%stack_name%/tmp/.empty_directory +0 -0
  21. data/lib/pancake/generators/templates/micro/%stack_name%/views/layouts/application.html.haml +5 -0
  22. data/lib/pancake/generators/templates/micro/%stack_name%/views/root.html.haml +1 -0
  23. data/lib/pancake/generators/templates/short/%stack_name%/LICENSE.tt +20 -0
  24. data/lib/pancake/generators/templates/short/%stack_name%/README.tt +7 -0
  25. data/lib/pancake/generators/templates/short/%stack_name%/Rakefile.tt +56 -0
  26. data/lib/pancake/generators/templates/short/%stack_name%/VERSION.tt +1 -0
  27. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%.rb.tt +14 -0
  28. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/%stack_name%.rb.tt +6 -0
  29. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config.ru.tt +11 -0
  30. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/config.rb.tt +23 -0
  31. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/development.rb.tt +15 -0
  32. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/production.rb.tt +16 -0
  33. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/config/environments/staging.rb.tt +15 -0
  34. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/models/.empty_directory +0 -0
  35. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/mounts/.empty_directory +0 -0
  36. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/public/.empty_directory +0 -0
  37. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tasks/%stack_name%.rake.tt +4 -0
  38. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/tmp/.empty_directory +0 -0
  39. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/views/layouts/application.html.haml +5 -0
  40. data/lib/pancake/generators/templates/short/%stack_name%/lib/%stack_name%/views/root.html.haml +2 -0
  41. data/lib/pancake/generators/templates/short/%stack_name%/pancake_init.rb.tt +1 -0
  42. data/lib/pancake/generators/templates/short/%stack_name%/spec/%stack_name%_spec.rb.tt +11 -0
  43. data/lib/pancake/generators/templates/short/%stack_name%/spec/spec_helper.rb.tt +13 -0
  44. data/lib/short_stack.rb +213 -0
  45. data/lib/short_stack/controller.rb +185 -0
  46. data/lib/short_stack/default/views/base.html.haml +5 -0
  47. data/lib/short_stack/default/views/error.html.haml +12 -0
  48. data/lib/short_stack/middleware.rb +14 -0
  49. data/short_stack.gemspec +38 -0
  50. data/spec/fixtures/foobar/other_root/views/base.html.haml +4 -0
  51. data/spec/fixtures/foobar/views/basic.html.haml +1 -0
  52. data/spec/fixtures/foobar/views/inherited_from_base.html.haml +5 -0
  53. data/spec/fixtures/foobar/views/template.html.haml +3 -0
  54. data/spec/fixtures/foobar/views/vault.html.haml +3 -0
  55. data/spec/short_stack/controller_spec.rb +444 -0
  56. data/spec/short_stack/middlewares_spec.rb +14 -0
  57. data/spec/short_stack/router_spec.rb +153 -0
  58. data/spec/short_stack/short_stack_spec.rb +122 -0
  59. data/spec/short_stack/stack_spec.rb +124 -0
  60. data/spec/spec.opts +1 -0
  61. data/spec/spec_helper.rb +13 -0
  62. metadata +181 -0
@@ -0,0 +1,5 @@
1
+ !!! 5
2
+ %html
3
+ %body
4
+ -content_block :content do
5
+ %h1 Welcome to Pancake!
@@ -0,0 +1,12 @@
1
+ - content_block :error do
2
+ .error
3
+ %h1
4
+ Error:
5
+ = error.class
6
+ .description
7
+ = error.respond_to?(:description) ? error.description : error.message
8
+
9
+ %ul.backtrace
10
+ - error.backtrace.each do |line|
11
+ %li= line
12
+
@@ -0,0 +1,14 @@
1
+ require 'rack-rescue'
2
+ require 'wrapt'
3
+
4
+ Pancake.before_build do
5
+ unless Pancake::StackMiddleware[:rescue] || Pancake::StackMiddleware[Rack::Rescue]
6
+ Pancake.stack(:rescue).use(Rack::Rescue)
7
+ end
8
+
9
+ unless Pancake::StackMiddleware[:layout] || Pancake::StackMiddleware[Wrapt]
10
+ Pancake.stack(:layout).use(Wrapt) do |wrapt|
11
+ wrapt.defer!
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'bundler'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{short_stack}
6
+ s.version = File.read("VERSION")
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.authors = ["Daniel Neighman"]
10
+ s.date = %q{2010-06-15}
11
+ s.description = %q{A short sinatra like pancake stack}
12
+ s.email = %q{has.sox@gmail.com}
13
+ s.extra_rdoc_files = [
14
+ "LICENSE",
15
+ "README.rdoc"
16
+ ]
17
+ s.files = Dir["**/{*,.[a-z]*}"]
18
+ s.add_bundler_dependencies
19
+ s.homepage = %q{http://github.com/hassox/short_stack}
20
+ s.rdoc_options = ["--charset=UTF-8"]
21
+ s.require_paths = ["lib"]
22
+ s.rubygems_version = %q{1.3.7}
23
+ s.summary = %q{A short sinatra like pancake stack}
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 3
28
+
29
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
30
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
31
+ else
32
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
33
+ end
34
+ else
35
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
36
+ end
37
+ end
38
+
@@ -0,0 +1,4 @@
1
+ %h1 Not the default pancake
2
+
3
+ - content_block :content do
4
+ %p not pancake!
@@ -0,0 +1 @@
1
+ %p basic template
@@ -0,0 +1,5 @@
1
+ - inherits_from :base
2
+
3
+ - content_block :content do
4
+ %p inherited from base
5
+ = content_block.super
@@ -0,0 +1,3 @@
1
+ .content
2
+ In Template
3
+ = url(:foobar)
@@ -0,0 +1,3 @@
1
+ .content
2
+ In Vault
3
+ = v[:my_data]
@@ -0,0 +1,444 @@
1
+ require 'spec_helper'
2
+
3
+ describe ShortStack::Controller do
4
+
5
+ before do
6
+ Pancake.stack(:logger).delete!
7
+ class ::ShortFoo < ShortStack
8
+ include_pancake_stack!
9
+ add_root(__FILE__)
10
+ add_root(File.expand_path(File.dirname(__FILE__)), "fixtures","foobar")
11
+ class Controller
12
+
13
+ def do_dispatch!
14
+ dispatch!
15
+ end
16
+
17
+ publish
18
+ def show; "show"; end
19
+
20
+ publish
21
+ def index; "index"; end
22
+
23
+ publish
24
+ def a_rack_response
25
+ r = Rack::Response.new
26
+ r.redirect("/foo")
27
+ r
28
+ end
29
+
30
+ publish
31
+ def an_array_response
32
+ [200, {"Content-Type" => "text/plain"}, ["Custom Array Response"]]
33
+ end
34
+
35
+ protected
36
+ def a_protected_method; "protected"; end
37
+
38
+ private
39
+ def a_private_method; "private"; end
40
+ end
41
+ end
42
+ end
43
+
44
+ after do
45
+ clear_constants "ShortFoo", :ShortBar
46
+ end
47
+
48
+ def app
49
+ ShortFoo.stackup
50
+ end
51
+
52
+ it "should have a Controller" do
53
+ ShortStack.constants.map(&:to_s).should include("Controller")
54
+ end
55
+
56
+ it "should inherit the subclass controller from the parent controller" do
57
+ ShortFoo::Controller.should inherit_from(ShortStack::Controller)
58
+ end
59
+
60
+ describe "dispatching an action" do
61
+ before do
62
+ @controller = ShortFoo::Controller.new(env_for)
63
+ end
64
+
65
+ it "should call the 'show' action" do
66
+ @controller.action = "show"
67
+ result = @controller.do_dispatch!
68
+ result[0].should == 200
69
+ result[2].body.join.should == "show"
70
+ end
71
+
72
+ it "should raise a Pancake::Errors::NotFound exception when an action is now found" do
73
+ @controller.action = :does_not_exist
74
+ lambda do
75
+ @controller.do_dispatch!
76
+ end.should raise_error(Pancake::Errors::NotFound)
77
+ end
78
+
79
+ it "should not dispatch to a protected method" do
80
+ @controller.action = "a_protected_method"
81
+ lambda do
82
+ @controller.do_dispatch!
83
+ end.should raise_error(Pancake::Errors::NotFound)
84
+ end
85
+
86
+ it "should not dispatch to a private method" do
87
+ @controller.action = "a_private_method"
88
+ lambda do
89
+ @controller.do_dispatch!
90
+ end.should raise_error(Pancake::Errors::NotFound)
91
+ end
92
+
93
+ it "should let me return an array as a rack response" do
94
+ @controller.action = "an_array_response"
95
+ result = @controller.do_dispatch!
96
+ result.should == [200, {"Content-Type" => "text/plain"}, ["Custom Array Response"]]
97
+ end
98
+
99
+ it "should allow me to return a Rack::Response" do
100
+ @controller.action = "a_rack_response"
101
+ result = @controller.do_dispatch!
102
+ result[0].should == 302
103
+ result[1]["Location"].should == "/foo"
104
+ end
105
+
106
+ describe "helper in methods" do
107
+ before do
108
+ module PancakeTestHelper
109
+ def some_helper_method
110
+ "foo"
111
+ end
112
+ end
113
+
114
+ class ShortFoo
115
+ class Controller
116
+ include PancakeTestHelper
117
+ end
118
+ end
119
+ end
120
+ after do
121
+ clear_constants "PancakeTestHelper"
122
+ end
123
+
124
+ it "should not call a helper method" do
125
+ @controller.params["action"] = "some_helper_method"
126
+ lambda do
127
+ @controller.do_dispatch!
128
+ end.should raise_error(Pancake::Errors::NotFound)
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "request helper methods" do
134
+ before do
135
+ class ::RequestFoo < ShortStack
136
+ add_root(__FILE__, "..", "fixtures", "foobar")
137
+ get "/foobar", :name => :foobar do
138
+ url(:foobar)
139
+ end
140
+
141
+ get "/template", :name => :template do
142
+ render :template
143
+ end
144
+
145
+ get "/vault" do
146
+ v[:my_data] = "some data"
147
+ render :vault
148
+ end
149
+
150
+ get "/redirect" do
151
+ redirect "/some_other_place"
152
+ end
153
+ end
154
+ end
155
+
156
+ after do
157
+ clear_constants :RequestFoo
158
+ end
159
+
160
+ def app
161
+ RequestFoo.stackup
162
+ end
163
+
164
+ it "should include the request helper methods" do
165
+ (Pancake::Mixins::RequestHelper > ShortFoo::Controller).should be_true
166
+ end
167
+
168
+ it "should provide access to the request methods in the controller" do
169
+ result = get "/foobar"
170
+ result.body.should == "/foobar"
171
+ end
172
+
173
+ it "should provide access to the helper methods in the views" do
174
+ result = get "/template"
175
+ result.status.should == 200
176
+ result.body.should include("/foobar")
177
+ result.body.should include("In Template")
178
+ end
179
+
180
+ it "should allow me to get information between the view and the controller" do
181
+ result = get "/vault"
182
+ result.status.should == 200
183
+ result.body.should include("some data")
184
+ result.body.should include("In Vault")
185
+ end
186
+
187
+ it "should redirect" do
188
+ result = get "/redirect"
189
+ result.status.should == 302
190
+ result.headers["Location"].should == "/some_other_place"
191
+ end
192
+ end
193
+
194
+ describe "accept type negotiations" do
195
+ before do
196
+ class ::ShortBar < ShortStack
197
+ include_pancake_stack!
198
+ roots << Pancake.get_root(__FILE__)
199
+ # makes the dispatch method public
200
+ def do_dispatch!
201
+ dispatch!
202
+ end
203
+
204
+ provides :json, :xml, :text
205
+
206
+ get "/foo/bar(.:format)" do
207
+ "format #{content_type.inspect}"
208
+ end
209
+ end # ShortBar
210
+ end # before
211
+
212
+ def app
213
+ ShortBar.stackup
214
+ end
215
+
216
+ it "should get json by default" do
217
+ result = get "/foo/bar", {}, "HTTP_ACCEPT" => "application/json"
218
+ result.status.should == 200
219
+ result.headers["Content-Type"].should == "application/json"
220
+ result.body.to_s.should == "format :json"
221
+ end
222
+
223
+ it "should get xml when specified" do
224
+ result = get "/foo/bar.xml"
225
+ result.status.should == 200
226
+ result.headers["Content-Type"].should == "application/xml"
227
+ result.body.to_s.should == "format :xml"
228
+ end
229
+
230
+ it "should get json when specified with */*" do
231
+ result = get "/foo/bar", {}, "HTTP_ACCEPT" => "*/*"
232
+ result.status.should == 200
233
+ result.body.to_s.should == "format :json"
234
+ result.headers["Content-Type"].should == "application/json"
235
+ end
236
+
237
+ it "should get the default when specified with */*" do
238
+ result = get "/foo/bar", {}, "HTTP_ACCEPT" => "application/xml,*/*"
239
+ result.status.should == 200
240
+ result.body.to_s.should == "format :json"
241
+ result.headers["Content-Type"].should == "application/json"
242
+ end
243
+
244
+ it "should use the format in preference to the content type" do
245
+ result = get "/foo/bar.xml", {}, "HTTP_ACCEPT" => "*/*"
246
+ result.status.should == 200
247
+ result.body.to_s.should == "format :xml"
248
+ result.headers["Content-Type"].should == "application/xml"
249
+ end
250
+
251
+ it "should get json by default" do
252
+ result = get "/foo/bar"
253
+ result.status.should == 200
254
+ result.body.to_s.should == "format :json"
255
+ result.headers["Content-Type"].should == "application/json"
256
+ end
257
+
258
+ it "should correctly negotiate different scenarios" do
259
+ r = get "/foo/bar", {}, {}
260
+ r.body.should == "format :json"
261
+ r = get "/foo/bar.xml", {}, {}
262
+ r.body.should == "format :xml"
263
+ r = get "/foo/bar", {}, {}
264
+ r.body.should == "format :json"
265
+ r = get "/foo/bar", {}, "HTTP_ACCEPT" => "application/xml"
266
+ r.body.should == "format :xml"
267
+ r = get "/foo/bar.json"
268
+ r.body.should == "format :json"
269
+ end
270
+
271
+ it "should negotiate based on extension" do
272
+ r = get "/foo/bar"
273
+ r.body.should == "format :json"
274
+ r = get "/foo/bar.text"
275
+ r.body.should == "format :text"
276
+ r = get "/foo/bar.xml"
277
+ r.body.should == "format :xml"
278
+ r = get "/foo/bar.txt"
279
+ r.body.should == "format :text"
280
+ end
281
+
282
+ it "should not provide a response to a format that is not provided" do
283
+ r = get "/foo/bar.svg"
284
+ r.status.should == 406
285
+ end
286
+ end # Accept type negotiations
287
+
288
+ describe "error handling" do
289
+ before do
290
+ class ::ShortFoo
291
+ provides :html, :xml
292
+
293
+ get "/foo(.:format)" do
294
+ "HERE"
295
+ end
296
+
297
+ get "/bad" do
298
+ raise "This is bad"
299
+ end
300
+
301
+ get "/template/:name" do
302
+ render params[:name]
303
+ end
304
+
305
+ end
306
+ end
307
+
308
+ def app
309
+ ShortFoo.stackup
310
+ end
311
+
312
+ describe "default error handling" do
313
+ def app
314
+ ShortFoo.stackup
315
+ end
316
+
317
+ it "should handle a NotFound by default" do
318
+ result = get "/does_not_exist"
319
+ result.status.should == 404
320
+ end
321
+
322
+ it "should return a 500 status for a Random Error by wrapping it in a Pancake::Errors::Server" do
323
+ result = get "/bad"
324
+ result.status.should == 500
325
+ end
326
+
327
+ it "should handle a NotAcceptable error" do
328
+ result = get "/foo.no_format_i_know_of"
329
+ result.status.should == 406
330
+ end
331
+
332
+ it "should return 406 for a format that is in pancake but not in the group" do
333
+ r = get "/foo.svg"
334
+ r.status.should == 406
335
+ end
336
+ end
337
+
338
+ describe "custom error handling" do
339
+ before do
340
+ ShortFoo.handle_exception do |error|
341
+ out = ""
342
+ out << "CUSTOM "
343
+ out << error.name
344
+ out << ": "
345
+ out << error.description
346
+ end
347
+
348
+ Pancake.handle_errors!(true)
349
+
350
+ ShortFoo.get "/bad" do
351
+ raise "Really Bad"
352
+ end
353
+ end
354
+
355
+ after do
356
+ ShortFoo.handle_exception(&ShortStack::Controller::DEFAULT_EXCEPTION_HANDLER)
357
+ Pancake.handle_errors!(false)
358
+ end
359
+
360
+ it "should handle Pancake::Errors::NotFound errors" do
361
+ r = get "/not_a_thing"
362
+ r.status.should == 404
363
+ r.body.should include("CUSTOM")
364
+ r.body.should include(Pancake::Errors::NotFound.description)
365
+ end
366
+
367
+ it "should handle an unknown server error" do
368
+ r = get "/bad"
369
+ r.status.should == 500
370
+ r.body.should include("CUSTOM")
371
+ r.body.should include(Pancake::Errors::Server.description)
372
+ end
373
+
374
+ it "should let me do stuff on an instance level inside the handle exception" do
375
+ ShortFoo.handle_exception do |error|
376
+ self.status = 123
377
+ "BOOO!"
378
+ end
379
+
380
+ r = get "/bad"
381
+ r.status.should == 123
382
+ r.body.should == "BOOO!"
383
+ end
384
+
385
+ end
386
+
387
+ describe "rendering" do
388
+
389
+ it "should render a template" do
390
+ result = get "/template/basic"
391
+ result.body.should include("basic template")
392
+ end
393
+
394
+ it "should inherit from a base view provided by short stacks" do
395
+ File.file?(File.join(File.expand_path(File.dirname(__FILE__)), "..", "fixtures", "stacks", "short", "foobar", "views", "base.html.haml")).should be_false
396
+ result = get "/template/inherited_from_base"
397
+ result.body.should include("inherited from base")
398
+ result.body.should include("Pancake")
399
+ end
400
+
401
+ it "should allow me to overwrite the base tempalte in later roots" do
402
+ ShortFoo.add_root(File.expand_path(File.dirname(__FILE__)), "fixtures","foobar", "other_root")
403
+ result = get "/template/inherited_from_base"
404
+ result.body.should include("inherited from base")
405
+ result.body.should include("Not the default pancake")
406
+ end
407
+ end
408
+
409
+ describe "throwing" do
410
+ before do
411
+ ShortFoo.get("/plain_throw"){ throw :halt }
412
+ ShortFoo.get("/string_throw"){ throw :halt, "output string" }
413
+ ShortFoo.get("/status_n_throw"){ self.status = 204; throw :halt }
414
+ ShortFoo.get("/headers_n_throw") do
415
+ headers["some-header"] = Time.now.to_s
416
+ throw :halt
417
+ end
418
+ end
419
+
420
+ it "should handle a plain throw" do
421
+ result = get "/plain_throw"
422
+ result.should be_successful
423
+ result.body.should == ""
424
+ end
425
+
426
+ it "should handle a string throw" do
427
+ result = get "/string_throw"
428
+ result.should be_successful
429
+ result.body.should == "output string"
430
+ end
431
+
432
+ it "should handle a change in the status" do
433
+ result = get "/status_n_throw"
434
+ result.status.should == 204
435
+ result.body.should == ""
436
+ end
437
+
438
+ it "should handle a change in the headers" do
439
+ result = get "/headers_n_throw"
440
+ result.headers["some-header"].should_not be_blank
441
+ end
442
+ end
443
+ end
444
+ end