volt 0.8.27.beta6 → 0.8.27.beta7

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -3
  3. data/VERSION +1 -1
  4. data/app/volt/models/user.rb +1 -1
  5. data/app/volt/tasks/query_tasks.rb +2 -2
  6. data/app/volt/tasks/store_tasks.rb +14 -4
  7. data/app/volt/tasks/user_tasks.rb +1 -1
  8. data/lib/volt/controllers/http_controller.rb +60 -0
  9. data/lib/volt/controllers/model_controller.rb +5 -1
  10. data/lib/volt/extra_core/string.rb +6 -0
  11. data/lib/volt/models/array_model.rb +6 -2
  12. data/lib/volt/models/associations.rb +1 -1
  13. data/lib/volt/models/buffer.rb +14 -3
  14. data/lib/volt/models/model.rb +28 -60
  15. data/lib/volt/models/permissions.rb +4 -4
  16. data/lib/volt/reactive/computation.rb +15 -15
  17. data/lib/volt/reactive/reactive_array.rb +1 -0
  18. data/lib/volt/router/routes.rb +67 -27
  19. data/lib/volt/server.rb +37 -6
  20. data/lib/volt/server/component_templates.rb +2 -2
  21. data/lib/volt/server/rack/http_request.rb +50 -0
  22. data/lib/volt/server/rack/http_resource.rb +41 -0
  23. data/lib/volt/server/rack/http_response_header.rb +33 -0
  24. data/lib/volt/server/rack/http_response_renderer.rb +41 -0
  25. data/lib/volt/spec/setup.rb +4 -2
  26. data/lib/volt/tasks/dispatcher.rb +7 -7
  27. data/lib/volt/tasks/task_handler.rb +1 -1
  28. data/lib/volt/volt/users.rb +12 -6
  29. data/spec/apps/kitchen_sink/app/main/config/routes.rb +18 -10
  30. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
  31. data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +15 -0
  32. data/spec/apps/kitchen_sink/app/main/controllers/upload_controller.rb +22 -0
  33. data/spec/apps/kitchen_sink/app/main/views/main/yield.html +2 -2
  34. data/spec/apps/kitchen_sink/app/main/views/upload/index.html +15 -0
  35. data/spec/controllers/http_controller_spec.rb +130 -0
  36. data/spec/extra_core/string_transformation_test_cases.rb +8 -0
  37. data/spec/extra_core/string_transformations_spec.rb +12 -0
  38. data/spec/integration/http_endpoints_spec.rb +29 -0
  39. data/spec/integration/user_spec.rb +42 -42
  40. data/spec/models/associations_spec.rb +4 -4
  41. data/spec/models/buffer_spec.rb +15 -0
  42. data/spec/models/model_spec.rb +70 -25
  43. data/spec/models/model_state_spec.rb +1 -1
  44. data/spec/models/permissions_spec.rb +64 -2
  45. data/spec/models/persistors/params_spec.rb +8 -8
  46. data/spec/models/persistors/store_spec.rb +1 -1
  47. data/spec/models/user_validation_spec.rb +1 -1
  48. data/spec/router/routes_spec.rb +111 -43
  49. data/spec/server/rack/http_request_spec.rb +50 -0
  50. data/spec/server/rack/http_resource_spec.rb +59 -0
  51. data/spec/server/rack/http_response_header_spec.rb +34 -0
  52. data/spec/server/rack/http_response_renderer_spec.rb +33 -0
  53. data/spec/tasks/dispatcher_spec.rb +2 -2
  54. data/templates/component/config/routes.rb +2 -2
  55. data/templates/project/Gemfile.tt +3 -5
  56. data/templates/project/app/main/config/routes.rb +4 -4
  57. data/volt.gemspec +2 -2
  58. metadata +33 -8
@@ -33,48 +33,48 @@ if ENV['BROWSER']
33
33
 
34
34
  expect(page).to have_content('Test Account 9550')
35
35
  end
