roda 0.9.0

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 (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +709 -0
  5. data/Rakefile +124 -0
  6. data/lib/roda.rb +608 -0
  7. data/lib/roda/plugins/all_verbs.rb +48 -0
  8. data/lib/roda/plugins/default_headers.rb +50 -0
  9. data/lib/roda/plugins/error_handler.rb +69 -0
  10. data/lib/roda/plugins/flash.rb +62 -0
  11. data/lib/roda/plugins/h.rb +24 -0
  12. data/lib/roda/plugins/halt.rb +79 -0
  13. data/lib/roda/plugins/header_matchers.rb +57 -0
  14. data/lib/roda/plugins/hooks.rb +106 -0
  15. data/lib/roda/plugins/indifferent_params.rb +47 -0
  16. data/lib/roda/plugins/middleware.rb +88 -0
  17. data/lib/roda/plugins/multi_route.rb +77 -0
  18. data/lib/roda/plugins/not_found.rb +62 -0
  19. data/lib/roda/plugins/pass.rb +34 -0
  20. data/lib/roda/plugins/render.rb +217 -0
  21. data/lib/roda/plugins/streaming.rb +165 -0
  22. data/spec/composition_spec.rb +19 -0
  23. data/spec/env_spec.rb +11 -0
  24. data/spec/integration_spec.rb +63 -0
  25. data/spec/matchers_spec.rb +658 -0
  26. data/spec/module_spec.rb +29 -0
  27. data/spec/opts_spec.rb +42 -0
  28. data/spec/plugin/all_verbs_spec.rb +29 -0
  29. data/spec/plugin/default_headers_spec.rb +63 -0
  30. data/spec/plugin/error_handler_spec.rb +67 -0
  31. data/spec/plugin/flash_spec.rb +59 -0
  32. data/spec/plugin/h_spec.rb +13 -0
  33. data/spec/plugin/halt_spec.rb +62 -0
  34. data/spec/plugin/header_matchers_spec.rb +61 -0
  35. data/spec/plugin/hooks_spec.rb +97 -0
  36. data/spec/plugin/indifferent_params_spec.rb +13 -0
  37. data/spec/plugin/middleware_spec.rb +52 -0
  38. data/spec/plugin/multi_route_spec.rb +98 -0
  39. data/spec/plugin/not_found_spec.rb +99 -0
  40. data/spec/plugin/pass_spec.rb +23 -0
  41. data/spec/plugin/render_spec.rb +148 -0
  42. data/spec/plugin/streaming_spec.rb +52 -0
  43. data/spec/plugin_spec.rb +61 -0
  44. data/spec/redirect_spec.rb +24 -0
  45. data/spec/request_spec.rb +55 -0
  46. data/spec/response_spec.rb +131 -0
  47. data/spec/session_spec.rb +35 -0
  48. data/spec/spec_helper.rb +89 -0
  49. data/spec/version_spec.rb +8 -0
  50. metadata +148 -0
@@ -0,0 +1,13 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "indifferent_params plugin" do
4
+ it "allows indifferent access to request params via params method" do
5
+ app(:indifferent_params) do |r|
6
+ r.on do
7
+ "#{params[:a]}/#{params[:b][0][:c]}"
8
+ end
9
+ end
10
+
11
+ body('QUERY_STRING'=>'a=2&b[][c]=3', 'rack.input'=>StringIO.new).should == '2/3'
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "middleware plugin" do
4
+ it "turns Roda app into middlware" do
5
+ a2 = app(:bare) do
6
+ plugin :middleware
7
+
8
+ route do |r|
9
+ r.is "a" do
10
+ "a2"
11
+ end
12
+ r.post "b" do
13
+ "b2"
14
+ end
15
+ end
16
+ end
17
+
18
+ a3 = app(:bare) do
19
+ plugin :middleware
20
+
21
+ route do |r|
22
+ r.get "a" do
23
+ "a3"
24
+ end
25
+ r.get "b" do
26
+ "b3"
27
+ end
28
+ end
29
+ end
30
+
31
+ app(:bare) do
32
+ use a3
33
+ use a2
34
+
35
+ route do |r|
36
+ r.is "a" do
37
+ "a1"
38
+ end
39
+ r.is "b" do
40
+ "b1"
41
+ end
42
+ end
43
+ end
44
+
45
+ body('/a').should == 'a3'
46
+ body('/b').should == 'b3'
47
+ body('/a', 'REQUEST_METHOD'=>'POST').should == 'a2'
48
+ body('/b', 'REQUEST_METHOD'=>'POST').should == 'b2'
49
+ body('/a', 'REQUEST_METHOD'=>'PATCH').should == 'a2'
50
+ body('/b', 'REQUEST_METHOD'=>'PATCH').should == 'b1'
51
+ end
52
+ end
@@ -0,0 +1,98 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "multi_route plugin" do
4
+ before do
5
+ app(:bare) do
6
+ plugin :multi_route
7
+
8
+ route(:get) do |r|
9
+ r.is "" do
10
+ "get"
11
+ end
12
+
13
+ r.is "a" do
14
+ "geta"
15
+ end
16
+ end
17
+
18
+ route(:post) do |r|
19
+ r.is "" do
20
+ "post"
21
+ end
22
+
23
+ r.is "a" do
24
+ "posta"
25
+ end
26
+ end
27
+
28
+ route do |r|
29
+ r.get do
30
+ route(:get)
31
+
32
+ r.is "b" do
33
+ "getb"
34
+ end
35
+ end
36
+ r.post do
37
+ route(:post)
38
+
39
+ r.is "b" do
40
+ "postb"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ it "adds named routing support" do
48
+ body.should == 'get'
49
+ body('REQUEST_METHOD'=>'POST').should == 'post'
50
+ body('/a').should == 'geta'
51
+ body('/a', 'REQUEST_METHOD'=>'POST').should == 'posta'
52
+ body('/b').should == 'getb'
53
+ body('/b', 'REQUEST_METHOD'=>'POST').should == 'postb'
54
+ status('/c').should == 404
55
+ status('/c', 'REQUEST_METHOD'=>'POST').should == 404
56
+ end
57
+
58
+ it "handles loading the plugin multiple times correctly" do
59
+ app.plugin :multi_route
60
+ body.should == 'get'
61
+ body('REQUEST_METHOD'=>'POST').should == 'post'
62
+ body('/a').should == 'geta'
63
+ body('/a', 'REQUEST_METHOD'=>'POST').should == 'posta'
64
+ body('/b').should == 'getb'
65
+ body('/b', 'REQUEST_METHOD'=>'POST').should == 'postb'
66
+ status('/c').should == 404
67
+ status('/c', 'REQUEST_METHOD'=>'POST').should == 404
68
+ end
69
+
70
+ it "handles subclassing correctly" do
71
+ @app = Class.new(@app)
72
+ @app.route do |r|
73
+ r.get do
74
+ route(:post)
75
+
76
+ r.is "b" do
77
+ "1b"
78
+ end
79
+ end
80
+ r.post do
81
+ route(:get)
82
+
83
+ r.is "b" do
84
+ "2b"
85
+ end
86
+ end
87
+ end
88
+
89
+ body.should == 'post'
90
+ body('REQUEST_METHOD'=>'POST').should == 'get'
91
+ body('/a').should == 'posta'
92
+ body('/a', 'REQUEST_METHOD'=>'POST').should == 'geta'
93
+ body('/b').should == '1b'
94
+ body('/b', 'REQUEST_METHOD'=>'POST').should == '2b'
95
+ status('/c').should == 404
96
+ status('/c', 'REQUEST_METHOD'=>'POST').should == 404
97
+ end
98
+ end
@@ -0,0 +1,99 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "not_found plugin" do
4
+ it "executes on no arguments" do
5
+ app(:bare) do
6
+ plugin :not_found
7
+
8
+ not_found do
9
+ "not found"
10
+ end
11
+
12
+ route do |r|
13
+ r.on "a" do
14
+ "found"
15
+ end
16
+ end
17
+ end
18
+
19
+ body.should == 'not found'
20
+ status.should == 404
21
+ body("/a").should == 'found'
22
+ status("/a").should == 200
23
+ end
24
+
25
+ it "allows overriding status inside not_found" do
26
+ app(:bare) do
27
+ plugin :not_found
28
+
29
+ not_found do
30
+ response.status = 403
31
+ "not found"
32
+ end
33
+
34
+ route do |r|
35
+ end
36
+ end
37
+
38
+ status.should == 403
39
+ end
40
+
41
+ it "does not modify behavior if not_found is not called" do
42
+ app(:not_found) do |r|
43
+ r.on "a" do
44
+ "found"
45
+ end
46
+ end
47
+
48
+ body.should == ''
49
+ body("/a").should == 'found'
50
+ end
51
+
52
+ it "can set not_found via the plugin block" do
53
+ app(:bare) do
54
+ plugin :not_found do
55
+ "not found"
56
+ end
57
+
58
+ route do |r|
59
+ r.on "a" do
60
+ "found"
61
+ end
62
+ end
63
+ end
64
+
65
+ body.should == 'not found'
66
+ body("/a").should == 'found'
67
+ end
68
+
69
+ it "does not modify behavior if body is not an array" do
70
+ app(:bare) do
71
+ plugin :not_found do
72
+ "not found"
73
+ end
74
+
75
+ o = Object.new
76
+ def o.join() '' end
77
+ route do |r|
78
+ r.halt [404, {}, o]
79
+ end
80
+ end
81
+
82
+ body.should == ''
83
+ end
84
+
85
+ it "does not modify behavior if body is not an empty array" do
86
+ app(:bare) do
87
+ plugin :not_found do
88
+ "not found"
89
+ end
90
+
91
+ route do |r|
92
+ response.status = 404
93
+ response.write 'a'
94
+ end
95
+ end
96
+
97
+ body.should == 'a'
98
+ end
99
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "pass plugin" do
4
+ it "executes on no arguments" do
5
+ app(:pass) do |r|
6
+ r.on :id do |id|
7
+ r.pass if id == 'foo'
8
+ id
9
+ end
10
+
11
+ r.on ":x/:y" do |x, y|
12
+ x + y
13
+ end
14
+ end
15
+
16
+ body("/a").should == 'a'
17
+ body("/a/b").should == 'a'
18
+ body("/foo/a").should == 'fooa'
19
+ body("/foo/a/b").should == 'fooa'
20
+ status("/foo").should == 404
21
+ status.should == 404
22
+ end
23
+ end
@@ -0,0 +1,148 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ begin
4
+ require 'tilt'
5
+ rescue LoadError
6
+ warn "tilt not installed, skipping render plugin test"
7
+ else
8
+ describe "render plugin" do
9
+ before do
10
+ app(:bare) do
11
+ plugin :render
12
+ render_opts[:views] = "./spec/views"
13
+
14
+ route do |r|
15
+ r.on "home" do
16
+ view("home", :locals=>{:name => "Agent Smith", :title => "Home"}, :layout_opts=>{:locals=>{:title=>"Home"}})
17
+ end
18
+
19
+ r.on "about" do
20
+ render("about", :locals=>{:title => "About Roda"})
21
+ end
22
+
23
+ r.on "inline" do
24
+ view(:inline=>"Hello <%= name %>", :locals=>{:name => "Agent Smith"}, :layout=>nil)
25
+ end
26
+
27
+ r.on "path" do
28
+ render(:path=>"./spec/views/about.erb", :locals=>{:title => "Path"}, :layout_opts=>{:locals=>{:title=>"Home"}})
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ it "default actions" do
35
+ body("/about").strip.should == "<h1>About Roda</h1>"
36
+ body("/home").strip.should == "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
37
+ body("/inline").strip.should == "Hello Agent Smith"
38
+ body("/path").strip.should == "<h1>Path</h1>"
39
+ end
40
+
41
+ it "with str as engine" do
42
+ app.render_opts[:engine] = "str"
43
+ body("/about").strip.should == "<h1>About Roda</h1>"
44
+ body("/home").strip.should == "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
45
+ body("/inline").strip.should == "Hello <%= name %>"
46
+ end
47
+
48
+ it "with str as ext" do
49
+ app.render_opts[:ext] = "str"
50
+ body("/about").strip.should == "<h1>About Roda</h1>"
51
+ body("/home").strip.should == "<title>Roda: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
52
+ body("/inline").strip.should == "Hello Agent Smith"
53
+ end
54
+
55
+ it "custom default layout support" do
56
+ app.render_opts[:layout] = "layout-alternative"
57
+ body("/home").strip.should == "<title>Alternative Layout: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
58
+ end
59
+ end
60
+
61
+ describe "render plugin" do
62
+ it "simple layout support" do
63
+ app(:bare) do
64
+ plugin :render
65
+
66
+ route do |r|
67
+ render(:path=>"spec/views/layout-yield.erb") do
68
+ render(:path=>"spec/views/content-yield.erb")
69
+ end
70
+ end
71
+ end
72
+
73
+ body.gsub(/\n+/, "\n").should == "Header\nThis is the actual content.\nFooter\n"
74
+ end
75
+
76
+ it "views without default layouts" do
77
+ app(:bare) do
78
+ plugin :render, :views=>"./spec/views", :layout=>false
79
+
80
+ route do |r|
81
+ view("home", :locals=>{:name=>"Agent Smith", :title=>"Home"})
82
+ end
83
+ end
84
+
85
+ body.strip.should == "<h1>Home</h1>\n<p>Hello Agent Smith</p>"
86
+ end
87
+
88
+ it "layout overrides" do
89
+ app(:bare) do
90
+ plugin :render, :views=>"./spec/views"
91
+
92
+ route do |r|
93
+ view("home", :locals=>{:name=>"Agent Smith", :title=>"Home" }, :layout=>"layout-alternative", :layout_opts=>{:locals=>{:title=>"Home"}})
94
+ end
95
+ end
96
+
97
+ body.strip.should == "<title>Alternative Layout: Home</title>\n<h1>Home</h1>\n<p>Hello Agent Smith</p>"
98
+ end
99
+
100
+ it "inline layouts and inline views" do
101
+ app(:render) do
102
+ view({:inline=>'bar'}, :layout=>{:inline=>'Foo: <%= yield %>'})
103
+ end
104
+
105
+ body.strip.should == "Foo: bar"
106
+ end
107
+
108
+ it "inline renders with opts" do
109
+ app(:render) do
110
+ render({:inline=>'<%= bar %>'}, {:engine=>'str'})
111
+ end
112
+
113
+ body.strip.should == '<%= bar %>'
114
+ end
115
+
116
+ it "render_opts inheritance" do
117
+ c = Class.new(Roda)
118
+ c.plugin :render
119
+ sc = Class.new(c)
120
+
121
+ c.render_opts.should_not equal(sc.render_opts)
122
+ c.render_opts[:layout_opts].should_not equal(sc.render_opts[:layout_opts])
123
+ c.render_opts[:opts].should_not equal(sc.render_opts[:opts])
124
+ c.render_opts[:cache].should_not equal(sc.render_opts[:cache])
125
+ end
126
+
127
+ it "render plugin call should not override options" do
128
+ c = Class.new(Roda)
129
+ c.plugin :render, :layout=>:foo
130
+ c.plugin :render
131
+ c.render_opts[:layout].should == :foo
132
+ end
133
+
134
+ it "with caching disabled" do
135
+ app(:bare) do
136
+ plugin :render, :views=>"./spec/views", :cache=>false
137
+
138
+ route do |r|
139
+ view(:inline=>"Hello <%= name %>: <%= render_opts[:cache] %>", :locals=>{:name => "Agent Smith"}, :layout=>nil)
140
+ end
141
+ end
142
+
143
+ body("/inline").strip.should == "Hello Agent Smith: false"
144
+
145
+ Class.new(app).render_opts[:cache].should == false
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "streaming plugin" do
4
+ it "adds stream method for streaming responses" do
5
+ app(:streaming) do |r|
6
+ stream do |out|
7
+ %w'a b c'.each{|v| out << v}
8
+ end
9
+ end
10
+
11
+ s, h, b = req
12
+ s.should == 200
13
+ h.should == {'Content-Type'=>'text/html'}
14
+ b.to_a.should == %w'a b c'
15
+ end
16
+
17
+ it "should handle errors when streaming, and run callbacks" do
18
+ a = []
19
+ app(:streaming) do |r|
20
+ stream(:callback=>proc{a << 'e'}) do |out|
21
+ %w'a b'.each{|v| out << v}
22
+ raise Roda::RodaError, 'foo'
23
+ out << 'c'
24
+ end
25
+ end
26
+
27
+ s, h, b = req
28
+ s.should == 200
29
+ h.should == {'Content-Type'=>'text/html'}
30
+ b.callback{a << 'd'}
31
+ proc{b.each{|v| a << v}}.should raise_error(Roda::RodaError)
32
+ a.should == %w'a b e d'
33
+ end
34
+
35
+ it "should handle :loop option to loop" do
36
+ a = []
37
+ app(:streaming) do |r|
38
+ b = %w'a b c'
39
+ stream(:loop=>true, :callback=>proc{a << 'e'}) do |out|
40
+ out << b.shift
41
+ raise Roda::RodaError, 'foo' if b.length == 1
42
+ end
43
+ end
44
+
45
+ s, h, b = req
46
+ s.should == 200
47
+ h.should == {'Content-Type'=>'text/html'}
48
+ b.callback{a << 'd'}
49
+ proc{b.each{|v| a << v}}.should raise_error(Roda::RodaError)
50
+ a.should == %w'a b e d'
51
+ end
52
+ end