rubycut-sinatra-contrib 1.4.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 (81) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +136 -0
  3. data/Rakefile +75 -0
  4. data/ideas.md +29 -0
  5. data/lib/sinatra/capture.rb +124 -0
  6. data/lib/sinatra/config_file.rb +167 -0
  7. data/lib/sinatra/content_for.rb +125 -0
  8. data/lib/sinatra/contrib.rb +39 -0
  9. data/lib/sinatra/contrib/all.rb +2 -0
  10. data/lib/sinatra/contrib/setup.rb +53 -0
  11. data/lib/sinatra/contrib/version.rb +17 -0
  12. data/lib/sinatra/cookies.rb +331 -0
  13. data/lib/sinatra/decompile.rb +120 -0
  14. data/lib/sinatra/engine_tracking.rb +96 -0
  15. data/lib/sinatra/extension.rb +95 -0
  16. data/lib/sinatra/json.rb +130 -0
  17. data/lib/sinatra/link_header.rb +132 -0
  18. data/lib/sinatra/multi_route.rb +87 -0
  19. data/lib/sinatra/namespace.rb +284 -0
  20. data/lib/sinatra/reloader.rb +394 -0
  21. data/lib/sinatra/respond_with.rb +249 -0
  22. data/lib/sinatra/streaming.rb +267 -0
  23. data/lib/sinatra/test_helpers.rb +87 -0
  24. data/sinatra-contrib.gemspec +127 -0
  25. data/spec/capture_spec.rb +93 -0
  26. data/spec/config_file/key_value.yml +6 -0
  27. data/spec/config_file/key_value.yml.erb +6 -0
  28. data/spec/config_file/key_value_override.yml +2 -0
  29. data/spec/config_file/missing_env.yml +4 -0
  30. data/spec/config_file/with_envs.yml +7 -0
  31. data/spec/config_file/with_nested_envs.yml +11 -0
  32. data/spec/config_file_spec.rb +63 -0
  33. data/spec/content_for/different_key.erb +1 -0
  34. data/spec/content_for/different_key.erubis +1 -0
  35. data/spec/content_for/different_key.haml +2 -0
  36. data/spec/content_for/different_key.slim +2 -0
  37. data/spec/content_for/layout.erb +1 -0
  38. data/spec/content_for/layout.erubis +1 -0
  39. data/spec/content_for/layout.haml +1 -0
  40. data/spec/content_for/layout.slim +1 -0
  41. data/spec/content_for/multiple_blocks.erb +4 -0
  42. data/spec/content_for/multiple_blocks.erubis +4 -0
  43. data/spec/content_for/multiple_blocks.haml +8 -0
  44. data/spec/content_for/multiple_blocks.slim +8 -0
  45. data/spec/content_for/multiple_yields.erb +3 -0
  46. data/spec/content_for/multiple_yields.erubis +3 -0
  47. data/spec/content_for/multiple_yields.haml +3 -0
  48. data/spec/content_for/multiple_yields.slim +3 -0
  49. data/spec/content_for/passes_values.erb +1 -0
  50. data/spec/content_for/passes_values.erubis +1 -0
  51. data/spec/content_for/passes_values.haml +1 -0
  52. data/spec/content_for/passes_values.slim +1 -0
  53. data/spec/content_for/same_key.erb +1 -0
  54. data/spec/content_for/same_key.erubis +1 -0
  55. data/spec/content_for/same_key.haml +2 -0
  56. data/spec/content_for/same_key.slim +2 -0
  57. data/spec/content_for/takes_values.erb +1 -0
  58. data/spec/content_for/takes_values.erubis +1 -0
  59. data/spec/content_for/takes_values.haml +3 -0
  60. data/spec/content_for/takes_values.slim +3 -0
  61. data/spec/content_for_spec.rb +213 -0
  62. data/spec/cookies_spec.rb +802 -0
  63. data/spec/decompile_spec.rb +44 -0
  64. data/spec/extension_spec.rb +33 -0
  65. data/spec/json_spec.rb +117 -0
  66. data/spec/link_header_spec.rb +100 -0
  67. data/spec/multi_route_spec.rb +60 -0
  68. data/spec/namespace/foo.erb +1 -0
  69. data/spec/namespace/nested/foo.erb +1 -0
  70. data/spec/namespace_spec.rb +676 -0
  71. data/spec/okjson.rb +581 -0
  72. data/spec/reloader/app.rb.erb +40 -0
  73. data/spec/reloader_spec.rb +441 -0
  74. data/spec/respond_with/bar.erb +1 -0
  75. data/spec/respond_with/bar.json.erb +1 -0
  76. data/spec/respond_with/foo.html.erb +1 -0
  77. data/spec/respond_with/not_html.sass +2 -0
  78. data/spec/respond_with_spec.rb +297 -0
  79. data/spec/spec_helper.rb +7 -0
  80. data/spec/streaming_spec.rb +436 -0
  81. metadata +313 -0
