roda-cj 0.9.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +13 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +715 -0
  5. data/Rakefile +124 -0
  6. data/lib/roda/plugins/all_verbs.rb +48 -0
  7. data/lib/roda/plugins/default_headers.rb +50 -0
  8. data/lib/roda/plugins/error_handler.rb +69 -0
  9. data/lib/roda/plugins/flash.rb +108 -0
  10. data/lib/roda/plugins/h.rb +24 -0
  11. data/lib/roda/plugins/halt.rb +79 -0
  12. data/lib/roda/plugins/header_matchers.rb +57 -0
  13. data/lib/roda/plugins/hooks.rb +106 -0
  14. data/lib/roda/plugins/indifferent_params.rb +47 -0
  15. data/lib/roda/plugins/middleware.rb +88 -0
  16. data/lib/roda/plugins/multi_route.rb +77 -0
  17. data/lib/roda/plugins/not_found.rb +62 -0
  18. data/lib/roda/plugins/pass.rb +34 -0
  19. data/lib/roda/plugins/render.rb +217 -0
  20. data/lib/roda/plugins/streaming.rb +165 -0
  21. data/lib/roda/version.rb +3 -0
  22. data/lib/roda.rb +610 -0
  23. data/spec/composition_spec.rb +19 -0
  24. data/spec/env_spec.rb +11 -0
  25. data/spec/integration_spec.rb +63 -0
  26. data/spec/matchers_spec.rb +683 -0
  27. data/spec/module_spec.rb +29 -0
  28. data/spec/opts_spec.rb +42 -0
  29. data/spec/plugin/all_verbs_spec.rb +29 -0
  30. data/spec/plugin/default_headers_spec.rb +63 -0
  31. data/spec/plugin/error_handler_spec.rb +67 -0
  32. data/spec/plugin/flash_spec.rb +123 -0
  33. data/spec/plugin/h_spec.rb +13 -0
  34. data/spec/plugin/halt_spec.rb +62 -0
  35. data/spec/plugin/header_matchers_spec.rb +61 -0
  36. data/spec/plugin/hooks_spec.rb +97 -0
  37. data/spec/plugin/indifferent_params_spec.rb +13 -0
  38. data/spec/plugin/middleware_spec.rb +52 -0
  39. data/spec/plugin/multi_route_spec.rb +98 -0
  40. data/spec/plugin/not_found_spec.rb +99 -0
  41. data/spec/plugin/pass_spec.rb +23 -0
  42. data/spec/plugin/render_spec.rb +148 -0
  43. data/spec/plugin/streaming_spec.rb +52 -0
  44. data/spec/plugin_spec.rb +61 -0
  45. data/spec/redirect_spec.rb +24 -0
  46. data/spec/request_spec.rb +55 -0
  47. data/spec/response_spec.rb +131 -0
  48. data/spec/session_spec.rb +35 -0
  49. data/spec/spec_helper.rb +89 -0
  50. data/spec/version_spec.rb +8 -0
  51. metadata +136 -0