36
- #
37
- # it 'should login and logout' do
38
- # visit '/'
39
- #
40
- # # Add the user
41
- # $page.store._users << { email: 'test@test.com', password: 'awes0mesEcRet', name: 'Test Account 9550' }
42
- #
43
- # click_link 'Login'
44
- #
45
- # fields = all(:css, 'form .form-control')
46
- # fields[0].set('test@test.com')
47
- # fields[1].set('awes0mesEcRet')
48
- # click_button 'Login'
49
- #
50
- # expect(page).to have_content('Test Account 9550')
51
- #
52
- # # Click the logout link
53
- # click_link 'Test Account 9550'
54
- # click_link 'Logout'
55
- #
56
- # expect(page).to_not have_content('Test Account 9550')
57
- # end
58
- #
59
- # it 'should fail to create an account without a valid email and password' do
60
- # visit '/'
61
- #
62
- # click_link 'Login'
63
- # click_link 'Signup here'
64
- #
65
- # expect(page).to_not have_content('must be at least 8 characters')
66
- #
67
- # fields = all(:css, 'form .form-control')
68
- #
69
- # fields[0].set('test')
70
- # fields[1].set('awe')
71
- # fields[2].set('Tes')
72
- #
73
- # # some capybara drivers don't trigger blur correctly
74
- # page.execute_script("$('.form-control').blur()")
75
- #
76
- # expect(page).to have_content('must be at least 8 characters')
77
- # end
36
+
37
+ it 'should login and logout' do
38
+ visit '/'
39
+
40
+ # Add the user
41
+ store._users! << { email: 'test@test.com', password: 'awes0mesEcRet', name: 'Test Account 9550' }
42
+
43
+ click_link 'Login'
44
+
45
+ fields = all(:css, 'form .form-control')
46
+ fields[0].set('test@test.com')
47
+ fields[1].set('awes0mesEcRet')
48
+ click_button 'Login'
49
+
50
+ expect(page).to have_content('Test Account 9550')
51
+
52
+ # Click the logout link
53
+ click_link 'Test Account 9550'
54
+ click_link 'Logout'
55
+
56
+ expect(page).to_not have_content('Test Account 9550')
57
+ end
58
+
59
+ it 'should fail to create an account without a valid email and password' do
60
+ visit '/'
61
+
62
+ click_link 'Login'
63
+ click_link 'Signup here'
64
+
65
+ expect(page).to_not have_content('must be at least 8 characters')
66
+
67
+ fields = all(:css, 'form .form-control')
68
+
69
+ fields[0].set('test')
70
+ fields[1].set('awe')
71
+ fields[2].set('Tes')
72
+
73
+ # some capybara drivers don't trigger blur correctly
74
+ page.execute_script("$('.form-control').blur()")
75
+
76
+ expect(page).to have_content('must be at least 8 characters')
77
+ end
78
78
  end
79
79
 
80
80
  end
@@ -14,20 +14,20 @@ describe Volt::Associations do
14
14
  # DataStore.new.drop_database
15
15
  # $page.instance_variable_set('@store', nil)
16
16
 
17
- store._people << {name: 'Jimmy'}
17
+ store._people! << {name: 'Jimmy'}
18
18
  @person = store._people[0]
19
- @person._addresses << {city: 'Bozeman'}
19
+ @person._addresses! << {city: 'Bozeman'}
20
20
  @person._addresses << {city: 'Portland'}
21
21
  end
22
22
 
23
23
  it 'should associate via belongs_to' do
24
- address = store._addresses.fetch_first.sync
24
+ address = store._addresses!.fetch_first.sync
25
25
 
26
26
  expect(address.person.sync._id).to eq(@person._id)
27
27
  end
28
28
 
29
29
  it 'should associate via has_many' do
30
- person = store._people.fetch_first.sync
30
+ person = store._people!.fetch_first.sync
31
31
 
32
32
  addresses = person.addresses.fetch.sync
33
33
  expect(addresses.size).to eq(2)
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Volt::Buffer do
4
+ it 'should let you pass a block that evaluates to the then of the promise' do
5
+ buffer = the_page._items!.buffer
6
+
7
+ count = 0
8
+ result = buffer.save! do
9
+ count += 1
10
+ end
11
+
12
+ expect(count).to eq(1)
13
+ expect(result.class).to eq(Promise)
14
+ end
15
+ end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'volt/models'
3
2
 
4
3
  class TestItem < Volt::Model
5
4
  end
@@ -53,9 +52,9 @@ describe Volt::Model do
53
52
  expect(!a._false1).to eq(true)
54
53
  end
55
54
 
56
- it "should return a nil model for an underscore value that doesn't exist" do
55
+ it "should return an empty model for an underscore value that doesn't exist" do
57
56
  a = Volt::Model.new
