webmachine 1.2.2 → 1.3.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +48 -206
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
data/lib/webmachine/resource.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'webmachine/constants'
|
2
|
+
|
1
3
|
module Webmachine
|
2
4
|
class Resource
|
3
5
|
# These methods are the primary way your {Webmachine::Resource}
|
@@ -123,7 +125,7 @@ module Webmachine
|
|
123
125
|
# @return [Array<String>] allowed methods on this resource
|
124
126
|
# @api callback
|
125
127
|
def allowed_methods
|
126
|
-
[
|
128
|
+
[GET_METHOD, HEAD_METHOD]
|
127
129
|
end
|
128
130
|
|
129
131
|
# HTTP methods that are known to the resource. Like
|
@@ -134,7 +136,7 @@ module Webmachine
|
|
134
136
|
# @return [Array<String>] known methods
|
135
137
|
# @api callback
|
136
138
|
def known_methods
|
137
|
-
|
139
|
+
STANDARD_HTTP_METHODS
|
138
140
|
end
|
139
141
|
|
140
142
|
# This method is called when a DELETE request should be enacted,
|
@@ -209,7 +211,7 @@ module Webmachine
|
|
209
211
|
# @return an array of mediatype/handler pairs
|
210
212
|
# @api callback
|
211
213
|
def content_types_provided
|
212
|
-
[[
|
214
|
+
[[TEXT_HTML, :to_html]]
|
213
215
|
end
|
214
216
|
|
215
217
|
# Similarly to content_types_provided, this should return an array
|
@@ -263,7 +265,7 @@ module Webmachine
|
|
263
265
|
# @api callback
|
264
266
|
# @see Encodings
|
265
267
|
def encodings_provided
|
266
|
-
{
|
268
|
+
{IDENTITY => :encode_identity }
|
267
269
|
end
|
268
270
|
|
269
271
|
# If this method is implemented, it should return a list of
|
@@ -0,0 +1 @@
|
|
1
|
+
IO response body
|
@@ -4,32 +4,68 @@ require "net/http"
|
|
4
4
|
shared_examples_for :adapter_lint do
|
5
5
|
attr_accessor :client
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
dispatcher = Webmachine::Dispatcher.new
|
10
|
-
dispatcher.add_route ["test"], Test::Resource
|
7
|
+
let(:address) { "127.0.0.1" }
|
8
|
+
let(:port) { s = TCPServer.new(address, 0); p = s.addr[1]; s.close; p }
|
11
9
|
|
12
|
-
|
13
|
-
|
10
|
+
let(:application) do
|
11
|
+
application = Webmachine::Application.new
|
12
|
+
application.dispatcher.add_route ["test"], Test::Resource
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
application.configure do |c|
|
15
|
+
c.ip = address
|
16
|
+
c.port = port
|
17
|
+
end
|
18
|
+
|
19
|
+
application
|
20
|
+
end
|
17
21
|
|
22
|
+
let(:client) do
|
23
|
+
client = Net::HTTP.new(application.configuration.ip, port)
|
18
24
|
# Wait until the server is responsive
|
19
25
|
timeout(5) do
|
20
26
|
begin
|
21
27
|
client.start
|
22
28
|
rescue Errno::ECONNREFUSED
|
23
|
-
sleep(0.
|
29
|
+
sleep(0.01)
|
24
30
|
retry
|
25
31
|
end
|
26
32
|
end
|
33
|
+
client
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
@adapter = described_class.new(application)
|
38
|
+
|
39
|
+
Thread.abort_on_exception = true
|
40
|
+
@server_thread = Thread.new { @adapter.run }
|
41
|
+
sleep(0.01)
|
27
42
|
end
|
28
43
|
|
29
|
-
after
|
30
|
-
|
31
|
-
@
|
32
|
-
|
44
|
+
after do
|
45
|
+
client.finish
|
46
|
+
@server_thread.kill
|
47
|
+
end
|
48
|
+
|
49
|
+
it "provides the request URI" do
|
50
|
+
request = Net::HTTP::Get.new("/test")
|
51
|
+
request["Accept"] = "test/response.request_uri"
|
52
|
+
response = client.request(request)
|
53
|
+
expect(response.body).to eq("http://#{address}:#{port}/test")
|
54
|
+
end
|
55
|
+
|
56
|
+
context do
|
57
|
+
let(:address) { "::1" }
|
58
|
+
|
59
|
+
it "provides the IPv6 request URI" do
|
60
|
+
if RUBY_VERSION =~ /^2\.(0|1)\./
|
61
|
+
skip "Net::HTTP regression in Ruby 2.(0|1)"
|
62
|
+
end
|
63
|
+
|
64
|
+
request = Net::HTTP::Get.new("/test")
|
65
|
+
request["Accept"] = "test/response.request_uri"
|
66
|
+
response = client.request(request)
|
67
|
+
expect(response.body).to eq("http://[#{address}]:#{port}/test")
|
68
|
+
end
|
33
69
|
end
|
34
70
|
|
35
71
|
it "provides a string-like request body" do
|
@@ -37,8 +73,8 @@ shared_examples_for :adapter_lint do
|
|
37
73
|
request.body = "Hello, World!"
|
38
74
|
request["Content-Type"] = "test/request.stringbody"
|
39
75
|
response = client.request(request)
|
40
|
-
response["Content-Length"].
|
41
|
-
response.body.
|
76
|
+
expect(response["Content-Length"]).to eq("21")
|
77
|
+
expect(response.body).to eq("String: Hello, World!")
|
42
78
|
end
|
43
79
|
|
44
80
|
it "provides an enumerable request body" do
|
@@ -46,66 +82,64 @@ shared_examples_for :adapter_lint do
|
|
46
82
|
request.body = "Hello, World!"
|
47
83
|
request["Content-Type"] = "test/request.enumbody"
|
48
84
|
response = client.request(request)
|
49
|
-
response["Content-Length"].
|
50
|
-
response.body.
|
85
|
+
expect(response["Content-Length"]).to eq("19")
|
86
|
+
expect(response.body).to eq("Enum: Hello, World!")
|
51
87
|
end
|
52
88
|
|
53
89
|
it "handles missing pages" do
|
54
90
|
request = Net::HTTP::Get.new("/missing")
|
55
91
|
response = client.request(request)
|
56
|
-
response.code.
|
57
|
-
response["Content-Type"].
|
92
|
+
expect(response.code).to eq("404")
|
93
|
+
expect(response["Content-Type"]).to eq("text/html")
|
58
94
|
end
|
59
95
|
|
60
96
|
it "handles empty response bodies" do
|
61
97
|
request = Net::HTTP::Post.new("/test")
|
62
98
|
request.body = ""
|
63
99
|
response = client.request(request)
|
64
|
-
response.code.
|
65
|
-
|
66
|
-
|
67
|
-
response["Content-Length"].should be_nil
|
68
|
-
response.body.should be_nil
|
100
|
+
expect(response.code).to eq("204")
|
101
|
+
expect(["0", nil]).to include(response["Content-Length"])
|
102
|
+
expect(response.body).to be_nil
|
69
103
|
end
|
70
104
|
|
71
105
|
it "handles string response bodies" do
|
72
106
|
request = Net::HTTP::Get.new("/test")
|
73
107
|
request["Accept"] = "test/response.stringbody"
|
74
108
|
response = client.request(request)
|
75
|
-
response["Content-Length"].
|
76
|
-
response.body.
|
109
|
+
expect(response["Content-Length"]).to eq("20")
|
110
|
+
expect(response.body).to eq("String response body")
|
77
111
|
end
|
78
112
|
|
79
113
|
it "handles enumerable response bodies" do
|
80
114
|
request = Net::HTTP::Get.new("/test")
|
81
115
|
request["Accept"] = "test/response.enumbody"
|
82
116
|
response = client.request(request)
|
83
|
-
response["Transfer-Encoding"].
|
84
|
-
response.body.
|
117
|
+
expect(response["Transfer-Encoding"]).to eq("chunked")
|
118
|
+
expect(response.body).to eq("Enumerable response body")
|
85
119
|
end
|
86
120
|
|
87
121
|
it "handles proc response bodies" do
|
88
122
|
request = Net::HTTP::Get.new("/test")
|
89
123
|
request["Accept"] = "test/response.procbody"
|
90
124
|
response = client.request(request)
|
91
|
-
response["Transfer-Encoding"].
|
92
|
-
response.body.
|
125
|
+
expect(response["Transfer-Encoding"]).to eq("chunked")
|
126
|
+
expect(response.body).to eq("Proc response body")
|
93
127
|
end
|
94
128
|
|
95
129
|
it "handles fiber response bodies" do
|
96
130
|
request = Net::HTTP::Get.new("/test")
|
97
131
|
request["Accept"] = "test/response.fiberbody"
|
98
132
|
response = client.request(request)
|
99
|
-
response["Transfer-Encoding"].
|
100
|
-
response.body.
|
133
|
+
expect(response["Transfer-Encoding"]).to eq("chunked")
|
134
|
+
expect(response.body).to eq("Fiber response body")
|
101
135
|
end
|
102
136
|
|
103
137
|
it "handles io response bodies" do
|
104
138
|
request = Net::HTTP::Get.new("/test")
|
105
139
|
request["Accept"] = "test/response.iobody"
|
106
140
|
response = client.request(request)
|
107
|
-
response["Content-Length"].
|
108
|
-
response.body.
|
141
|
+
expect(response["Content-Length"]).to eq("17")
|
142
|
+
expect(response.body).to eq("IO response body\n")
|
109
143
|
end
|
110
144
|
|
111
145
|
it "handles request cookies" do
|
@@ -113,13 +147,13 @@ shared_examples_for :adapter_lint do
|
|
113
147
|
request["Accept"] = "test/response.cookies"
|
114
148
|
request["Cookie"] = "echo=echocookie"
|
115
149
|
response = client.request(request)
|
116
|
-
response.body.
|
150
|
+
expect(response.body).to eq("echocookie")
|
117
151
|
end
|
118
152
|
|
119
153
|
it "handles response cookies" do
|
120
154
|
request = Net::HTTP::Get.new("/test")
|
121
155
|
request["Accept"] = "test/response.cookies"
|
122
156
|
response = client.request(request)
|
123
|
-
response["Set-Cookie"].
|
157
|
+
expect(response["Set-Cookie"]).to eq("cookie=monster, rodeo=clown")
|
124
158
|
end
|
125
159
|
end
|
@@ -17,8 +17,9 @@ module Test
|
|
17
17
|
["test/response.enumbody", :to_enum],
|
18
18
|
["test/response.procbody", :to_proc],
|
19
19
|
["test/response.fiberbody", :to_fiber],
|
20
|
-
["test/response.iobody", :
|
21
|
-
["test/response.cookies", :to_cookies]
|
20
|
+
["test/response.iobody", :to_io_body],
|
21
|
+
["test/response.cookies", :to_cookies],
|
22
|
+
["test/response.request_uri", :to_request_uri]
|
22
23
|
]
|
23
24
|
end
|
24
25
|
|
@@ -58,8 +59,8 @@ module Test
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
def
|
62
|
-
|
62
|
+
def to_io_body
|
63
|
+
File.new(File.expand_path('../IO_response.body', __FILE__))
|
63
64
|
end
|
64
65
|
|
65
66
|
def to_cookies
|
@@ -67,7 +68,12 @@ module Test
|
|
67
68
|
response.set_cookie("rodeo", "clown")
|
68
69
|
# FIXME: Mongrel/WEBrick fail if this method returns nil
|
69
70
|
# Might be a net/http issue. Is this a bug?
|
71
|
+
# @see Flow#o18, Helpers#encode_body_if_set
|
70
72
|
request.cookies["echo"] || ""
|
71
73
|
end
|
74
|
+
|
75
|
+
def to_request_uri
|
76
|
+
request.uri.to_s
|
77
|
+
end
|
72
78
|
end
|
73
79
|
end
|
@@ -30,6 +30,12 @@ module Webmachine
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
# Allows the response body to be converted to a IO object.
|
34
|
+
# @return [IO,nil] the body as a IO object, or nil.
|
35
|
+
def to_io
|
36
|
+
IO.try_convert(body)
|
37
|
+
end
|
38
|
+
|
33
39
|
# Returns the length of the IO stream, if known. Returns nil if
|
34
40
|
# the stream uses an encoder or charsetter that might modify the
|
35
41
|
# length of the stream, or the stream size is unknown.
|
data/lib/webmachine/trace.rb
CHANGED
data/lib/webmachine/trace/fsm.rb
CHANGED
@@ -4,6 +4,22 @@ module Webmachine
|
|
4
4
|
# tracing is enabled for a resource, enabling the capturing of
|
5
5
|
# traces.
|
6
6
|
module FSM
|
7
|
+
# Overrides the default resource accessor so that incoming
|
8
|
+
# callbacks are traced.
|
9
|
+
def initialize(_resource, _request, _response)
|
10
|
+
if trace?
|
11
|
+
class << self
|
12
|
+
def resource
|
13
|
+
@resource_proxy ||= ResourceProxy.new(@resource)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def trace?
|
20
|
+
Trace.trace?(@resource)
|
21
|
+
end
|
22
|
+
|
7
23
|
# Adds the request to the trace.
|
8
24
|
# @param [Webmachine::Request] request the request to be traced
|
9
25
|
def trace_request(request)
|
@@ -13,7 +29,7 @@ module Webmachine
|
|
13
29
|
:path => request.uri.request_uri.to_s,
|
14
30
|
:headers => request.headers,
|
15
31
|
:body => request.body.to_s
|
16
|
-
}
|
32
|
+
} if trace?
|
17
33
|
end
|
18
34
|
|
19
35
|
# Adds the response to the trace and then commits the trace to
|
@@ -25,24 +41,18 @@ module Webmachine
|
|
25
41
|
:code => response.code.to_s,
|
26
42
|
:headers => response.headers,
|
27
43
|
:body => trace_response_body(response.body)
|
28
|
-
}
|
44
|
+
} if trace?
|
29
45
|
ensure
|
30
46
|
Webmachine::Events.publish('wm.trace.record', {
|
31
47
|
:trace_id => resource.object_id.to_s,
|
32
48
|
:trace => response.trace
|
33
|
-
})
|
49
|
+
}) if trace?
|
34
50
|
end
|
35
51
|
|
36
52
|
# Adds a decision to the trace.
|
37
53
|
# @param [Symbol] decision the decision being processed
|
38
54
|
def trace_decision(decision)
|
39
|
-
response.trace << {:type => :decision, :decision => decision}
|
40
|
-
end
|
41
|
-
|
42
|
-
# Overrides the default resource accessor so that incoming
|
43
|
-
# callbacks are traced.
|
44
|
-
def resource
|
45
|
-
@resource_proxy ||= ResourceProxy.new(@resource)
|
55
|
+
response.trace << {:type => :decision, :decision => decision} if trace?
|
46
56
|
end
|
47
57
|
|
48
58
|
private
|
data/lib/webmachine/version.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
module Webmachine
|
1
|
+
module Webmachine
|
2
2
|
# Library version
|
3
|
-
VERSION = "1.
|
3
|
+
VERSION = "1.3.0".freeze
|
4
4
|
|
5
5
|
# String for use in "Server" HTTP response header, which includes
|
6
6
|
# the {VERSION}.
|
7
|
-
SERVER_STRING = "Webmachine-Ruby/#{VERSION}"
|
7
|
+
SERVER_STRING = "Webmachine-Ruby/#{VERSION}".freeze
|
8
8
|
end
|
data/memory_test.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'webmachine'
|
3
|
+
|
4
|
+
class Constantized < Webmachine::Resource
|
5
|
+
HELLO_WORLD = "Hello World".freeze
|
6
|
+
ALLOWED_METHODS = ['GET'.freeze].freeze
|
7
|
+
CONTENT_TYPES_PROVIDED = [['text/html'.freeze, :to_html].freeze].freeze
|
8
|
+
|
9
|
+
def allowed_methods
|
10
|
+
ALLOWED_METHODS
|
11
|
+
end
|
12
|
+
|
13
|
+
def content_types_provided
|
14
|
+
CONTENT_TYPES_PROVIDED
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_html
|
18
|
+
HELLO_WORLD
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Webmachine.application.routes do
|
23
|
+
add ['constantized'], Constantized
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'webmachine/test'
|
27
|
+
session = Webmachine::Test::Session.new(Webmachine.application)
|
28
|
+
CONSTANTIZED = '/constantized'.freeze
|
29
|
+
require 'memory_profiler'
|
30
|
+
report = MemoryProfiler.report do
|
31
|
+
100.times do
|
32
|
+
session.get(CONSTANTIZED)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
report.pretty_print
|
37
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'webmachine'
|
6
|
-
require 'rspec'
|
1
|
+
require "bundler/setup"
|
2
|
+
Bundler.require :default, :test, :webservers
|
7
3
|
require 'logger'
|
8
4
|
|
5
|
+
class NullLogger < Logger
|
6
|
+
def add(severity, message=nil, progname=nil, &block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
9
10
|
RSpec.configure do |config|
|
10
11
|
config.mock_with :rspec
|
11
12
|
config.filter_run :focus => true
|
12
13
|
config.run_all_when_everything_filtered = true
|
13
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
14
14
|
config.formatter = :documentation if ENV['CI']
|
15
15
|
if defined?(::Java)
|
16
16
|
config.seed = Time.now.utc
|
@@ -20,11 +20,11 @@ RSpec.configure do |config|
|
|
20
20
|
|
21
21
|
config.before(:suite) do
|
22
22
|
options = {
|
23
|
-
:Logger =>
|
23
|
+
:Logger => NullLogger.new(STDERR),
|
24
24
|
:AccessLog => []
|
25
25
|
}
|
26
26
|
Webmachine::Adapters::WEBrick::DEFAULT_OPTIONS.merge! options
|
27
|
-
Webmachine::Adapters::Rack::DEFAULT_OPTIONS.merge! options
|
27
|
+
Webmachine::Adapters::Rack::DEFAULT_OPTIONS.merge! options if defined?(Webmachine::Adapters::Rack)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|