@@ -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
@@ -0,0 +1,61 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe "plugins" do
4
+ it "should be able to override class, instance, response, and request methods, and execute configure method" do
5
+ c = Module.new do
6
+ self::ClassMethods = Module.new do
7
+ def fix(str)
8
+ opts[:prefix] + str.strip
9
+ end
10
+ end
11
+ self::InstanceMethods = Module.new do
12
+ def fix(str)
13
+ super("a" + str)
14
+ end
15
+ end
16
+ self::RequestMethods = Module.new do
17
+ def hello(&block)
18
+ on 'hello', &block
19
+ end
20
+ end
21
+ self::ResponseMethods = Module.new do
22
+ def foobar
23
+ "Default "
24
+ end
25
+ end
26
+
27
+ def self.load_dependencies(mod, prefix)
28
+ mod.send(:include, Module.new do
29
+ def fix(str)
30
+ self.class.fix(str)
31
+ end
32
+ end)
33
+ end
34
+
35
+ def self.configure(mod, prefix)
36
+ mod.opts[:prefix] = prefix
37
+ end
38
+ end
39
+
40
+ app(:bare) do
41
+ plugin c, "Foo "
42
+
43
+ route do |r|
44
+ r.hello do
45
+ fix(response.foobar)
46
+ end
47
+ end
48
+ end
49
+
50
+ body('/hello').should == 'Foo aDefault'
51
+ end
52
+
53
+ it "should support registering plugins and loading them by symbol" do
54
+ Roda::RodaPlugins.register_plugin(:foo, Module.new{module self::InstanceMethods; def a; '1' end end})
55
+ app(:foo) do
56
+ a
57
+ end
58
+
59
+ body.should == '1'
60
+ end
61
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe "redirects" do
4
+ it "should be immediately processed" do
5
+ app do |r|
6
+ r.on "about" do
7
+ r.redirect "/hello", 301
8
+ "Foo"
9
+ end
10
+ r.on do
11
+ r.redirect "/hello"
12
+ "Foo"
13
+ end
14
+ end
15
+
16
+ status.should == 302
17
+ header('Location').should == '/hello'
18
+ body.should == ''
19
+
20
+ status("/about").should == 301
21
+ header('Location', "/about").should == '/hello'
22
+ body("/about").should == ''
23
+ end
24
+ end
@@ -0,0 +1,55 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe "request.full_path_info" do
4
+ it "should return the script name and path_info as a string" do
5
+ app do |r|
6
+ r.on "foo" do
7
+ "#{r.full_path_info}:#{r.script_name}:#{r.path_info}"
8
+ end
9
+ end
10
+
11
+ body("/foo/bar").should == "/foo/bar:/foo:/bar"
12
+ end
13
+ end
14
+
15
+ describe "request.halt" do
16
+ it "should return rack response as argument given it as argument" do
17
+ app do |r|
18
+ r.halt [200, {}, ['foo']]
19
+ end
20
+
21
+ body.should == "foo"
22
+ end
23
+ end
24
+
25
+ describe "request.scope" do
26
+ it "should return roda instance" do
27
+ app(:bare) do
28
+ attr_accessor :b
29
+
30
+ route do |r|
31
+ self.b = 'a'
32
+ request.scope.b
33
+ end
34
+ end
35
+
36
+ body.should == "a"
37
+ end
38
+ end
39
+
40
+ describe "request.inspect" do
41
+ it "should return information about request" do
42
+ app(:bare) do
43
+ def self.inspect
44
+ 'Foo'
45
+ end
46
+
47
+ route do |r|
48
+ request.inspect
49
+ end
50
+ end
51
+
52
+ body('/a/b').should == "#<Foo::RodaRequest GET /a/b>"
53
+ body('REQUEST_METHOD'=>'POST').should == "#<Foo::RodaRequest POST />"
54
+ end
55
+ end
@@ -0,0 +1,131 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe "cookie handling" do
4
+ it "should set cookies on response" do
5
+ app do |r|
6
+ response.set_cookie("foo", "bar")
7
+ response.set_cookie("bar", "baz")
8
+ "Hello"
9
+ end
10
+
11
+ header('Set-Cookie').should == "foo=bar\nbar=baz"
12
+ body.should == 'Hello'
13
+ end
14
+
15
+ it "should delete cookies on response" do
16
+ app do |r|
17
+ response.set_cookie("foo", "bar")
18
+ response.delete_cookie("foo")
19
+ "Hello"
20
+ end
21
+
22
+ header('Set-Cookie').should =~ /foo=; (max-age=0; )?expires=Thu, 01[ -]Jan[ -]1970 00:00:00 (-0000|GMT)/
23
+ body.should == 'Hello'
24
+ end
25
+ end
26
+
27
+ describe "response #[] and #[]=" do
28
+ it "should get/set headers" do
29
+ app do |r|
30
+ response['foo'] = 'bar'
31
+ response['foo'] + response.headers['foo']
32
+ end
33
+
34
+ header('foo').should == "bar"
35
+ body.should == 'barbar'
36
+ end
37
+ end
38
+
39
+ describe "response #write" do
40
+ it "should add to body" do
41
+ app do |r|
42
+ response.write 'a'
43
+ response.write 'b'
44
+ end
45
+
46
+ body.should == 'ab'
47
+ end
48
+ end
49
+
50
+ describe "response #finish" do
51
+ it "should set status to 404 if body has not been written to" do
52
+ app do |r|
53
+ s, h, b = response.finish
54
+ "#{s}#{h['Content-Type']}#{b.length}"
55
+ end
56
+
57
+ body.should == '404text/html0'
58
+ end
59
+
60
+ it "should set status to 200 if body has been written to" do
61
+ app do |r|
62
+ response.write 'a'
63
+ s, h, b = response.finish
64
+ response.write "#{s}#{h['Content-Type']}#{b.length}"
65
+ end
66
+
67
+ body.should == 'a200text/html1'
68
+ end
69
+
70
+ it "should not overwrite existing status" do
71
+ app do |r|
72
+ response.status = 500
73
+ s, h, b = response.finish
74
+ "#{s}#{h['Content-Type']}#{b.length}"
75
+ end
76
+
77
+ body.should == '500text/html0'
78
+ end
79
+ end
80
+
81
+ describe "response #redirect" do
82
+ it "should set location and status" do
83
+ app do |r|
84
+ r.on 'a' do
85
+ response.redirect '/foo', 303
86
+ end
87
+ r.on do
88
+ response.redirect '/bar'
89
+ end
90
+ end
91
+
92
+ status('/a').should == 303
93
+ status.should == 302
94
+ header('Location', '/a').should == '/foo'
95
+ header('Location').should == '/bar'
96
+ end
97
+ end
98
+
99
+ describe "response #empty?" do
100
+ it "should return whether the body is empty" do
101
+ app do |r|
102
+ r.on 'a' do
103
+ response['foo'] = response.empty?.to_s
104
+ end
105
+ r.on do
106
+ response.write 'a'
107
+ response['foo'] = response.empty?.to_s
108
+ end
109
+ end
110
+
111
+ header('foo', '/a').should == 'true'
112
+ header('foo').should == 'false'
113
+ end
114
+ end
115
+
116
+ describe "response #inspect" do
117
+ it "should return information about response" do
118
+ app(:bare) do
119
+ def self.inspect
120
+ 'Foo'
121
+ end
122
+
123
+ route do |r|
124
+ response.status = 200
125
+ response.inspect
126
+ end
127
+ end
128
+
129
+ body.should == '#<Foo::RodaResponse 200 {"Content-Type"=>"text/html"} []>'
130
+ end
131
+ end