58
- expect(a._something.attributes).to eq(nil)
57
+ expect(a._something!.attributes).to eq({})
59
58
  end
60
59
 
61
60
  it 'should trigger changed once when a new value is assigned.' do
@@ -141,7 +140,7 @@ describe Volt::Model do
141
140
  it 'should trigger changed for any indicies after a deleted index' do
142
141
  model = Volt::Model.new
143
142
 
144
- model._items << { _name: 'One' }
143
+ model._items! << { _name: 'One' }
145
144
  model._items << { _name: 'Two' }
146
145
  model._items << { _name: 'Three' }
147
146
 
@@ -157,7 +156,7 @@ describe Volt::Model do
157
156
  it 'should change the size and length when an item gets added' do
158
157
  model = Volt::Model.new
159
158
 
160
- model._items << { _name: 'One' }
159
+ model._items! << { _name: 'One' }
161
160
  size = model._items.size
162
161
  length = model._items.length
163
162
 
@@ -178,30 +177,73 @@ describe Volt::Model do
178
177
  it 'should add doubly nested arrays' do
179
178
  model = Volt::Model.new
180
179
 
181
- model._items << { name: 'Cool', lists: [] }
182
- model._items[0]._lists << { name: 'worked' }
180
+ model._items! << { name: 'Cool', lists: [] }
181
+ model._items[0]._lists! << { name: 'worked' }
183
182
  expect(model._items[0]._lists[0]._name).to eq('worked')
184
183
  end
185
184
 
186
185
  it 'should make pushed subarrays into ArrayModels' do
187
186
  model = Volt::Model.new
188
187
 
189
- model._items << { _name: 'Test', _lists: [] }
188
+ model._items! << { _name: 'Test', _lists: [] }
190
189
  expect(model._items[0]._lists.class).to eq(Volt::ArrayModel)
191
190
  end
192
191
 
193
192
  it 'should make assigned subarrays into ArrayModels' do
194
193
  model = Volt::Model.new
195
194
 
196
- model._item._name = 'Test'
195
+ model._item!._name = 'Test'
197
196
  model._item._lists = []
198
197
  expect(model._item._lists.class).to eq(Volt::ArrayModel)
199
198
  end
200
199
 
200
+ it 'should call changed when an expanded reference changes' do
201
+ a = Volt::Model.new
202
+
203
+ count = 0
204
+ -> { a._blue ; count += 1 }.watch!
205
+
206
+ expect(count).to eq(1)
207
+
208
+ a._blue!
209
+ Volt::Computation.flush!
210
+
211
+ expect(count).to eq(2)
212
+ end
213
+
214
+ it 'should call size changed when adding to an ArrayModel' do
215
+ a = Volt::Model.new
216
+
217
+ count = 0
218
+ -> { count = a._todos.size }.watch!
219
+
220
+ expect(count).to eq(0)
221
+
222
+ a._todos << {label: 'Be active'}
223
+ Volt::Computation.flush!
224
+
225
+ expect(count).to eq(1)
226
+ end
227
+
228
+ it 'should track changes through an expansion' do
229
+ a = Volt::Model.new
230
+
231
+ last_count = 0
232
+ -> { last_count = a._todos.count(&:_checked) }.watch!
233
+
234
+ expect(last_count).to eq(0)
235
+
236
+ a._todos! << {checked: true}
237
+ Volt::Computation.flush!
238
+
239
+ expect(last_count).to eq(1)
240
+ end
241
+
201
242
  it 'should call changed when a the reference to a submodel is assigned to another value' do
202
243
  a = Volt::Model.new
203
244
 
204
245
  count = 0
246
+ a._blue!
205
247
  -> { a._blue && a._blue.respond_to?(:_green) && a._blue._green; count += 1 }.watch!
206
248
  expect(count).to eq(1)
207
249
 
@@ -215,7 +257,7 @@ describe Volt::Model do
215
257
  expect(count).to eq(3)
216
258
 
217
259
  a._blue = { green: 50 }
218
- expect(a._blue._green).to eq(50)
260
+ expect(a._blue!._green).to eq(50)
219
261
  Volt::Computation.flush!
220
262
  expect(count).to eq(4)
221
263
  end
@@ -239,14 +281,14 @@ describe Volt::Model do
239
281
  it 'should let you append nested hashes' do
