short_stack 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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