webmachine 0.1.0 → 0.2.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.
- data/Gemfile +11 -3
- data/README.md +55 -27
- data/lib/webmachine/adapters/mongrel.rb +84 -0
- data/lib/webmachine/adapters/webrick.rb +12 -3
- data/lib/webmachine/adapters.rb +1 -7
- data/lib/webmachine/configuration.rb +30 -0
- data/lib/webmachine/decision/conneg.rb +7 -72
- data/lib/webmachine/decision/flow.rb +13 -11
- data/lib/webmachine/decision/fsm.rb +1 -9
- data/lib/webmachine/decision/helpers.rb +27 -7
- data/lib/webmachine/errors.rb +1 -0
- data/lib/webmachine/headers.rb +12 -3
- data/lib/webmachine/locale/en.yml +2 -2
- data/lib/webmachine/media_type.rb +117 -0
- data/lib/webmachine/resource/callbacks.rb +9 -0
- data/lib/webmachine/streaming.rb +3 -3
- data/lib/webmachine/version.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/pkg/webmachine-0.1.0/Gemfile +16 -0
- data/pkg/webmachine-0.1.0/Guardfile +11 -0
- data/pkg/webmachine-0.1.0/README.md +90 -0
- data/pkg/webmachine-0.1.0/Rakefile +31 -0
- data/pkg/webmachine-0.1.0/examples/webrick.rb +19 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/adapters/webrick.rb +74 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/adapters.rb +15 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/conneg.rb +304 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/flow.rb +502 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/fsm.rb +79 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision/helpers.rb +80 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/decision.rb +12 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/dispatcher/route.rb +85 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/dispatcher.rb +40 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/errors.rb +37 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/headers.rb +16 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/locale/en.yml +28 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/request.rb +56 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource/callbacks.rb +362 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource/encodings.rb +36 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/resource.rb +48 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/response.rb +49 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/streaming.rb +27 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/translation.rb +11 -0
- data/pkg/webmachine-0.1.0/lib/webmachine/version.rb +4 -0
- data/pkg/webmachine-0.1.0/lib/webmachine.rb +19 -0
- data/pkg/webmachine-0.1.0/spec/spec_helper.rb +13 -0
- data/pkg/webmachine-0.1.0/spec/tests.org +57 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/decision/conneg_spec.rb +152 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/decision/flow_spec.rb +1030 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/dispatcher/route_spec.rb +109 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/dispatcher_spec.rb +34 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/headers_spec.rb +19 -0
- data/pkg/webmachine-0.1.0/spec/webmachine/request_spec.rb +24 -0
- data/pkg/webmachine-0.1.0/webmachine.gemspec +44 -0
- data/pkg/webmachine-0.1.0.gem +0 -0
- data/spec/webmachine/configuration_spec.rb +27 -0
- data/spec/webmachine/decision/conneg_spec.rb +18 -11
- data/spec/webmachine/decision/flow_spec.rb +2 -0
- data/spec/webmachine/decision/helpers_spec.rb +105 -0
- data/spec/webmachine/errors_spec.rb +13 -0
- data/spec/webmachine/headers_spec.rb +2 -1
- data/spec/webmachine/media_type_spec.rb +78 -0
- data/webmachine.gemspec +4 -1
- metadata +69 -11
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Dispatcher::Route do
|
4
|
+
let(:request){ Webmachine::Request.new("GET", URI.parse("http://localhost:8098/"), Webmachine::Headers.new, "") }
|
5
|
+
let(:resource){ Class.new(Webmachine::Resource) }
|
6
|
+
|
7
|
+
matcher :match_route do |*expected|
|
8
|
+
route = described_class.new(expected[0], resource, expected[1] || {})
|
9
|
+
match do |actual|
|
10
|
+
request.uri.path = actual if String === actual
|
11
|
+
route.match?(request)
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message_for_should do |_|
|
15
|
+
"expected route #{expected[0].inspect} to match path #{request.uri.path}"
|
16
|
+
end
|
17
|
+
failure_message_for_should_not do |_|
|
18
|
+
"expected route #{expected[0].inspect} not to match path #{request.uri.path}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "matching a request" do
|
23
|
+
context "on the root path" do
|
24
|
+
subject { "/" }
|
25
|
+
it { should match_route([]) }
|
26
|
+
it { should match_route ['*'] }
|
27
|
+
it { should_not match_route %w{foo} }
|
28
|
+
it { should_not match_route [:id] }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "on a deep path" do
|
32
|
+
subject { "/foo/bar/baz" }
|
33
|
+
it { should match_route %w{foo bar baz} }
|
34
|
+
it { should match_route ['foo', :id, "baz"] }
|
35
|
+
it { should match_route %w{foo *} }
|
36
|
+
it { should match_route [:id, '*'] }
|
37
|
+
it { should_not match_route [] }
|
38
|
+
it { should_not match_route %w{bar *} }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "applying bindings" do
|
43
|
+
context "on the root path" do
|
44
|
+
subject { described_class.new([], resource) }
|
45
|
+
before { subject.apply(request) }
|
46
|
+
|
47
|
+
it "should assign the dispatched path to the empty string" do
|
48
|
+
request.disp_path.should == ""
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should assign empty bindings" do
|
52
|
+
request.path_info.should == {}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should assign empty path tokens" do
|
56
|
+
request.path_tokens.should == []
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with extra user-defined bindings" do
|
60
|
+
subject { described_class.new([], resource, "bar" => "baz") }
|
61
|
+
|
62
|
+
it "should assign the user-defined bindings" do
|
63
|
+
request.path_info.should == {"bar" => "baz"}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with a splat" do
|
68
|
+
subject { described_class.new(['*'], resource) }
|
69
|
+
|
70
|
+
it "should assign empty path tokens" do
|
71
|
+
request.path_tokens.should == []
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "on a deep path" do
|
77
|
+
subject { described_class.new(%w{foo bar baz}, resource) }
|
78
|
+
before { request.uri.path = "/foo/bar/baz"; subject.apply(request) }
|
79
|
+
|
80
|
+
it "should assign the dispatched path as the path past the initial slash" do
|
81
|
+
request.disp_path.should == "foo/bar/baz"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should assign empty bindings" do
|
85
|
+
request.path_info.should == {}
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should assign empty path tokens" do
|
89
|
+
request.path_tokens.should == []
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with path variables" do
|
93
|
+
subject { described_class.new(['foo', :id, 'baz'], resource) }
|
94
|
+
|
95
|
+
it "should assign the path variables in the bindings" do
|
96
|
+
request.path_info.should == {:id => "bar"}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "with a splat" do
|
101
|
+
subject { described_class.new(%w{foo *}, resource) }
|
102
|
+
|
103
|
+
it "should capture the path tokens matched by the splat" do
|
104
|
+
request.path_tokens.should == %w{ bar baz }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Dispatcher do
|
4
|
+
let(:dispatcher) { described_class }
|
5
|
+
let(:request) { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/"), Webmachine::Headers["accept" => "*/*"], "") }
|
6
|
+
let(:response) { Webmachine::Response.new }
|
7
|
+
let(:resource) do
|
8
|
+
Class.new(Webmachine::Resource) do
|
9
|
+
def to_html; "hello world!"; end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
let(:resource2) do
|
13
|
+
Class.new(Webmachine::Resource) do
|
14
|
+
def to_html; "goodbye, cruel world"; end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
let(:fsm){ mock }
|
18
|
+
|
19
|
+
before { dispatcher.reset }
|
20
|
+
|
21
|
+
it "should add routes" do
|
22
|
+
expect {
|
23
|
+
dispatcher.add_route ['*'], resource
|
24
|
+
}.should_not raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should route to the proper resource" do
|
28
|
+
dispatcher.add_route ["goodbye"], resource2
|
29
|
+
dispatcher.add_route ['*'], resource
|
30
|
+
Webmachine::Decision::FSM.should_receive(:new).with(instance_of(resource), request, response).and_return(fsm)
|
31
|
+
fsm.should_receive(:run)
|
32
|
+
dispatcher.dispatch(request, response)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Headers do
|
4
|
+
it "should set and access values insensitive to case" do
|
5
|
+
subject['Content-TYPE'] = "text/plain"
|
6
|
+
subject['CONTENT-TYPE'].should == 'text/plain'
|
7
|
+
end
|
8
|
+
|
9
|
+
context "filtering with #grep" do
|
10
|
+
subject { described_class["content-type" => "text/plain", "etag" => '"abcdef1234567890"'] }
|
11
|
+
it "should filter keys by the given pattern" do
|
12
|
+
subject.grep(/content/i).should include("content-type")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return a Headers instance" do
|
16
|
+
subject.grep(/etag/i).should be_instance_of(described_class)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Request do
|
4
|
+
subject { Webmachine::Request.new("GET", URI.parse("http://localhost:8080/some/resource"), Webmachine::Headers.new, "") }
|
5
|
+
it "should provide access to the headers via brackets" do
|
6
|
+
subject.headers['Accept'] = "*/*"
|
7
|
+
subject["accept"].should == "*/*"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should provide access to the headers via underscored methods" do
|
11
|
+
subject.headers["Accept-Encoding"] = "identity"
|
12
|
+
subject.accept_encoding.should == "identity"
|
13
|
+
subject.content_md5.should be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should calculate a base URI" do
|
17
|
+
subject.base_uri.should == URI.parse("http://localhost:8080/")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should provide a hash of query parameters" do
|
21
|
+
subject.uri.query = "foo=bar&baz=bam"
|
22
|
+
subject.query.should == {"foo" => "bar", "baz" => "bam"}
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'webmachine/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "webmachine"
|
6
|
+
gem.version = Webmachine::VERSION
|
7
|
+
gem.date = File.mtime("lib/webmachine/version.rb")
|
8
|
+
gem.summary = %Q{webmachine is a toolkit for building HTTP applications,}
|
9
|
+
gem.description = <<-DESC.gsub(/\s+/, ' ')
|
10
|
+
webmachine is a toolkit for building HTTP applications in a declarative fashion, that avoids
|
11
|
+
the confusion of going through a CGI-style interface like Rack. It is strongly influenced
|
12
|
+
by the original Erlang project of the same name and shares its opinionated nature about HTTP.
|
13
|
+
DESC
|
14
|
+
gem.homepage = "http://github.com/seancribbs/webmachine-ruby"
|
15
|
+
gem.authors = ["Sean Cribbs"]
|
16
|
+
gem.email = ["sean@basho.com"]
|
17
|
+
|
18
|
+
if gem.respond_to? :specification_version then
|
19
|
+
gem.specification_version = 3
|
20
|
+
|
21
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
22
|
+
gem.add_runtime_dependency(%q<i18n>, [">= 0.4.0"])
|
23
|
+
gem.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
24
|
+
gem.add_development_dependency(%q<yard>, ["~> 0.6.7"])
|
25
|
+
gem.add_development_dependency(%q<rake>)
|
26
|
+
else
|
27
|
+
gem.add_dependency(%q<i18n>, [">= 0.4.0"])
|
28
|
+
gem.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
29
|
+
gem.add_dependency(%q<yard>, ["~> 0.6.7"])
|
30
|
+
gem.add_dependency(%q<rake>)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
gem.add_dependency(%q<i18n>, [">= 0.4.0"])
|
34
|
+
gem.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
35
|
+
gem.add_dependency(%q<yard>, ["~> 0.6.7"])
|
36
|
+
gem.add_dependency(%q<rake>)
|
37
|
+
end
|
38
|
+
|
39
|
+
ignores = File.read(".gitignore").split(/\r?\n/).reject{ |f| f =~ /^(#.+|\s*)$/ }.map {|f| Dir[f] }.flatten
|
40
|
+
gem.files = (Dir['**/*','.gitignore'] - ignores).reject {|f| !File.file?(f) }
|
41
|
+
gem.test_files = (Dir['spec/**/*','features/**/*','.gitignore'] - ignores).reject {|f| !File.file?(f) }
|
42
|
+
gem.executables = Dir['bin/*'].map { |f| File.basename(f) }
|
43
|
+
gem.require_paths = ['lib']
|
44
|
+
end
|
Binary file
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Configuration do
|
4
|
+
before { Webmachine.configuration = nil }
|
5
|
+
|
6
|
+
%w{ip port adapter adapter_options}.each do |field|
|
7
|
+
it { should respond_to(field) }
|
8
|
+
it { should respond_to("#{field}=") }
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should yield configuration to the block" do
|
12
|
+
Webmachine.configure do |config|
|
13
|
+
config.should be_kind_of(described_class)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set the global configuration from the yielded instance" do
|
18
|
+
Webmachine.configure do |config|
|
19
|
+
@config = config
|
20
|
+
end
|
21
|
+
@config.should == Webmachine.configuration
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the module from the configure call so you can chain it" do
|
25
|
+
Webmachine.configure {|c|}.should == Webmachine
|
26
|
+
end
|
27
|
+
end
|
@@ -8,36 +8,43 @@ describe Webmachine::Decision::Conneg do
|
|
8
8
|
def to_html; "hello world!"; end
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
11
12
|
subject do
|
12
13
|
Webmachine::Decision::FSM.new(resource, request, response)
|
13
14
|
end
|
14
15
|
|
15
16
|
context "choosing a media type" do
|
16
17
|
it "should not choose a type when none are provided" do
|
17
|
-
subject.choose_media_type([], "*/*").should be_nil
|
18
|
+
subject.choose_media_type([], "*/*").should be_nil
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
it "should not choose a type when none are acceptable" do
|
21
22
|
subject.choose_media_type(["text/html"], "application/json").should be_nil
|
22
23
|
end
|
23
|
-
|
24
|
+
|
24
25
|
it "should choose the first acceptable type" do
|
25
26
|
subject.choose_media_type(["text/html", "application/xml"],
|
26
27
|
"application/xml, text/html, */*").should == "application/xml"
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
it "should choose the type that matches closest when matching subparams" do
|
30
31
|
subject.choose_media_type(["text/html",
|
31
32
|
["text/html", {"charset" => "iso8859-1"}]],
|
32
33
|
"text/html;charset=iso8859-1, application/xml").
|
33
34
|
should == "text/html;charset=iso8859-1"
|
34
|
-
|
35
35
|
end
|
36
36
|
|
37
|
+
it "should choose a type more specific than requested when an exact match is not present" do
|
38
|
+
subject.choose_media_type(["application/json;v=3;foo=bar", "application/json;v=2"],
|
39
|
+
"text/html, application/json").
|
40
|
+
should == "application/json;v=3;foo=bar"
|
41
|
+
end
|
42
|
+
|
43
|
+
|
37
44
|
it "should choose the preferred type over less-preferred types" do
|
38
45
|
subject.choose_media_type(["text/html", "application/xml"],
|
39
46
|
"application/xml;q=0.7, text/html, */*").should == "text/html"
|
40
|
-
|
47
|
+
|
41
48
|
end
|
42
49
|
|
43
50
|
it "should raise an exception when a media-type is improperly formatted" do
|
@@ -112,17 +119,17 @@ describe Webmachine::Decision::Conneg do
|
|
112
119
|
subject.choose_language([], "en")
|
113
120
|
subject.metadata['Language'].should be_nil
|
114
121
|
end
|
115
|
-
|
122
|
+
|
116
123
|
it "should choose the first acceptable language" do
|
117
124
|
subject.choose_language(['en', 'en-US', 'es'], "en-US, es")
|
118
125
|
subject.metadata['Language'].should == "en-US"
|
119
126
|
response.headers['Content-Language'].should == "en-US"
|
120
127
|
end
|
121
|
-
|
128
|
+
|
122
129
|
it "should choose the preferred language over less-preferred languages" do
|
123
130
|
subject.choose_language(['en', 'en-US', 'es'], "en-US;q=0.6, es")
|
124
131
|
subject.metadata['Language'].should == "es"
|
125
|
-
response.headers['Content-Language'].should == "es"
|
132
|
+
response.headers['Content-Language'].should == "es"
|
126
133
|
end
|
127
134
|
|
128
135
|
it "should select the first language if all are acceptable" do
|
@@ -130,13 +137,13 @@ describe Webmachine::Decision::Conneg do
|
|
130
137
|
subject.metadata['Language'].should == "en"
|
131
138
|
response.headers['Content-Language'].should == "en"
|
132
139
|
end
|
133
|
-
|
140
|
+
|
134
141
|
it "should select the closest acceptable language when an exact match is not available" do
|
135
142
|
subject.choose_language(['en-US', 'es'], "en, fr")
|
136
143
|
subject.metadata['Language'].should == 'en-US'
|
137
144
|
response.headers['Content-Language'].should == 'en-US'
|
138
145
|
end
|
139
|
-
|
146
|
+
|
140
147
|
it "should not set the language if none are acceptable" do
|
141
148
|
subject.choose_language(['en'], 'es')
|
142
149
|
subject.metadata['Language'].should be_nil
|
@@ -309,6 +309,7 @@ describe Webmachine::Decision::Flow do
|
|
309
309
|
subject.run
|
310
310
|
response.code.should_not == 406
|
311
311
|
response.headers['Content-Language'].should == "en-US"
|
312
|
+
resource.instance_variable_get(:@language).should == 'en-US'
|
312
313
|
end
|
313
314
|
end
|
314
315
|
|
@@ -318,6 +319,7 @@ describe Webmachine::Decision::Flow do
|
|
318
319
|
subject.should_not_receive(:d5)
|
319
320
|
subject.run
|
320
321
|
response.headers['Content-Language'].should == 'en-US'
|
322
|
+
resource.instance_variable_get(:@language).should == 'en-US'
|
321
323
|
end
|
322
324
|
end
|
323
325
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Decision::Helpers do
|
4
|
+
subject { Webmachine::Decision::FSM.new(resource, request, response) }
|
5
|
+
let(:method) { 'GET' }
|
6
|
+
let(:uri) { URI.parse('http://localhost/') }
|
7
|
+
let(:headers) { Webmachine::Headers.new }
|
8
|
+
let(:body) { '' }
|
9
|
+
let(:request) { Webmachine::Request.new(method, uri, headers, body) }
|
10
|
+
let(:response) { Webmachine::Response.new }
|
11
|
+
|
12
|
+
def resource_with(&block)
|
13
|
+
klass = Class.new(Webmachine::Resource) do
|
14
|
+
def to_html; "test resource"; end
|
15
|
+
end
|
16
|
+
klass.module_eval(&block) if block_given?
|
17
|
+
klass.new(request, response)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:resource) { resource_with }
|
21
|
+
|
22
|
+
describe "accepting request bodies" do
|
23
|
+
let(:resource) do
|
24
|
+
resource_with do
|
25
|
+
def initialize
|
26
|
+
@accepted, @result = [], true
|
27
|
+
end
|
28
|
+
attr_accessor :accepted, :result
|
29
|
+
def content_types_accepted
|
30
|
+
(accepted || []).map {|t| Array === t ? t : [t, :accept_doc] }
|
31
|
+
end
|
32
|
+
def accept_doc; result; end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return 415 when no types are accepted" do
|
37
|
+
subject.accept_helper.should == 415
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return 415 when the posted type is not acceptable" do
|
41
|
+
resource.accepted = %W{application/json}
|
42
|
+
headers['Content-Type'] = "text/xml"
|
43
|
+
subject.accept_helper.should == 415
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should call the method for the first acceptable type, taking into account params" do
|
47
|
+
resource.accepted = ["application/json;v=3", ["application/json", :other]]
|
48
|
+
resource.should_receive(:other).and_return(true)
|
49
|
+
headers['Content-Type'] = 'application/json;v=2'
|
50
|
+
subject.accept_helper.should be_true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#encode_body" do
|
55
|
+
before { subject.run }
|
56
|
+
|
57
|
+
context "with a String body" do
|
58
|
+
before { response.body = '<body></body>' }
|
59
|
+
|
60
|
+
it "does not modify the response body" do
|
61
|
+
subject.encode_body
|
62
|
+
String.should === response.body
|
63
|
+
end
|
64
|
+
|
65
|
+
it "sets the Content-Length header in the response" do
|
66
|
+
subject.encode_body
|
67
|
+
response.headers['Content-Length'].should == response.body.bytesize.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
shared_examples_for "a non-String body" do
|
72
|
+
it "does not set the Content-Length header in the response" do
|
73
|
+
subject.encode_body
|
74
|
+
response.headers.should_not have_key('Content-Length')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sets the Transfer-Encoding response header to chunked" do
|
78
|
+
subject.encode_body
|
79
|
+
response.headers['Transfer-Encoding'].should == 'chunked'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with an Enumerable body" do
|
84
|
+
before { response.body = ['one', 'two'] }
|
85
|
+
|
86
|
+
it "wraps the response body in an EnumerableEncoder" do
|
87
|
+
subject.encode_body
|
88
|
+
Webmachine::EnumerableEncoder.should === response.body
|
89
|
+
end
|
90
|
+
|
91
|
+
it_should_behave_like "a non-String body"
|
92
|
+
end
|
93
|
+
|
94
|
+
context "with a callable body" do
|
95
|
+
before { response.body = Proc.new { 'proc' } }
|
96
|
+
|
97
|
+
it "wraps the response body in a CallableEncoder" do
|
98
|
+
subject.encode_body
|
99
|
+
Webmachine::CallableEncoder.should === response.body
|
100
|
+
end
|
101
|
+
|
102
|
+
it_should_behave_like "a non-String body"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|