240
282
  a = Volt::Model.new
241
283
 
242
- a._items << { name: { text: 'Name' } }
284
+ a._items! << { name: { text: 'Name' } }
243
285
 
244
- expect(a._items[0]._name._text).to eq('Name')
286
+ expect(a._items[0]._name!._text).to eq('Name')
245
287
  end
246
288
 
247
289
  it 'should not call added too many times' do
248
290
  a = Volt::Model.new
249
- a._lists << 1
291
+ a._lists! << 1
250
292
 
251
293
  count = 0
252
294
  a._lists.on('added') { count += 1 }
@@ -258,6 +300,9 @@ describe Volt::Model do
258
300
 
259
301
  it 'should propigate to different branches' do
260
302
  a = Volt::Model.new
303
+
304
+ # Expand first
305
+ a._new_item!
261
306
  count = 0
262
307
  -> do
263
308
  count += 1
@@ -273,11 +318,11 @@ describe Volt::Model do
273
318
  describe 'paths' do
274
319
  it 'should store the path' do
275
320
  a = Volt::Model.new
276
- expect(a._test.path).to eq([:test])
321
+ expect(a._test!.path).to eq([:test])
277
322
  a._test = { _name: 'Yes' }
278
323
  expect(a._test.path).to eq([:test])
279
324
 
280
- a._items << { _name: 'Yes' }
325
+ a._items! << { _name: 'Yes' }
281
326
  expect(a._items.path).to eq([:items])
282
327
  expect(a._items[0].path).to eq([:items, :[]])
283
328
  end
@@ -294,7 +339,7 @@ describe Volt::Model do
294
339
  it 'should handle nested paths' do
295
340
  a = Volt::Model.new
296
341
 
297
- a._items << { name: 'Cool', lists: [{ name: 'One' }, { name: 'Two' }] }
342
+ a._items! << { name: 'Cool', lists: [{ name: 'One' }, { name: 'Two' }] }
298
343
 
299
344
  expect(a._items[0]._lists.path).to eq([:items, :[], :lists])
300
345
  expect(a._items[0]._lists[1].path).to eq([:items, :[], :lists, :[]])
@@ -303,7 +348,7 @@ describe Volt::Model do
303
348
  it 'should trigger added when added' do
304
349
  a = Volt::Model.new
305
350
  count = 0
306
- b = a._items
351
+ b = a._items!
307
352
 
308
353
  b.on('added') { count += 1 }
309
354
  expect(count).to eq(0)
@@ -360,7 +405,7 @@ describe Volt::Model do
360
405
 
361
406
  it 'should convert to a hash, and unwrap all of the way down' do
362
407
  a = Volt::Model.new
363
- a._items << { name: 'Test1', other: { time: 'Now' } }
408
+ a._items! << { name: 'Test1', other: { time: 'Now' } }
364
409
  a._items << { name: 'Test2', other: { time: 'Later' } }
365
410
 
366
411
  item1 = a._items[0].to_h
@@ -382,25 +427,25 @@ describe Volt::Model do
382
427
  end
383
428
 
384
429
  it 'should set the model path' do
385
- @model._object._name = 'Test'
430
+ @model._object!._name = 'Test'
386
431
  expect(@model._object.path).to eq([:object])
387
432
  end
388
433
 
389
434
  it 'should set the model path for a sub array' do
390
- @model._items << { name: 'Bob' }
435
+ @model._items! << { name: 'Bob' }
391
436
  expect(@model._items.path).to eq([:items])
392
437
  expect(@model._items[0].path).to eq([:items, :[]])
393
438
  end
394
439
 
395
440
  it 'should set the model path for sub sub arrays' do
396
- @model._lists << { name: 'List 1', items: [] }
397
- expect(@model._lists[0]._items.path).to eq([:lists, :[], :items])
441
+ @model._lists! << { name: 'List 1', items: [] }
442
+ expect(@model._lists[0]._items!.path).to eq([:lists, :[], :items])
398
443
  end
399
444
 
400
445
  it 'should update the path when added from a model instance to a collection' do
401
446
  test_item = TestItem.new
402
447
 
403
- @model._items << test_item
448
+ @model._items! << test_item
404
449
  expect(@model._items[0].path).to eq([:items, :[]])
405
450
  end
406
451
  end
@@ -440,7 +485,7 @@ describe Volt::Model do
440
485
  @model = Volt::Model.new