@@ -0,0 +1,4 @@
1
+ <% content_for :foo do %>foo<% end %>
2
+ <% content_for :foo do %>bar<% end %>
3
+ <% content_for :baz do %>WON'T RENDER ME<% end %>
4
+ <% content_for :foo do %>baz<% end %>
@@ -0,0 +1,8 @@
1
+ - content_for :foo do
2
+ foo
3
+ - content_for :foo do
4
+ bar
5
+ - content_for :baz do
6
+ WON'T RENDER ME
7
+ - content_for :foo do
8
+ baz
@@ -0,0 +1,8 @@
1
+ - content_for :foo do
2
+ | foo
3
+ - content_for :foo do
4
+ | bar
5
+ - content_for :baz do
6
+ | WON'T RENDER ME
7
+ - content_for :foo do
8
+ | baz
@@ -0,0 +1,3 @@
1
+ <%= yield_content :foo %>
2
+ <%= yield_content :foo %>
3
+ <%= yield_content :foo %>
@@ -0,0 +1,3 @@
1
+ <%= yield_content :foo %>
2
+ <%= yield_content :foo %>
3
+ <%= yield_content :foo %>
@@ -0,0 +1,3 @@
1
+ = yield_content :foo
2
+ = yield_content :foo
3
+ = yield_content :foo
@@ -0,0 +1,3 @@
1
+ = yield_content :foo
2
+ = yield_content :foo
3
+ = yield_content :foo
@@ -0,0 +1 @@
1
+ <%= yield_content :foo, 1, 2 %>
@@ -0,0 +1 @@
1
+ <%= yield_content :foo, 1, 2 %>
@@ -0,0 +1 @@
1
+ = yield_content :foo, 1, 2
@@ -0,0 +1 @@
1
+ == yield_content :foo, 1, 2
@@ -0,0 +1 @@
1
+ <% content_for :foo do %>foo<% end %>
@@ -0,0 +1 @@
1
+ <% content_for :foo do %>foo<% end %>
@@ -0,0 +1,2 @@
1
+ - content_for :foo do
2
+ foo
@@ -0,0 +1,2 @@
1
+ - content_for :foo do
2
+ | foo
@@ -0,0 +1 @@
1
+ <% content_for :foo do |a, b| %><i><%= a %></i> <%= b %><% end %>
@@ -0,0 +1 @@
1
+ <% content_for :foo do |a, b| %><i><%= a %></i> <%= b %><% end %>
@@ -0,0 +1,3 @@
1
+ - content_for :foo do |a, b|
2
+ %i= a
3
+ =b
@@ -0,0 +1,3 @@
1
+ - content_for :foo do |a, b|
2
+ i= a
3
+ = b
@@ -0,0 +1,213 @@
1
+ require 'backports'
2
+ require_relative 'spec_helper'
3
+
4
+ describe Sinatra::ContentFor do
5
+ subject do
6
+ Sinatra.new do
7
+ helpers Sinatra::ContentFor
8
+ set :views, File.expand_path("../content_for", __FILE__)
9
+ end.new!
10
+ end
11
+
12
+ Tilt.prefer Tilt::ERBTemplate
13
+
14
+ extend Forwardable
15
+ def_delegators :subject, :content_for, :yield_content
16
+ def render(engine, template)
17
+ subject.send(:render, engine, template, :layout => false).gsub(/\s/, '')
18
+ end
19
+
20
+ describe "without templates" do
21
+ it 'renders blocks declared with the same key you use when rendering' do
22
+ content_for(:foo) { "foo" }
23
+ yield_content(:foo).should == "foo"
24
+ end
25
+
26
+ it 'renders blocks more than once' do
27
+ content_for(:foo) { "foo" }
28
+ 3.times { yield_content(:foo).should == "foo" }
29
+ end
30
+
31
+ it 'does not render a block with a different key' do
32
+ content_for(:bar) { "bar" }
33
+ yield_content(:foo).should be_empty
34
+ end
35
+
36
+ it 'renders multiple blocks with the same key' do
37
+ content_for(:foo) { "foo" }
38
+ content_for(:foo) { "bar" }
39
+ content_for(:bar) { "WON'T RENDER ME" }
40
+ content_for(:foo) { "baz" }
41
+ yield_content(:foo).should == "foobarbaz"
42
+ end
43
+
44
+ it 'renders multiple blocks more than once' do
45
+ content_for(:foo) { "foo" }
46
+ content_for(:foo) { "bar" }
47
+ content_for(:bar) { "WON'T RENDER ME" }
48
+ content_for(:foo) { "baz" }
49
+ 3.times { yield_content(:foo).should == "foobarbaz" }
50
+ end
51
+
52
+ it 'passes values to the blocks' do
53
+ content_for(:foo) { |a| a.upcase }
54
+ yield_content(:foo, 'a').should == "A"
55
+ yield_content(:foo, 'b').should == "B"
56
+ end
57
+ end
58
+
59
+ # TODO: liquid radius markaby builder nokogiri
60
+ engines = %w[erb erubis haml slim]
61
+
62
+ engines.each do |inner|
63
+ describe inner.capitalize do
64
+ before :all do
65
+ begin
66
+ require inner
67
+ rescue LoadError => e
68
+ pending "Skipping: " << e.message
69
+ end
70
+ end
71
+
72
+ describe "with yield_content in Ruby" do
73
+ it 'renders blocks declared with the same key you use when rendering' do
74
+ render inner, :same_key
75
+ yield_content(:foo).strip.should == "foo"
76
+ end
77
+
78
+ it 'renders blocks more than once' do
79
+ render inner, :same_key
80
+ 3.times { yield_content(:foo).strip.should == "foo" }
81
+ end
82
+
83
+ it 'does not render a block with a different key' do
84
+ render inner, :different_key
85
+ yield_content(:foo).should be_empty
86
+ end
87
+
88
+ it 'renders multiple blocks with the same key' do
89
+ render inner, :multiple_blocks
90
+ yield_content(:foo).gsub(/\s/, '').should == "foobarbaz"
91
+ end
92
+
93
+ it 'renders multiple blocks more than once' do
94
+ render inner, :multiple_blocks
95
+ 3.times { yield_content(:foo).gsub(/\s/, '').should == "foobarbaz" }
96
+ end
97
+
98
+ it 'passes values to the blocks' do
99
+ render inner, :takes_values
100
+ yield_content(:foo, 1, 2).gsub(/\s/, '').should == "<i>1</i>2"
101
+ end
102
+ end
103
+
104
+ describe "with content_for in Ruby" do
105
+ it 'renders blocks declared with the same key you use when rendering' do
106
+ content_for(:foo) { "foo" }
107
+ render(inner, :layout).should == "foo"
108
+ end
109
+
110
+ it 'renders blocks more than once' do
111
+ content_for(:foo) { "foo" }
112
+ render(inner, :multiple_yields).should == "foofoofoo"
113
+ end
114
+
115
+ it 'does not render a block with a different key' do
116
+ content_for(:bar) { "foo" }
117
+ render(inner, :layout).should be_empty
118
+ end
119
+
120
+ it 'renders multiple blocks with the same key' do
121
+ content_for(:foo) { "foo" }
122
+ content_for(:foo) { "bar" }
123
+ content_for(:bar) { "WON'T RENDER ME" }
124
+ content_for(:foo) { "baz" }
125
+ render(inner, :layout).should == "foobarbaz"
126
+ end
127
+
128
+ it 'renders multiple blocks more than once' do
129
+ content_for(:foo) { "foo" }
130
+ content_for(:foo) { "bar" }
131
+ content_for(:bar) { "WON'T RENDER ME" }
132
+ content_for(:foo) { "baz" }
133
+ render(inner, :multiple_yields).should == "foobarbazfoobarbazfoobarbaz"
134
+ end
135
+
136
+ it 'passes values to the blocks' do
137
+ content_for(:foo) { |a,b| "<i>#{a}</i>#{b}" }
138
+ render(inner, :passes_values).should == "<i>1</i>2"
139
+ end
140
+ end
141
+
142
+ describe "with content_for? in Ruby" do
143
+ it 'renders block if key is set' do
144
+ content_for(:foo) { "foot" }
145
+ render(inner, :footer).should == "foot"
146
+ end
147
+
148
+ it 'does not render a block if different key' do
149
+ content_for(:different_key) { "foot" }
150
+ render(inner, :footer).should be_empty
151
+ end
152
+ end
153
+
154
+ engines.each do |outer|
155
+ describe "with yield_content in #{outer.capitalize}" do
156
+ def body
157
+ last_response.body.gsub(/\s/, '')
158
+ end
159
+
160
+ before :all do
161
+ begin
162
+ require outer
163
+ rescue LoadError => e
164
+ pending "Skipping: " << e.message
165
+ end
166
+ end
167
+
168
+ before do
169
+ mock_app do
170
+ helpers Sinatra::ContentFor
171
+ set inner, :layout_engine => outer
172
+ set :views, File.expand_path("../content_for", __FILE__)
173
+ get('/:view') { render(inner, params[:view].to_sym) }
174
+ get('/:layout/:view') do
175
+ render inner, params[:view].to_sym, :layout => params[:layout].to_sym
176
+ end
177
+ end
178
+ end
179
+
180
+ it 'renders blocks declared with the same key you use when rendering' do
181
+ get('/same_key').should be_ok
182
+ body.should == "foo"
183
+ end
184
+
185
+ it 'renders blocks more than once' do
186
+ get('/multiple_yields/same_key').should be_ok
187
+ body.should == "foofoofoo"
188
+ end
189
+
190
+ it 'does not render a block with a different key' do
191
+ get('/different_key').should be_ok
192
+ body.should be_empty
193
+ end
194
+
195
+ it 'renders multiple blocks with the same key' do
196
+ get('/multiple_blocks').should be_ok
197
+ body.should == "foobarbaz"
198
+ end
199
+
200
+ it 'renders multiple blocks more than once' do
201
+ get('/multiple_yields/multiple_blocks').should be_ok
202
+ body.should == "foobarbazfoobarbazfoobarbaz"
203
+ end
204
+
205
+ it 'passes values to the blocks' do
206
+ get('/passes_values/takes_values').should be_ok
207
+ body.should == "<i>1</i>2"
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,802 @@
1
+ require 'backports'
2
+ require_relative 'spec_helper'
3
+
4
+ describe Sinatra::Cookies do
5
+ def cookie_route(*cookies, &block)
6
+ result = nil
7
+ set_cookie(cookies)
8
+ @cookie_app.get('/') do
9
+ result = instance_eval(&block)
10
+ "ok"
11
+ end
12
+ get '/'
13
+ last_response.should be_ok
14
+ body.should be == "ok"
15
+ result
16
+ end
17
+
18
+ def cookies(*set_cookies)
19
+ cookie_route(*set_cookies) { cookies }
20
+ end
21
+
22
+ before do
23
+ app = nil
24
+ mock_app do
25
+ helpers Sinatra::Cookies
26
+ app = self
27
+ end
28
+ @cookie_app = app
29
+ clear_cookies
30
+ end
31
+
32
+ describe :cookie_route do
33
+ it 'runs the block' do
34
+ ran = false
35
+ cookie_route { ran = true }
36
+ ran.should be_true
37
+ end
38
+
39
+ it 'returns the block result' do
40
+ cookie_route { 42 }.should be == 42
41
+ end
42
+ end
43
+
44
+ describe :== do
45
+ it 'is comparable to hashes' do
46
+ cookies.should be == {}
47
+ end
48
+
49
+ it 'is comparable to anything that responds to to_hash' do
50
+ other = Struct.new(:to_hash).new({})
51
+ cookies.should be == other
52
+ end
53
+ end
54
+
55
+ describe :[] do
56
+ it 'allows access to request cookies' do
57
+ cookies("foo=bar")["foo"].should be == "bar"
58
+ end
59
+
60
+ it 'takes symbols as keys' do
61
+ cookies("foo=bar")[:foo].should be == "bar"
62
+ end
63
+
64
+ it 'returns nil for missing keys' do
65
+ cookies("foo=bar")['bar'].should be_nil
66
+ end
67
+
68
+ it 'allows access to response cookies' do
69
+ cookie_route do
70
+ response.set_cookie 'foo', 'bar'
71
+ cookies['foo']
72
+ end.should be == 'bar'
73
+ end
74
+
75
+ it 'favors response cookies over request cookies' do
76
+ cookie_route('foo=bar') do
77
+ response.set_cookie 'foo', 'baz'
78
+ cookies['foo']
79
+ end.should be == 'baz'
80
+ end
81
+
82
+
83
+ it 'takes the last value for response cookies' do
84
+ cookie_route do
85
+ response.set_cookie 'foo', 'bar'
86
+ response.set_cookie 'foo', 'baz'
87
+ cookies['foo']
88
+ end.should be == 'baz'
89
+ end
90
+ end
91
+
92
+ describe :[]= do
93
+ it 'sets cookies to httponly' do
94
+ cookie_route do
95
+ cookies['foo'] = 'bar'
96
+ response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
97
+ end.should include('HttpOnly')
98
+ end
99
+
100
+ it 'sets the domain' do
101
+ cookie_route do
102
+ cookies['foo'] = 'bar'
103
+ response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
104
+ end.should include('domain=example.org')
105
+ end
106
+
107
+ it 'sets path to / by default' do
108
+ cookie_route do
109
+ cookies['foo'] = 'bar'
110
+ response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
111
+ end.should include('path=/')
112
+ end
113
+
114
+ it 'sets path to the script_name if app is nested' do
115
+ cookie_route do
116
+ request.script_name = '/foo'
117
+ cookies['foo'] = 'bar'
118
+ response['Set-Cookie'].lines.detect { |l| l.start_with? 'foo=' }
119
+ end.should include('path=/foo')
120
+ end
121
+
122
+ it 'sets a cookie' do
123
+ cookie_route { cookies['foo'] = 'bar' }
124
+ cookie_jar['foo'].should be == 'bar'
125
+ end
126
+
127
+ it 'adds a value to the cookies hash' do
128
+ cookie_route do
129
+ cookies['foo'] = 'bar'
130
+ cookies['foo']
131
+ end.should be == 'bar'
132
+ end
133
+ end
134
+
135
+ describe :assoc do
136
+ it 'behaves like Hash#assoc' do
137
+ cookies('foo=bar').assoc('foo') == ['foo', 'bar']
138
+ end
139
+ end if Hash.method_defined? :assoc
140
+
141
+ describe :clear do
142
+ it 'removes request cookies from cookies hash' do
143
+ jar = cookies('foo=bar')
144
+ jar['foo'].should be == 'bar'
145
+ jar.clear
146
+ jar['foo'].should be_nil
147
+ end
148
+
149
+ it 'removes response cookies from cookies hash' do
150
+ cookie_route do
151
+ cookies['foo'] = 'bar'
152
+ cookies.clear
153
+ cookies['foo']
154
+ end.should be_nil
155
+ end
156
+
157
+ it 'expires existing cookies' do
158
+ cookie_route("foo=bar") do
159
+ cookies.clear
160
+ response['Set-Cookie']
161
+ end.should include("foo=;", "expires=", "1970 00:00:00")
162
+ end
163
+ end
164
+
165
+ describe :compare_by_identity? do
166
+ it { cookies.should_not be_compare_by_identity }
167
+ end
168
+
169
+ describe :default do
170
+ it { cookies.default.should be_nil }
171
+ end
172
+
173
+ describe :default_proc do
174
+ it { cookies.default_proc.should be_nil }
175
+ end
176
+
177
+ describe :delete do
178
+ it 'removes request cookies from cookies hash' do
179
+ jar = cookies('foo=bar')
180
+ jar['foo'].should be == 'bar'
181
+ jar.delete 'foo'
182
+ jar['foo'].should be_nil
183
+ end
184
+
185
+ it 'removes response cookies from cookies hash' do
186
+ cookie_route do
187
+ cookies['foo'] = 'bar'
188
+ cookies.delete 'foo'
189
+ cookies['foo']
190
+ end.should be_nil
191
+ end
192
+
193
+ it 'expires existing cookies' do
194
+ cookie_route("foo=bar") do
195
+ cookies.delete 'foo'
196
+ response['Set-Cookie']
197
+ end.should include("foo=;", "expires=", "1970 00:00:00")
198
+ end
199
+
200
+ it 'honours the app cookie_options' do
201
+ @cookie_app.class_eval do
202
+ set :cookie_options, {
203
+ :path => '/foo',
204
+ :domain => 'bar.com',
205
+ :secure => true,
206
+ :httponly => true
207
+ }
208
+ end
209
+ cookie_header = cookie_route("foo=bar") do
210
+ cookies.delete 'foo'
211
+ response['Set-Cookie']
212
+ end
213
+ cookie_header.should include("path=/foo;", "domain=bar.com;", "secure;", "HttpOnly")
214
+ end
215
+
216
+ it 'does not touch other cookies' do
217
+ cookie_route("foo=bar", "bar=baz") do
218
+ cookies.delete 'foo'
219
+ cookies['bar']
220
+ end.should be == 'baz'
221
+ end
222
+
223
+ it 'returns the previous value for request cookies' do
224
+ cookie_route("foo=bar") do
225
+ cookies.delete "foo"
226
+ end.should be == "bar"
227
+ end
228
+
229
+ it 'returns the previous value for response cookies' do
230
+ cookie_route do
231
+ cookies['foo'] = 'bar'
232
+ cookies.delete "foo"
233
+ end.should be == "bar"
234
+ end
235
+
236
+ it 'returns nil for non-existing cookies' do
237
+ cookie_route { cookies.delete("foo") }.should be_nil
238
+ end
239
+ end
240
+
241
+ describe :delete_if do
242
+ it 'deletes cookies that match the block' do
243
+ cookie_route('foo=bar') do
244
+ cookies['bar'] = 'baz'
245
+ cookies['baz'] = 'foo'
246
+ cookies.delete_if { |*a| a.include? 'bar' }
247
+ cookies.values_at 'foo', 'bar', 'baz'
248
+ end.should be == [nil, nil, 'foo']
249
+ end
250
+ end
251
+
252
+ describe :each do
253
+ it 'loops through cookies' do
254
+ keys = []
255
+ foo = nil
256
+ bar = nil
257
+
258
+ cookie_route('foo=bar', 'bar=baz') do
259
+ cookies.each do |key, value|
260
+ foo = value if key == 'foo'
261
+ bar = value if key == 'bar'
262
+ keys << key
263
+ end
264
+ end
265
+
266
+ keys.sort.should be == ['bar', 'foo']
267
+ foo.should be == 'bar'
268
+ bar.should be == 'baz'
269
+ end
270
+
271
+ it 'favors response over request cookies' do
272
+ seen = false
273
+ cookie_route('foo=bar') do
274
+ cookies[:foo] = 'baz'
275
+ cookies.each do |key, value|
276
+ key.should == 'foo'
277
+ value.should == 'baz'
278
+ seen.should == false
279
+ seen = true
280
+ end
281
+ end
282
+ end
283
+
284
+ it 'does not loop through deleted cookies' do
285
+ cookie_route('foo=bar') do
286
+ cookies.delete :foo
287
+ cookies.each { fail }
288
+ end
289
+ end
290
+
291
+ it 'returns an enumerator' do
292
+ cookie_route('foo=bar') do
293
+ enum = cookies.each
294
+ enum.each { |key, value| key.should == 'foo' }
295
+ end
296
+ end
297
+ end
298
+
299
+ describe :each_key do
300
+ it 'loops through cookies' do
301
+ keys = []
302
+
303
+ cookie_route('foo=bar', 'bar=baz') do
304
+ cookies.each_key do |key|
305
+ keys << key
306
+ end
307
+ end
308
+
309
+ keys.sort.should be == ['bar', 'foo']
310
+ end
311
+
312
+ it 'only yields keys once' do
313
+ seen = false
314
+ cookie_route('foo=bar') do
315
+ cookies[:foo] = 'baz'
316
+ cookies.each_key do |key|
317
+ seen.should == false
318
+ seen = true
319
+ end
320
+ end
321
+ end
322
+
323
+ it 'does not loop through deleted cookies' do
324
+ cookie_route('foo=bar') do
325
+ cookies.delete :foo
326
+ cookies.each_key { fail }
327
+ end
328
+ end
329
+
330
+ it 'returns an enumerator' do
331
+ cookie_route('foo=bar') do
332
+ enum = cookies.each_key
333
+ enum.each { |key| key.should == 'foo' }
334
+ end
335
+ end
336
+ end
337
+
338
+ describe :each_pair do
339
+ it 'loops through cookies' do
340
+ keys = []
341
+ foo = nil
342
+ bar = nil
343
+
344
+ cookie_route('foo=bar', 'bar=baz') do
345
+ cookies.each_pair do |key, value|
346
+ foo = value if key == 'foo'
347
+ bar = value if key == 'bar'
348
+ keys << key
349
+ end
350
+ end
351
+
352
+ keys.sort.should be == ['bar', 'foo']
353
+ foo.should be == 'bar'
354
+ bar.should be == 'baz'
355
+ end
356
+
357
+ it 'favors response over request cookies' do
358
+ seen = false
359
+ cookie_route('foo=bar') do
360
+ cookies[:foo] = 'baz'
361
+ cookies.each_pair do |key, value|
362
+ key.should == 'foo'
363
+ value.should == 'baz'
364
+ seen.should == false
365
+ seen = true
366
+ end
367
+ end
368
+ end
369
+
370
+ it 'does not loop through deleted cookies' do
371
+ cookie_route('foo=bar') do
372
+ cookies.delete :foo
373
+ cookies.each_pair { fail }
374
+ end
375
+ end
376
+
377
+ it 'returns an enumerator' do
378
+ cookie_route('foo=bar') do
379
+ enum = cookies.each_pair
380
+ enum.each { |key, value| key.should == 'foo' }
381
+ end
382
+ end
383
+ end
384
+
385
+ describe :each_value do
386
+ it 'loops through cookies' do
387
+ values = []
388
+
389
+ cookie_route('foo=bar', 'bar=baz') do
390
+ cookies.each_value do |value|
391
+ values << value
392
+ end
393
+ end
394
+
395
+ values.sort.should be == ['bar', 'baz']
396
+ end
397
+
398
+ it 'favors response over request cookies' do
399
+ seen = false
400
+ cookie_route('foo=bar') do
401
+ cookies[:foo] = 'baz'
402
+ cookies.each_value do |value|
403
+ value.should == 'baz'
404
+ seen.should == false
405
+ seen = true
406
+ end
407
+ end
408
+ end
409
+
410
+ it 'does not loop through deleted cookies' do
411
+ cookie_route('foo=bar') do
412
+ cookies.delete :foo
413
+ cookies.each_value { fail }
414
+ end
415
+ end
416
+
417
+ it 'returns an enumerator' do
418
+ cookie_route('foo=bar') do
419
+ enum = cookies.each_value
420
+ enum.each { |value| value.should == 'bar' }
421
+ end
422
+ end
423
+ end
424
+
425
+ describe :empty? do
426
+ it 'returns true if there are no cookies' do
427
+ cookies.should be_empty
428
+ end
429
+
430
+ it 'returns false if there are request cookies' do
431
+ cookies('foo=bar').should_not be_empty
432
+ end
433
+
434
+ it 'returns false if there are response cookies' do
435
+ cookie_route do
436
+ cookies['foo'] = 'bar'
437
+ cookies.empty?
438
+ end.should be_false
439
+ end
440
+
441
+ it 'becomes true if response cookies are removed' do
442
+ cookie_route do
443
+ cookies['foo'] = 'bar'
444
+ cookies.delete :foo
445
+ cookies.empty?
446
+ end.should be_true
447
+ end
448
+
449
+ it 'becomes true if request cookies are removed' do
450
+ cookie_route('foo=bar') do
451
+ cookies.delete :foo
452
+ cookies.empty?
453
+ end.should be_true
454
+ end
455
+
456
+ it 'becomes true after clear' do
457
+ cookie_route('foo=bar', 'bar=baz') do
458
+ cookies['foo'] = 'bar'
459
+ cookies.clear
460
+ cookies.empty?
461
+ end.should be_true
462
+ end
463
+ end
464
+
465
+ describe :fetch do
466
+ it 'returns values from request cookies' do
467
+ cookies('foo=bar').fetch('foo').should be == 'bar'
468
+ end
469
+
470
+ it 'returns values from response cookies' do
471
+ cookie_route do
472
+ cookies['foo'] = 'bar'
473
+ cookies.fetch('foo')
474
+ end.should be == 'bar'
475
+ end
476
+
477
+ it 'favors response over request cookies' do
478
+ cookie_route('foo=baz') do
479
+ cookies['foo'] = 'bar'
480
+ cookies.fetch('foo')
481
+ end.should be == 'bar'
482
+ end
483
+
484
+ it 'raises an exception if key does not exist' do
485
+ error = if defined? JRUBY_VERSION
486
+ IndexError
487
+ else
488
+ RUBY_VERSION >= '1.9' ? KeyError : IndexError
489
+ end
490
+ expect { cookies.fetch('foo') }.to raise_exception(error)
491
+ end
492
+
493
+ it 'returns the block result if missing' do
494
+ cookies.fetch('foo') { 'bar' }.should be == 'bar'
495
+ end
496
+ end
497
+
498
+ describe :flatten do
499
+ it { cookies('foo=bar').flatten.should be == {'foo' => 'bar'}.flatten }
500
+ end if Hash.method_defined? :flatten
501
+
502
+ describe :has_key? do
503
+ it 'checks request cookies' do
504
+ cookies('foo=bar').should have_key('foo')
505
+ end
506
+
507
+ it 'checks response cookies' do
508
+ jar = cookies
509
+ jar['foo'] = 'bar'
510
+ jar.should have_key(:foo)
511
+ end
512
+
513
+ it 'does not use deleted cookies' do
514
+ jar = cookies('foo=bar')
515
+ jar.delete :foo
516
+ jar.should_not have_key('foo')
517
+ end
518
+ end
519
+
520
+ describe :has_value? do
521
+ it 'checks request cookies' do
522
+ cookies('foo=bar').should have_value('bar')
523
+ end
524
+
525
+ it 'checks response cookies' do
526
+ jar = cookies
527
+ jar[:foo] = 'bar'
528
+ jar.should have_value('bar')
529
+ end
530
+
531
+ it 'does not use deleted cookies' do
532
+ jar = cookies('foo=bar')
533
+ jar.delete :foo
534
+ jar.should_not have_value('bar')
535
+ end
536
+ end
537
+
538
+ describe :include? do
539
+ it 'checks request cookies' do
540
+ cookies('foo=bar').should include('foo')
541
+ end
542
+
543
+ it 'checks response cookies' do
544
+ jar = cookies
545
+ jar['foo'] = 'bar'
546
+ jar.should include(:foo)
547
+ end
548
+
549
+ it 'does not use deleted cookies' do
550
+ jar = cookies('foo=bar')
551
+ jar.delete :foo
552
+ jar.should_not include('foo')
553
+ end
554
+ end
555
+
556
+ describe :index do
557
+ it 'checks request cookies' do
558
+ cookies('foo=bar').index('bar').should be == 'foo'
559
+ end
560
+
561
+ it 'checks response cookies' do
562
+ jar = cookies
563
+ jar['foo'] = 'bar'
564
+ jar.index('bar').should be == 'foo'
565
+ end
566
+
567
+ it 'returns nil when missing' do
568
+ cookies('foo=bar').index('baz').should be_nil
569
+ end
570
+ end if RUBY_VERSION < '1.9'
571
+
572
+ describe :keep_if do
573
+ it 'removes entries' do
574
+ jar = cookies('foo=bar', 'bar=baz')
575
+ jar.keep_if { |*args| args == ['bar', 'baz'] }
576
+ jar.should be == {'bar' => 'baz'}
577
+ end
578
+ end
579
+
580
+ describe :key do
581
+ it 'checks request cookies' do
582
+ cookies('foo=bar').key('bar').should be == 'foo'
583
+ end
584
+
585
+ it 'checks response cookies' do
586
+ jar = cookies
587
+ jar['foo'] = 'bar'
588
+ jar.key('bar').should be == 'foo'
589
+ end
590
+
591
+ it 'returns nil when missing' do
592
+ cookies('foo=bar').key('baz').should be_nil
593
+ end
594
+ end
595
+
596
+ describe :key? do
597
+ it 'checks request cookies' do
598
+ cookies('foo=bar').key?('foo').should be_true
599
+ end
600
+
601
+ it 'checks response cookies' do
602
+ jar = cookies
603
+ jar['foo'] = 'bar'
604
+ jar.key?(:foo).should be_true
605
+ end
606
+
607
+ it 'does not use deleted cookies' do
608
+ jar = cookies('foo=bar')
609
+ jar.delete :foo
610
+ jar.key?('foo').should be_false
611
+ end
612
+ end
613
+
614
+ describe :keys do
615
+ it { cookies('foo=bar').keys.should == ['foo'] }
616
+ end
617
+
618
+ describe :length do
619
+ it { cookies.length.should == 0 }
620
+ it { cookies('foo=bar').length.should == 1 }
621
+ end
622
+
623
+ describe :member? do
624
+ it 'checks request cookies' do
625
+ cookies('foo=bar').member?('foo').should be_true
626
+ end
627
+
628
+ it 'checks response cookies' do
629
+ jar = cookies
630
+ jar['foo'] = 'bar'
631
+ jar.member?(:foo).should be_true
632
+ end
633
+
634
+ it 'does not use deleted cookies' do
635
+ jar = cookies('foo=bar')
636
+ jar.delete :foo
637
+ jar.member?('foo').should be_false
638
+ end
639
+ end
640
+
641
+ describe :merge do
642
+ it 'is mergable with a hash' do
643
+ cookies('foo=bar').merge(:bar => :baz).should be == {"foo" => "bar", :bar => :baz}
644
+ end
645
+
646
+ it 'does not create cookies' do
647
+ jar = cookies('foo=bar')
648
+ jar.merge(:bar => 'baz')
649
+ jar.should_not include(:bar)
650
+ end
651
+
652
+ it 'takes a block for conflict resolution' do
653
+ update = {'foo' => 'baz', 'bar' => 'baz'}
654
+ merged = cookies('foo=bar').merge(update) do |key, old, other|
655
+ key.should be == 'foo'
656
+ old.should be == 'bar'
657
+ other.should be == 'baz'
658
+ 'foo'
659
+ end
660
+ merged['foo'].should be == 'foo'
661
+ end
662
+ end
663
+
664
+ describe :merge! do
665
+ it 'creates cookies' do
666
+ jar = cookies('foo=bar')
667
+ jar.merge! :bar => 'baz'
668
+ jar.should include('bar')
669
+ end
670
+
671
+ it 'overrides existing values' do
672
+ jar = cookies('foo=bar')
673
+ jar.merge! :foo => "baz"
674
+ jar["foo"].should be == "baz"
675
+ end
676
+
677
+ it 'takes a block for conflict resolution' do
678
+ update = {'foo' => 'baz', 'bar' => 'baz'}
679
+ jar = cookies('foo=bar')
680
+ jar.merge!(update) do |key, old, other|
681
+ key.should be == 'foo'
682
+ old.should be == 'bar'
683
+ other.should be == 'baz'
684
+ 'foo'
685
+ end
686
+ jar['foo'].should be == 'foo'
687
+ end
688
+ end
689
+
690
+ describe :rassoc do
691
+ it 'behaves like Hash#assoc' do
692
+ cookies('foo=bar').rassoc('bar') == ['foo', 'bar']
693
+ end
694
+ end if Hash.method_defined? :rassoc
695
+
696
+ describe :reject do
697
+ it 'removes entries from new hash' do
698
+ jar = cookies('foo=bar', 'bar=baz')
699
+ sub = jar.reject { |*args| args == ['bar', 'baz'] }
700
+ sub.should be == {'foo' => 'bar'}
701
+ jar['bar'].should be == 'baz'
702
+ end
703
+ end
704
+
705
+ describe :reject! do
706
+ it 'removes entries' do
707
+ jar = cookies('foo=bar', 'bar=baz')
708
+ jar.reject! { |*args| args == ['bar', 'baz'] }
709
+ jar.should be == {'foo' => 'bar'}
710
+ end
711
+ end
712
+
713
+ describe :replace do
714
+ it 'replaces entries' do
715
+ jar = cookies('foo=bar', 'bar=baz')
716
+ jar.replace 'foo' => 'baz', 'baz' => 'bar'
717
+ jar.should be == {'foo' => 'baz', 'baz' => 'bar'}
718
+ end
719
+ end
720
+
721
+ describe :select do
722
+ it 'removes entries from new hash' do
723
+ jar = cookies('foo=bar', 'bar=baz')
724
+ sub = jar.select { |*args| args != ['bar', 'baz'] }
725
+ sub.should be == {'foo' => 'bar'}.select { true }
726
+ jar['bar'].should be == 'baz'
727
+ end
728
+ end
729
+
730
+ describe :select! do
731
+ it 'removes entries' do
732
+ jar = cookies('foo=bar', 'bar=baz')
733
+ jar.select! { |*args| args != ['bar', 'baz'] }
734
+ jar.should be == {'foo' => 'bar'}
735
+ end
736
+ end if Hash.method_defined? :select!
737
+
738
+ describe :shift do
739
+ it 'removes from the hash' do
740
+ jar = cookies('foo=bar')
741
+ jar.shift.should be == ['foo', 'bar']
742
+ jar.should_not include('bar')
743
+ end
744
+ end
745
+
746
+ describe :size do
747
+ it { cookies.size.should == 0 }
748
+ it { cookies('foo=bar').size.should == 1 }
749
+ end
750
+
751
+ describe :update do
752
+ it 'creates cookies' do
753
+ jar = cookies('foo=bar')
754
+ jar.update :bar => 'baz'
755
+ jar.should include('bar')
756
+ end
757
+
758
+ it 'overrides existing values' do
759
+ jar = cookies('foo=bar')
760
+ jar.update :foo => "baz"
761
+ jar["foo"].should be == "baz"
762
+ end
763
+
764
+ it 'takes a block for conflict resolution' do
765
+ merge = {'foo' => 'baz', 'bar' => 'baz'}
766
+ jar = cookies('foo=bar')
767
+ jar.update(merge) do |key, old, other|
768
+ key.should be == 'foo'
769
+ old.should be == 'bar'
770
+ other.should be == 'baz'
771
+ 'foo'
772
+ end
773
+ jar['foo'].should be == 'foo'
774
+ end
775
+ end
776
+
777
+ describe :value? do
778
+ it 'checks request cookies' do
779
+ cookies('foo=bar').value?('bar').should be_true
780
+ end
781
+
782
+ it 'checks response cookies' do
783
+ jar = cookies
784
+ jar[:foo] = 'bar'
785
+ jar.value?('bar').should be_true
786
+ end
787
+
788
+ it 'does not use deleted cookies' do
789
+ jar = cookies('foo=bar')
790
+ jar.delete :foo
791
+ jar.value?('bar').should_not be_true
792
+ end
793
+ end
794
+
795
+ describe :values do
796
+ it { cookies('foo=bar', 'bar=baz').values.sort.should be == ['bar', 'baz'] }
797
+ end
798
+
799
+ describe :values_at do
800
+ it { cookies('foo=bar', 'bar=baz').values_at('foo').should be == ['bar'] }
801
+ end
802
+ end