sinatra-contrib 2.0.0.rc1 → 2.0.0.rc2
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 +4 -4
- data/LICENSE +2 -1
- data/lib/sinatra/decompile.rb +5 -0
- data/lib/sinatra/runner.rb +155 -0
- data/lib/sinatra/webdav.rb +93 -0
- data/sinatra-contrib.gemspec +5 -199
- metadata +13 -175
- data/spec/capture_spec.rb +0 -100
- data/spec/config_file/key_value.yml +0 -7
- data/spec/config_file/key_value.yml.erb +0 -6
- data/spec/config_file/key_value_override.yml +0 -2
- data/spec/config_file/missing_env.yml +0 -4
- data/spec/config_file/with_envs.yml +0 -7
- data/spec/config_file/with_nested_envs.yml +0 -11
- data/spec/config_file_spec.rb +0 -76
- data/spec/content_for/different_key.erb +0 -1
- data/spec/content_for/different_key.erubis +0 -1
- data/spec/content_for/different_key.haml +0 -2
- data/spec/content_for/different_key.slim +0 -2
- data/spec/content_for/footer.erb +0 -3
- data/spec/content_for/footer.erubis +0 -3
- data/spec/content_for/footer.haml +0 -2
- data/spec/content_for/footer.slim +0 -2
- data/spec/content_for/layout.erb +0 -1
- data/spec/content_for/layout.erubis +0 -1
- data/spec/content_for/layout.haml +0 -1
- data/spec/content_for/layout.slim +0 -1
- data/spec/content_for/multiple_blocks.erb +0 -4
- data/spec/content_for/multiple_blocks.erubis +0 -4
- data/spec/content_for/multiple_blocks.haml +0 -8
- data/spec/content_for/multiple_blocks.slim +0 -8
- data/spec/content_for/multiple_yields.erb +0 -3
- data/spec/content_for/multiple_yields.erubis +0 -3
- data/spec/content_for/multiple_yields.haml +0 -3
- data/spec/content_for/multiple_yields.slim +0 -3
- data/spec/content_for/passes_values.erb +0 -1
- data/spec/content_for/passes_values.erubis +0 -1
- data/spec/content_for/passes_values.haml +0 -1
- data/spec/content_for/passes_values.slim +0 -1
- data/spec/content_for/same_key.erb +0 -1
- data/spec/content_for/same_key.erubis +0 -1
- data/spec/content_for/same_key.haml +0 -2
- data/spec/content_for/same_key.slim +0 -2
- data/spec/content_for/takes_values.erb +0 -1
- data/spec/content_for/takes_values.erubis +0 -1
- data/spec/content_for/takes_values.haml +0 -3
- data/spec/content_for/takes_values.slim +0 -3
- data/spec/content_for_spec.rb +0 -241
- data/spec/cookies_spec.rb +0 -826
- data/spec/custom_logger_spec.rb +0 -43
- data/spec/extension_spec.rb +0 -32
- data/spec/json_spec.rb +0 -115
- data/spec/link_header_spec.rb +0 -99
- data/spec/multi_route_spec.rb +0 -59
- data/spec/namespace/foo.erb +0 -1
- data/spec/namespace/nested/foo.erb +0 -1
- data/spec/namespace_spec.rb +0 -791
- data/spec/okjson.rb +0 -581
- data/spec/reloader/app.rb.erb +0 -40
- data/spec/reloader_spec.rb +0 -465
- data/spec/required_params_spec.rb +0 -68
- data/spec/respond_with/bar.erb +0 -1
- data/spec/respond_with/bar.json.erb +0 -1
- data/spec/respond_with/baz.yajl +0 -1
- data/spec/respond_with/foo.html.erb +0 -1
- data/spec/respond_with/not_html.sass +0 -2
- data/spec/respond_with_spec.rb +0 -317
- data/spec/spec_helper.rb +0 -7
- data/spec/streaming_spec.rb +0 -415
@@ -1,68 +0,0 @@
|
|
1
|
-
require_relative 'spec_helper'
|
2
|
-
|
3
|
-
describe Sinatra::RequiredParams do
|
4
|
-
context "#required_params" do
|
5
|
-
context "simple keys" do
|
6
|
-
before do
|
7
|
-
mock_app do
|
8
|
-
helpers Sinatra::RequiredParams
|
9
|
-
get('/') { required_params(:p1, :p2) }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
it 'return 400 if required params do not exist' do
|
13
|
-
get('/')
|
14
|
-
expect(last_response.status).to eq(400)
|
15
|
-
end
|
16
|
-
it 'return 400 if required params do not exist partially' do
|
17
|
-
get('/', :p1 => 1)
|
18
|
-
expect(last_response.status).to eq(400)
|
19
|
-
end
|
20
|
-
it 'return 200 if required params exist' do
|
21
|
-
get('/', :p1 => 1, :p2 => 2)
|
22
|
-
expect(last_response.status).to eq(200)
|
23
|
-
end
|
24
|
-
it 'return 200 if required params exist with array' do
|
25
|
-
get('/', :p1 => 1, :p2 => [31, 32, 33])
|
26
|
-
expect(last_response.status).to eq(200)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
context "hash keys" do
|
30
|
-
before do
|
31
|
-
mock_app do
|
32
|
-
helpers Sinatra::RequiredParams
|
33
|
-
get('/') { required_params(:p1, :p2 => :p21) }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
it 'return 400 if required params do not exist' do
|
37
|
-
get('/')
|
38
|
-
expect(last_response.status).to eq(400)
|
39
|
-
end
|
40
|
-
it 'return 200 if required params exist' do
|
41
|
-
get('/', :p1 => 1, :p2 => {:p21 => 21})
|
42
|
-
expect(last_response.status).to eq(200)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
context "complex keys" do
|
46
|
-
before do
|
47
|
-
mock_app do
|
48
|
-
helpers Sinatra::RequiredParams
|
49
|
-
get('/') { required_params(:p1 => [:p11, {:p12 => :p121, :p122 => [:p123, {:p124 => :p1241}]}]) }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
it 'return 400 if required params do not exist' do
|
53
|
-
get('/')
|
54
|
-
expect(last_response.status).to eq(400)
|
55
|
-
end
|
56
|
-
it 'return 200 if required params exist' do
|
57
|
-
get('/', :p1 => {:p11 => 11, :p12 => {:p121 => 121}, :p122 => {:p123 => 123, :p124 => {:p1241 => 1241}}})
|
58
|
-
expect(last_response.status).to eq(200)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context "#_required_params" do
|
64
|
-
it "is invisible" do
|
65
|
-
expect { _required_params }.to raise_error(NameError)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/spec/respond_with/bar.erb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
guten Tag!
|
@@ -1 +0,0 @@
|
|
1
|
-
json!
|
data/spec/respond_with/baz.yajl
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
json = "yajl!"
|
@@ -1 +0,0 @@
|
|
1
|
-
Hello <%= name %>!
|
data/spec/respond_with_spec.rb
DELETED
@@ -1,317 +0,0 @@
|
|
1
|
-
require 'multi_json'
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'okjson'
|
5
|
-
|
6
|
-
describe Sinatra::RespondWith do
|
7
|
-
def provides(*args)
|
8
|
-
@provides = args
|
9
|
-
end
|
10
|
-
|
11
|
-
def respond_app(&block)
|
12
|
-
types = @provides
|
13
|
-
mock_app do
|
14
|
-
set :app_file, __FILE__
|
15
|
-
set :views, root + '/respond_with'
|
16
|
-
register Sinatra::RespondWith
|
17
|
-
respond_to(*types) if types
|
18
|
-
class_eval(&block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def respond_to(*args, &block)
|
23
|
-
respond_app { get('/') { respond_to(*args, &block) } }
|
24
|
-
end
|
25
|
-
|
26
|
-
def respond_with(*args, &block)
|
27
|
-
respond_app { get('/') { respond_with(*args, &block) } }
|
28
|
-
end
|
29
|
-
|
30
|
-
def req(*types)
|
31
|
-
p = types.shift if types.first.is_a? String and types.first.start_with? '/'
|
32
|
-
accept = types.map { |t| Sinatra::Base.mime_type(t).to_s }.join ','
|
33
|
-
get (p || '/'), {}, 'HTTP_ACCEPT' => accept
|
34
|
-
end
|
35
|
-
|
36
|
-
describe "Helpers#respond_to" do
|
37
|
-
it 'allows defining handlers by file extensions' do
|
38
|
-
respond_to do |format|
|
39
|
-
format.html { "html!" }
|
40
|
-
format.json { "json!" }
|
41
|
-
end
|
42
|
-
|
43
|
-
expect(req(:html).body).to eq("html!")
|
44
|
-
expect(req(:json).body).to eq("json!")
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'respects quality' do
|
48
|
-
respond_to do |format|
|
49
|
-
format.html { "html!" }
|
50
|
-
format.json { "json!" }
|
51
|
-
end
|
52
|
-
|
53
|
-
expect(req("text/html;q=0.7, application/json;q=0.3").body).to eq("html!")
|
54
|
-
expect(req("text/html;q=0.3, application/json;q=0.7").body).to eq("json!")
|
55
|
-
end
|
56
|
-
|
57
|
-
it 'allows using mime types' do
|
58
|
-
respond_to do |format|
|
59
|
-
format.on('text/html') { "html!" }
|
60
|
-
format.json { "json!" }
|
61
|
-
end
|
62
|
-
|
63
|
-
expect(req(:html).body).to eq("html!")
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'allows using wildcards in format matchers' do
|
67
|
-
respond_to do |format|
|
68
|
-
format.on('text/*') { "text!" }
|
69
|
-
format.json { "json!" }
|
70
|
-
end
|
71
|
-
|
72
|
-
expect(req(:html).body).to eq("text!")
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'allows using catch all wildcards in format matchers' do
|
76
|
-
respond_to do |format|
|
77
|
-
format.on('*/*') { "anything!" }
|
78
|
-
format.json { "json!" }
|
79
|
-
end
|
80
|
-
|
81
|
-
expect(req(:html).body).to eq("anything!")
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'prefers concret over generic' do
|
85
|
-
respond_to do |format|
|
86
|
-
format.on('text/*') { "text!" }
|
87
|
-
format.on('*/*') { "anything!" }
|
88
|
-
format.json { "json!" }
|
89
|
-
end
|
90
|
-
|
91
|
-
expect(req(:json).body).to eq("json!")
|
92
|
-
expect(req(:html).body).to eq("text!")
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'does not set up default handlers' do
|
96
|
-
respond_to
|
97
|
-
expect(req).not_to be_ok
|
98
|
-
expect(status).to eq(500)
|
99
|
-
expect(body).to eq("Unknown template engine")
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe "Helpers#respond_with" do
|
104
|
-
describe "matching" do
|
105
|
-
it 'allows defining handlers by file extensions' do
|
106
|
-
respond_with(:ignore) do |format|
|
107
|
-
format.html { "html!" }
|
108
|
-
format.json { "json!" }
|
109
|
-
end
|
110
|
-
|
111
|
-
expect(req(:html).body).to eq("html!")
|
112
|
-
expect(req(:json).body).to eq("json!")
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'respects quality' do
|
116
|
-
respond_with(:ignore) do |format|
|
117
|
-
format.html { "html!" }
|
118
|
-
format.json { "json!" }
|
119
|
-
end
|
120
|
-
|
121
|
-
expect(req("text/html;q=0.7, application/json;q=0.3").body).to eq("html!")
|
122
|
-
expect(req("text/html;q=0.3, application/json;q=0.7").body).to eq("json!")
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'allows using mime types' do
|
126
|
-
respond_with(:ignore) do |format|
|
127
|
-
format.on('text/html') { "html!" }
|
128
|
-
format.json { "json!" }
|
129
|
-
end
|
130
|
-
|
131
|
-
expect(req(:html).body).to eq("html!")
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'allows using wildcards in format matchers' do
|
135
|
-
respond_with(:ignore) do |format|
|
136
|
-
format.on('text/*') { "text!" }
|
137
|
-
format.json { "json!" }
|
138
|
-
end
|
139
|
-
|
140
|
-
expect(req(:html).body).to eq("text!")
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'allows using catch all wildcards in format matchers' do
|
144
|
-
respond_with(:ignore) do |format|
|
145
|
-
format.on('*/*') { "anything!" }
|
146
|
-
format.json { "json!" }
|
147
|
-
end
|
148
|
-
|
149
|
-
expect(req(:html).body).to eq("anything!")
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'prefers concret over generic' do
|
153
|
-
respond_with(:ignore) do |format|
|
154
|
-
format.on('text/*') { "text!" }
|
155
|
-
format.on('*/*') { "anything!" }
|
156
|
-
format.json { "json!" }
|
157
|
-
end
|
158
|
-
|
159
|
-
expect(req(:json).body).to eq("json!")
|
160
|
-
expect(req(:html).body).to eq("text!")
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "default behavior" do
|
165
|
-
it 'converts objects to json out of the box' do
|
166
|
-
respond_with 'a' => 'b'
|
167
|
-
expect(OkJson.decode(req(:json).body)).to eq({'a' => 'b'})
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'handles multiple routes correctly' do
|
171
|
-
respond_app do
|
172
|
-
get('/') { respond_with 'a' => 'b' }
|
173
|
-
get('/:name') { respond_with 'a' => params[:name] }
|
174
|
-
end
|
175
|
-
expect(OkJson.decode(req('/', :json).body)).to eq({'a' => 'b'})
|
176
|
-
expect(OkJson.decode(req('/b', :json).body)).to eq({'a' => 'b'})
|
177
|
-
expect(OkJson.decode(req('/c', :json).body)).to eq({'a' => 'c'})
|
178
|
-
end
|
179
|
-
|
180
|
-
it "calls to_EXT if available" do
|
181
|
-
respond_with Struct.new(:to_pdf).new("hello")
|
182
|
-
expect(req(:pdf).body).to eq("hello")
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'results in a 500 if format cannot be produced' do
|
186
|
-
respond_with({})
|
187
|
-
expect(req(:html)).not_to be_ok
|
188
|
-
expect(status).to eq(500)
|
189
|
-
expect(body).to eq("Unknown template engine")
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
describe 'templates' do
|
194
|
-
it 'looks for templates with name.target.engine' do
|
195
|
-
respond_with :foo, :name => 'World'
|
196
|
-
expect(req(:html)).to be_ok
|
197
|
-
expect(body).to eq("Hello World!")
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'looks for templates with name.engine for specific engines' do
|
201
|
-
respond_with :bar
|
202
|
-
expect(req(:html)).to be_ok
|
203
|
-
expect(body).to eq("guten Tag!")
|
204
|
-
end
|
205
|
-
|
206
|
-
it 'does not use name.engine for engines producing other formats' do
|
207
|
-
respond_with :not_html
|
208
|
-
expect(req(:html)).not_to be_ok
|
209
|
-
expect(status).to eq(500)
|
210
|
-
expect(body).to eq("Unknown template engine")
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'falls back to #json if no template is found' do
|
214
|
-
respond_with :foo, :name => 'World'
|
215
|
-
expect(req(:json)).to be_ok
|
216
|
-
expect(OkJson.decode(body)).to eq({'name' => 'World'})
|
217
|
-
end
|
218
|
-
|
219
|
-
it 'favors templates over #json' do
|
220
|
-
respond_with :bar, :name => 'World'
|
221
|
-
expect(req(:json)).to be_ok
|
222
|
-
expect(body).to eq('json!')
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'falls back to to_EXT if no template is found' do
|
226
|
-
object = {:name => 'World'}
|
227
|
-
def object.to_pdf; "hi" end
|
228
|
-
respond_with :foo, object
|
229
|
-
expect(req(:pdf)).to be_ok
|
230
|
-
expect(body).to eq("hi")
|
231
|
-
end
|
232
|
-
|
233
|
-
unless defined? JRUBY_VERSION
|
234
|
-
it 'uses yajl for json' do
|
235
|
-
respond_with :baz
|
236
|
-
expect(req(:json)).to be_ok
|
237
|
-
expect(body).to eq("\"yajl!\"")
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
describe 'customizing' do
|
243
|
-
it 'allows customizing' do
|
244
|
-
respond_with(:foo, :name => 'World') { |f| f.html { 'html!' }}
|
245
|
-
expect(req(:html)).to be_ok
|
246
|
-
expect(body).to eq("html!")
|
247
|
-
end
|
248
|
-
|
249
|
-
it 'falls back to default behavior if none matches' do
|
250
|
-
respond_with(:foo, :name => 'World') { |f| f.json { 'json!' }}
|
251
|
-
expect(req(:html)).to be_ok
|
252
|
-
expect(body).to eq("Hello World!")
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'favors generic rule over default behavior' do
|
256
|
-
respond_with(:foo, :name => 'World') { |f| f.on('*/*') { 'generic!' }}
|
257
|
-
expect(req(:html)).to be_ok
|
258
|
-
expect(body).to eq("generic!")
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
describe "inherited" do
|
263
|
-
it "registers RespondWith in an inherited app" do
|
264
|
-
app = Sinatra.new do
|
265
|
-
set :app_file, __FILE__
|
266
|
-
set :views, root + '/respond_with'
|
267
|
-
register Sinatra::RespondWith
|
268
|
-
|
269
|
-
get '/a' do
|
270
|
-
respond_with :json
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
self.app = Sinatra.new(app)
|
275
|
-
expect(req('/a', :json)).not_to be_ok
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
describe :respond_to do
|
281
|
-
it 'acts as global provides condition' do
|
282
|
-
respond_app do
|
283
|
-
respond_to :json, :html
|
284
|
-
get('/a') { 'ok' }
|
285
|
-
get('/b') { 'ok' }
|
286
|
-
end
|
287
|
-
|
288
|
-
expect(req('/b', :xml)).not_to be_ok
|
289
|
-
expect(req('/b', :html)).to be_ok
|
290
|
-
end
|
291
|
-
|
292
|
-
it 'still allows provides' do
|
293
|
-
respond_app do
|
294
|
-
respond_to :json, :html
|
295
|
-
get('/a') { 'ok' }
|
296
|
-
get('/b', :provides => :json) { 'ok' }
|
297
|
-
end
|
298
|
-
|
299
|
-
expect(req('/b', :html)).not_to be_ok
|
300
|
-
expect(req('/b', :json)).to be_ok
|
301
|
-
end
|
302
|
-
|
303
|
-
it 'plays well with namespaces' do
|
304
|
-
respond_app do
|
305
|
-
register Sinatra::Namespace
|
306
|
-
namespace '/a' do
|
307
|
-
respond_to :json
|
308
|
-
get { 'json' }
|
309
|
-
end
|
310
|
-
get('/b') { 'anything' }
|
311
|
-
end
|
312
|
-
|
313
|
-
expect(req('/a', :html)).not_to be_ok
|
314
|
-
expect(req('/b', :html)).to be_ok
|
315
|
-
end
|
316
|
-
end
|
317
|
-
end
|
data/spec/spec_helper.rb
DELETED
data/spec/streaming_spec.rb
DELETED
@@ -1,415 +0,0 @@
|
|
1
|
-
require 'backports'
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe Sinatra::Streaming do
|
5
|
-
def stream(&block)
|
6
|
-
rack_middleware = @use
|
7
|
-
out = nil
|
8
|
-
mock_app do
|
9
|
-
rack_middleware.each { |args| use(*args) }
|
10
|
-
helpers Sinatra::Streaming
|
11
|
-
get('/') { out = stream(&block) }
|
12
|
-
end
|
13
|
-
get('/')
|
14
|
-
out
|
15
|
-
end
|
16
|
-
|
17
|
-
def use(*args)
|
18
|
-
@use << args
|
19
|
-
end
|
20
|
-
|
21
|
-
before do
|
22
|
-
@use = []
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'stream test helper' do
|
26
|
-
it 'runs the given block' do
|
27
|
-
ran = false
|
28
|
-
stream { ran = true }
|
29
|
-
expect(ran).to be true
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'returns the stream object' do
|
33
|
-
out = stream { }
|
34
|
-
expect(out).to be_a(Sinatra::Helpers::Stream)
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'fires a request against that stream' do
|
38
|
-
stream { |out| out << "Hello World!" }
|
39
|
-
expect(last_response).to be_ok
|
40
|
-
expect(body).to eq("Hello World!")
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'passes the stream object to the block' do
|
44
|
-
passed = nil
|
45
|
-
returned = stream { |out| passed = out }
|
46
|
-
expect(passed).to eq(returned)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context Sinatra::Streaming::Stream do
|
51
|
-
it 'should extend the stream object' do
|
52
|
-
out = stream { }
|
53
|
-
expect(out).to be_a(Sinatra::Streaming::Stream)
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should not extend stream objects of other apps' do
|
57
|
-
out = nil
|
58
|
-
mock_app { get('/') { out = stream { }}}
|
59
|
-
get('/')
|
60
|
-
expect(out).to be_a(Sinatra::Helpers::Stream)
|
61
|
-
expect(out).not_to be_a(Sinatra::Streaming::Stream)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'app' do
|
66
|
-
it 'is the app instance the stream was created from' do
|
67
|
-
out = stream { }
|
68
|
-
expect(out.app).to be_a(Sinatra::Base)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'lineno' do
|
73
|
-
it 'defaults to 0' do
|
74
|
-
expect(stream { }.lineno).to eq(0)
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'does not increase on write' do
|
78
|
-
stream do |out|
|
79
|
-
out << "many\nlines\n"
|
80
|
-
expect(out.lineno).to eq(0)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'is writable' do
|
85
|
-
out = stream { }
|
86
|
-
out.lineno = 10
|
87
|
-
expect(out.lineno).to eq(10)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context 'pos' do
|
92
|
-
it 'defaults to 0' do
|
93
|
-
expect(stream { }.pos).to eq(0)
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'increases when writing data' do
|
97
|
-
stream do |out|
|
98
|
-
expect(out.pos).to eq(0)
|
99
|
-
out << 'hi'
|
100
|
-
expect(out.pos).to eq(2)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'is writable' do
|
105
|
-
out = stream { }
|
106
|
-
out.pos = 10
|
107
|
-
expect(out.pos).to eq(10)
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'aliased to #tell' do
|
111
|
-
out = stream { }
|
112
|
-
expect(out.tell).to eq(0)
|
113
|
-
out.pos = 10
|
114
|
-
expect(out.tell).to eq(10)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
context 'closed' do
|
119
|
-
it 'returns false while streaming' do
|
120
|
-
stream { |out| expect(out).not_to be_closed }
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'returns true after streaming' do
|
124
|
-
expect(stream {}).to be_closed
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
context 'map!' do
|
129
|
-
it 'applies transformations later' do
|
130
|
-
stream do |out|
|
131
|
-
out.map! { |s| s.upcase }
|
132
|
-
out << 'ok'
|
133
|
-
end
|
134
|
-
expect(body).to eq("OK")
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'is chainable' do
|
138
|
-
stream do |out|
|
139
|
-
out.map! { |s| s.upcase }
|
140
|
-
out.map! { |s| s.reverse }
|
141
|
-
out << 'ok'
|
142
|
-
end
|
143
|
-
expect(body).to eq("KO")
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'works with middleware' do
|
147
|
-
middleware = Class.new do
|
148
|
-
def initialize(app) @app = app end
|
149
|
-
def call(env)
|
150
|
-
status, headers, body = @app.call(env)
|
151
|
-
body.map! { |s| s.upcase }
|
152
|
-
[status, headers, body]
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
use middleware
|
157
|
-
stream { |out| out << "ok" }
|
158
|
-
expect(body).to eq("OK")
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'modifies each value separately' do
|
162
|
-
stream do |out|
|
163
|
-
out.map! { |s| s.reverse }
|
164
|
-
out << "ab" << "cd"
|
165
|
-
end
|
166
|
-
expect(body).to eq("badc")
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context 'map' do
|
171
|
-
it 'works with middleware' do
|
172
|
-
middleware = Class.new do
|
173
|
-
def initialize(app) @app = app end
|
174
|
-
def call(env)
|
175
|
-
status, headers, body = @app.call(env)
|
176
|
-
[status, headers, body.map(&:upcase)]
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
use middleware
|
181
|
-
stream { |out| out << "ok" }
|
182
|
-
expect(body).to eq("OK")
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'is chainable' do
|
186
|
-
middleware = Class.new do
|
187
|
-
def initialize(app) @app = app end
|
188
|
-
def call(env)
|
189
|
-
status, headers, body = @app.call(env)
|
190
|
-
[status, headers, body.map(&:upcase).map(&:reverse)]
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
use middleware
|
195
|
-
stream { |out| out << "ok" }
|
196
|
-
expect(body).to eq("KO")
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'can be written as each.map' do
|
200
|
-
middleware = Class.new do
|
201
|
-
def initialize(app) @app = app end
|
202
|
-
def call(env)
|
203
|
-
status, headers, body = @app.call(env)
|
204
|
-
[status, headers, body.each.map(&:upcase)]
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
use middleware
|
209
|
-
stream { |out| out << "ok" }
|
210
|
-
expect(body).to eq("OK")
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'does not modify the original body' do
|
214
|
-
stream do |out|
|
215
|
-
out.map { |s| s.reverse }
|
216
|
-
out << 'ok'
|
217
|
-
end
|
218
|
-
expect(body).to eq('ok')
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
context 'write' do
|
223
|
-
it 'writes to the stream' do
|
224
|
-
stream { |out| out.write 'hi' }
|
225
|
-
expect(body).to eq('hi')
|
226
|
-
end
|
227
|
-
|
228
|
-
it 'returns the number of bytes' do
|
229
|
-
stream do |out|
|
230
|
-
expect(out.write('hi')).to eq(2)
|
231
|
-
expect(out.write('hello')).to eq(5)
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'accepts non-string objects' do
|
236
|
-
stream do |out|
|
237
|
-
expect(out.write(12)).to eq(2)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
it 'should be aliased to syswrite' do
|
242
|
-
stream { |out| expect(out.syswrite('hi')).to eq(2) }
|
243
|
-
expect(body).to eq('hi')
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'should be aliased to write_nonblock' do
|
247
|
-
stream { |out| expect(out.write_nonblock('hi')).to eq(2) }
|
248
|
-
expect(body).to eq('hi')
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
context 'print' do
|
253
|
-
it 'writes to the stream' do
|
254
|
-
stream { |out| out.print('hi') }
|
255
|
-
expect(body).to eq('hi')
|
256
|
-
end
|
257
|
-
|
258
|
-
it 'accepts multiple arguments' do
|
259
|
-
stream { |out| out.print(1, 2, 3, 4) }
|
260
|
-
expect(body).to eq('1234')
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'returns nil' do
|
264
|
-
stream { |out| expect(out.print('hi')).to be_nil }
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
context 'printf' do
|
269
|
-
it 'writes to the stream' do
|
270
|
-
stream { |out| out.printf('hi') }
|
271
|
-
expect(body).to eq('hi')
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'interpolates the format string' do
|
275
|
-
stream { |out| out.printf("%s: %d", "answer", 42) }
|
276
|
-
expect(body).to eq('answer: 42')
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'returns nil' do
|
280
|
-
stream { |out| expect(out.printf('hi')).to be_nil }
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
context 'putc' do
|
285
|
-
it 'writes the first character of a string' do
|
286
|
-
stream { |out| out.putc('hi') }
|
287
|
-
expect(body).to eq('h')
|
288
|
-
end
|
289
|
-
|
290
|
-
it 'writes the character corresponding to an integer' do
|
291
|
-
stream { |out| out.putc(42) }
|
292
|
-
expect(body).to eq('*')
|
293
|
-
end
|
294
|
-
|
295
|
-
it 'returns nil' do
|
296
|
-
stream { |out| expect(out.putc('hi')).to be_nil }
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
context 'puts' do
|
301
|
-
it 'writes to the stream' do
|
302
|
-
stream { |out| out.puts('hi') }
|
303
|
-
expect(body).to eq("hi\n")
|
304
|
-
end
|
305
|
-
|
306
|
-
it 'accepts multiple arguments' do
|
307
|
-
stream { |out| out.puts(1, 2, 3, 4) }
|
308
|
-
expect(body).to eq("1\n2\n3\n4\n")
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'returns nil' do
|
312
|
-
stream { |out| expect(out.puts('hi')).to be_nil }
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
context 'close' do
|
317
|
-
it 'sets #closed? to true' do
|
318
|
-
stream do |out|
|
319
|
-
out.close
|
320
|
-
expect(out).to be_closed
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
it 'sets #closed_write? to true' do
|
325
|
-
stream do |out|
|
326
|
-
expect(out).not_to be_closed_write
|
327
|
-
out.close
|
328
|
-
expect(out).to be_closed_write
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
it 'fires callbacks' do
|
333
|
-
stream do |out|
|
334
|
-
fired = false
|
335
|
-
out.callback { fired = true }
|
336
|
-
out.close
|
337
|
-
expect(fired).to be true
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'prevents from further writing' do
|
342
|
-
stream do |out|
|
343
|
-
out.close
|
344
|
-
expect { out << 'hi' }.to raise_error(IOError, 'not opened for writing')
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
context 'close_read' do
|
350
|
-
it 'raises the appropriate exception' do
|
351
|
-
expect { stream { |out| out.close_read }}.
|
352
|
-
to raise_error(IOError, "closing non-duplex IO for reading")
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
context 'closed_read?' do
|
357
|
-
it('returns true') { stream { |out| expect(out).to be_closed_read }}
|
358
|
-
end
|
359
|
-
|
360
|
-
context 'rewind' do
|
361
|
-
it 'resets pos' do
|
362
|
-
stream do |out|
|
363
|
-
out << 'hi'
|
364
|
-
out.rewind
|
365
|
-
expect(out.pos).to eq(0)
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
it 'resets lineno' do
|
370
|
-
stream do |out|
|
371
|
-
out.lineno = 10
|
372
|
-
out.rewind
|
373
|
-
expect(out.lineno).to eq(0)
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
raises = %w[
|
379
|
-
bytes eof? eof getbyte getc gets read read_nonblock readbyte readchar
|
380
|
-
readline readlines readpartial sysread ungetbyte ungetc
|
381
|
-
]
|
382
|
-
|
383
|
-
enum = %w[chars each_line each_byte each_char lines]
|
384
|
-
dummies = %w[flush fsync internal_encoding pid]
|
385
|
-
|
386
|
-
raises.each do |method|
|
387
|
-
context method do
|
388
|
-
it 'raises the appropriate exception' do
|
389
|
-
expect { stream { |out| out.public_send(method) }}.
|
390
|
-
to raise_error(IOError, "not opened for reading")
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
394
|
-
|
395
|
-
enum.each do |method|
|
396
|
-
context method do
|
397
|
-
it 'creates an Enumerator' do
|
398
|
-
stream { |out| expect(out.public_send(method)).to be_a(Enumerator) }
|
399
|
-
end
|
400
|
-
|
401
|
-
it 'calling each raises the appropriate exception' do
|
402
|
-
expect { stream { |out| out.public_send(method).each { }}}.
|
403
|
-
to raise_error(IOError, "not opened for reading")
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
dummies.each do |method|
|
409
|
-
context method do
|
410
|
-
it 'returns nil' do
|
411
|
-
stream { |out| expect(out.public_send(method)).to be_nil }
|
412
|
-
end
|
413
|
-
end
|
414
|
-
end
|
415
|
-
end
|