441
486
 
442
487
  # Should return a buffer of the right type
443
- expect(@model._items.buffer.class).to eq(Item)
488
+ expect(@model._items!.buffer.class).to eq(Item)
444
489
 
445
490
  # Should insert as the right type
446
491
  @model._items << { _name: 'Item 1' }
@@ -482,7 +527,7 @@ describe Volt::Model do
482
527
 
483
528
  if RUBY_PLATFORM != 'opal'
484
529
  it 'should update other queries on the server when a new model is created' do
485
- query1 = store._todos
530
+ query1 = store._todos!
486
531
  query2 = store._todos.limit(1)
487
532
 
488
533
  count = 0
@@ -5,7 +5,7 @@ if RUBY_PLATFORM != 'opal'
5
5
 
6
6
  describe Volt::Model do
7
7
  it 'should stay loaded while a computaiton is watching some data' do
8
- expect(store._items.loaded_state).to eq(:not_loaded)
8
+ expect(store._items!.loaded_state).to eq(:not_loaded)
9
9
 
10
10
  comp = -> { store._items.size }.watch!
11
11
 
@@ -28,6 +28,25 @@ class ::TestDenyReadName < Volt::Model
28
28
  end
29
29
  end
30
30
 
31
+ class ::TestUpdateReadCheck < Volt::Model
32
+ attr_accessor :create_check, :update_check, :read_check
33
+
34
+ permissions(:create) do
35
+ self.create_check = true
36
+ allow
37
+ end
38
+
39
+ permissions(:update) do
40
+ self.update_check = true
41
+ allow
42
+ end
43
+
44
+ permissions(:read) do
45
+ self.read_check = true
46
+ allow
47
+ end
48
+ end
49
+
31
50
  describe "model permissions" do
32
51
  it 'should follow CRUD states when checking permissions' do
33
52
  todo = TestUserTodoWithCrudStates.new.buffer
@@ -61,7 +80,7 @@ describe "model permissions" do
61
80
  if RUBY_PLATFORM != 'opal'
62
81
  describe "read permissions" do
63
82
  it 'should deny read on a field' do
64
- model = store._test_deny_read_names.buffer
83
+ model = store._test_deny_read_names!.buffer
65
84
  model._name = 'Jimmy'
66
85
  model._other = 'should be visible'
67
86
 
@@ -78,7 +97,7 @@ describe "model permissions" do
78
97
  end
79
98
 
80
99
  it 'should prevent delete if denied' do
81
- model = store._test_deny_deletes.buffer
100
+ model = store._test_deny_deletes!.buffer
82
101
 
83
102
  model.save!.then do
84
103
  # Saved
@@ -92,5 +111,48 @@ describe "model permissions" do
92
111
  expect(count).to eq(1)
93
112
  end
94
113
  end
114
+
115
+ it 'should not check the read permissions when updating (so that all fields are present for the permissions check)' do
116
+ model = store._test_update_read_checks!.append({name: 'Ryan'}).sync
117
+
118
+ expect(model.create_check).to eq(true)
119
+ expect(model.read_check).to eq(nil)
120
+
121
+ # Update
122
+ model._name = 'Jimmy'
123
+
124
+ expect(model.read_check).to eq(nil)
125
+ expect(model.update_check).to eq(true)
126
+ end
127
+
128
+ it 'should not check read permissions on buffer save on server' do
129
+ model = store._test_update_read_checks!.buffer
130
+
131
+ model._name = 'Ryan'
132
+
133
+ # Create
134
+ model.save!
135
+
136
+ # Create happens on the save_to, not the buffer
137
+ expect(model.save_to.create_check).to eq(true)
138
+ expect(model.save_to.read_check).to eq(nil)
139
+
140
+ # Update
141
+ model._name = 'Jimmy'
142
+ model.save!
143
+
144
+ expect(model.save_to.read_check).to eq(nil)
145
+ expect(model.save_to.update_check).to eq(true)
146
+ end
147
+
148
+ it 'should not check read on delete, so all fields are available to the permissions block' do
149
+ model = store._test_update_read_checks!.append({name: 'Ryan'}).sync
150
+
151
+ expect(model.read_check).to eq(nil)
152
+
153
+ model.destroy
154
+
155
+ expect(model.read_check).to eq(nil)
156
+ end
95
157
  end
96
158
  end