volt 0.7.23 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -1
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +8 -0
  5. data/Guardfile +2 -2
  6. data/Readme.md +139 -136
  7. data/VERSION +1 -1
  8. data/app/volt/assets/js/setImmediate.js +175 -0
  9. data/app/volt/tasks/live_query/data_store.rb +0 -2
  10. data/app/volt/tasks/live_query/live_query.rb +4 -4
  11. data/docs/GETTING_STARTED.md +24 -3
  12. data/docs/WHY.md +1 -22
  13. data/lib/volt.rb +20 -1
  14. data/lib/volt/console.rb +20 -0
  15. data/lib/volt/controllers/model_controller.rb +25 -11
  16. data/lib/volt/extra_core/object.rb +2 -14
  17. data/lib/volt/extra_core/string.rb +4 -0
  18. data/lib/volt/models.rb +0 -1
  19. data/lib/volt/models/array_model.rb +8 -16
  20. data/lib/volt/models/cursor.rb +1 -1
  21. data/lib/volt/models/model.rb +40 -60
  22. data/lib/volt/models/model_hash_behaviour.rb +10 -24
  23. data/lib/volt/models/model_helpers.rb +2 -2
  24. data/lib/volt/models/model_state.rb +1 -1
  25. data/lib/volt/models/model_wrapper.rb +4 -4
  26. data/lib/volt/models/persistors/array_store.rb +44 -28
  27. data/lib/volt/models/persistors/base.rb +1 -1
  28. data/lib/volt/models/persistors/model_store.rb +1 -1
  29. data/lib/volt/models/persistors/params.rb +5 -1
  30. data/lib/volt/models/persistors/query/query_listener.rb +2 -0
  31. data/lib/volt/models/persistors/store.rb +3 -2
  32. data/lib/volt/models/persistors/store_state.rb +7 -2
  33. data/lib/volt/models/url.rb +35 -29
  34. data/lib/volt/models/validations.rb +7 -17
  35. data/lib/volt/page/bindings/attribute_binding.rb +57 -39
  36. data/lib/volt/page/bindings/base_binding.rb +0 -14
  37. data/lib/volt/page/bindings/content_binding.rb +15 -18
  38. data/lib/volt/page/bindings/each_binding.rb +67 -34
  39. data/lib/volt/page/bindings/if_binding.rb +15 -12
  40. data/lib/volt/page/bindings/template_binding.rb +77 -59
  41. data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +19 -4
  42. data/lib/volt/page/channel.rb +22 -38
  43. data/lib/volt/page/channel_stub.rb +3 -6
  44. data/lib/volt/page/page.rb +24 -26
  45. data/lib/volt/page/string_template_renderer.rb +46 -0
  46. data/lib/volt/page/sub_context.rb +7 -1
  47. data/lib/volt/page/targets/binding_document/component_node.rb +11 -9
  48. data/lib/volt/page/tasks.rb +3 -2
  49. data/lib/volt/page/url_tracker.rb +4 -3
  50. data/lib/volt/reactive/computation.rb +131 -0
  51. data/lib/volt/reactive/dependency.rb +71 -0
  52. data/lib/volt/reactive/eventable.rb +82 -0
  53. data/lib/volt/reactive/hash_dependency.rb +36 -0
  54. data/lib/volt/{controllers → reactive}/reactive_accessors.rb +8 -11
  55. data/lib/volt/reactive/reactive_array.rb +100 -193
  56. data/lib/volt/reactive/reactive_hash.rb +49 -0
  57. data/lib/volt/server/html_parser/attribute_scope.rb +24 -4
  58. data/lib/volt/server/html_parser/if_view_scope.rb +15 -15
  59. data/lib/volt/server/html_parser/view_scope.rb +31 -1
  60. data/spec/apps/kitchen_sink/Gemfile +4 -8
  61. data/spec/apps/kitchen_sink/app/main/config/dependencies.rb +8 -0
  62. data/spec/apps/kitchen_sink/app/main/config/routes.rb +8 -1
  63. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +8 -0
  64. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +73 -0
  65. data/spec/apps/kitchen_sink/app/main/views/main/index.html +6 -1
  66. data/spec/apps/kitchen_sink/app/main/views/main/main.html +26 -6
  67. data/spec/apps/kitchen_sink/app/main/views/main/store.html +6 -0
  68. data/spec/controllers/reactive_accessors_spec.rb +13 -15
  69. data/spec/integration/bindings_spec.rb +159 -0
  70. data/spec/integration/templates_spec.rb +15 -0
  71. data/spec/models/model_spec.rb +130 -228
  72. data/spec/reactive/computation_spec.rb +63 -0
  73. data/spec/reactive/dependency_spec.rb +5 -0
  74. data/spec/reactive/eventable_spec.rb +48 -0
  75. data/spec/reactive/reactive_array_spec.rb +97 -0
  76. data/spec/router/routes_spec.rb +26 -27
  77. data/spec/server/html_parser/view_parser_spec.rb +3 -21
  78. data/spec/server/rack/asset_files_spec.rb +1 -1
  79. data/templates/project/app/main/views/main/main.html +2 -2
  80. metadata +29 -41
  81. data/lib/volt/extra_core/time.rb +0 -16
  82. data/lib/volt/page/draw_cycle.rb +0 -31
  83. data/lib/volt/page/memory_test.rb +0 -26
  84. data/lib/volt/page/reactive_template.rb +0 -32
  85. data/lib/volt/reactive/array_extensions.rb +0 -12
  86. data/lib/volt/reactive/destructive_methods.rb +0 -19
  87. data/lib/volt/reactive/event_chain.rb +0 -125
  88. data/lib/volt/reactive/events.rb +0 -216
  89. data/lib/volt/reactive/object_tracking.rb +0 -14
  90. data/lib/volt/reactive/reactive_block.rb +0 -88
  91. data/lib/volt/reactive/reactive_generator.rb +0 -44
  92. data/lib/volt/reactive/reactive_tags.rb +0 -71
  93. data/lib/volt/reactive/reactive_value.rb +0 -427
  94. data/lib/volt/reactive/string_extensions.rb +0 -31
  95. data/spec/integration/test_integration_spec.rb +0 -14
  96. data/spec/models/event_chain_spec.rb +0 -150
  97. data/spec/models/model_buffers_spec.rb +0 -9
  98. data/spec/models/old_model_spec.rb +0 -67
  99. data/spec/models/reactive_array_spec.rb +0 -364
  100. data/spec/models/reactive_block_spec.rb +0 -13
  101. data/spec/models/reactive_call_times_spec.rb +0 -28
  102. data/spec/models/reactive_generator_spec.rb +0 -58
  103. data/spec/models/reactive_tags_spec.rb +0 -35
  104. data/spec/models/reactive_value_spec.rb +0 -370
  105. data/spec/models/store_spec.rb +0 -16
  106. data/spec/models/string_extensions_spec.rb +0 -57
@@ -0,0 +1,159 @@
1
+ if ENV['BROWSER']
2
+ require 'spec_helper'
3
+
4
+ describe "bindings test", :type => :feature do
5
+ it "should load the page" do
6
+ visit '/'
7
+
8
+ expect(page).to have_content('Kitchen Sink')
9
+ end
10
+
11
+ describe "text/fields" do
12
+ it 'should load the bindings page and update bindings' do
13
+ visit '/'
14
+
15
+ click_link 'Bindings'
16
+
17
+ # Fill in one field and see if it updates the rest
18
+ fill_in('pageName1', :with => 'Page bindings')
19
+ expect(find('#pageName1').value).to eq('Page bindings')
20
+ expect(find('#pageName2').value).to eq('Page bindings')
21
+ expect(find('#pageName3')).to have_content('Page bindings')
22
+
23
+ fill_in('pageName2', :with => 'Update everywhere')
24
+ expect(find('#pageName1').value).to eq('Update everywhere')
25
+ expect(find('#pageName2').value).to eq('Update everywhere')
26
+ expect(find('#pageName3')).to have_content('Update everywhere')
27
+ end
28
+
29
+ it 'should update params bindings and the url' do
30
+ visit '/'
31
+
32
+ click_link 'Bindings'
33
+
34
+ # phantom does not support the html5 history api
35
+ # TODO: We could probably polyfill this in phantom
36
+ if ENV['BROWSER'] != 'phantom'
37
+ expect(current_path).to eq('/bindings')
38
+ end
39
+
40
+ # Fill in one field and see if it updates the rest
41
+ fill_in('paramsName1', :with => 'Params bindings')
42
+ expect(find('#paramsName1').value).to eq('Params bindings')
43
+ expect(find('#paramsName2').value).to eq('Params bindings')
44
+ expect(find('#paramsName3')).to have_content('Params bindings')
45
+
46
+ fill_in('paramsName2', :with => 'Update everywhere')
47
+ expect(find('#paramsName1').value).to eq('Update everywhere')
48
+ expect(find('#paramsName2').value).to eq('Update everywhere')
49
+ expect(find('#paramsName3')).to have_content('Update everywhere')
50
+
51
+ if ENV['BROWSER'] != 'phantom'
52
+ expect(current_url).to match(/\/bindings[?]name[=]Update%20everywhere$/)
53
+ end
54
+ end
55
+
56
+ it 'should update the url and fields when bound to a param in the route' do
57
+ visit '/'
58
+
59
+ click_link 'Bindings'
60
+
61
+ # phantom does not support the html5 history api
62
+ # TODO: We could probably polyfill this in phantom
63
+ if ENV['BROWSER'] != 'phantom'
64
+ expect(current_path).to eq('/bindings')
65
+ end
66
+
67
+ # Fill in one field and see if it updates the rest
68
+ fill_in('routesName1', :with => 'Routes bindings')
69
+ expect(find('#routesName1').value).to eq('Routes bindings')
70
+ expect(find('#routesName2').value).to eq('Routes bindings')
71
+ expect(find('#routesName3')).to have_content('Routes bindings')
72
+
73
+ fill_in('routesName2', :with => 'bound_url')
74
+ expect(find('#routesName1').value).to eq('bound_url')
75
+ expect(find('#routesName2').value).to eq('bound_url')
76
+ expect(find('#routesName3')).to have_content('bound_url')
77
+
78
+ if ENV['BROWSER'] != 'phantom'
79
+ expect(current_path).to eq('/bindings/bound_url')
80
+ end
81
+ end
82
+
83
+ it 'should go from a url and query to params' do
84
+ visit '/bindings/testing?name=cool'
85
+
86
+ expect(find('#paramsName3')).to have_content('cool')
87
+ expect(find('#routesName3')).to have_content('testing')
88
+ end
89
+
90
+ it 'should load the bindings page and update bindings' do
91
+ visit '/'
92
+
93
+ click_link 'Bindings'
94
+
95
+ # Fill in one field and see if it updates the rest
96
+ fill_in('textareaName1', :with => 'Page bindings')
97
+ expect(find('#textareaName1').value).to eq('Page bindings')
98
+ expect(find('#textareaName2').value).to eq('Page bindings')
99
+ expect(find('#textareaName3')).to have_content('Page bindings')
100
+
101
+ fill_in('textareaName2', :with => 'Update everywhere')
102
+ expect(find('#textareaName1').value).to eq('Update everywhere')
103
+ expect(find('#textareaName2').value).to eq('Update everywhere')
104
+ expect(find('#textareaName3')).to have_content('Update everywhere')
105
+ end
106
+
107
+ end
108
+
109
+ describe "check boxes" do
110
+ it 'should load the bindings page and update checkboxes' do
111
+ visit '/'
112
+
113
+ click_link 'Bindings'
114
+
115
+ expect(find('#pageCheck3')).to have_content('')
116
+ # Fill in one field and see if it updates the rest
117
+ check('pageCheck1')
118
+ expect(find('#pageCheck1')).to be_checked
119
+ expect(find('#pageCheck2')).to be_checked
120
+ expect(find('#pageCheck3')).to have_content('true')
121
+
122
+ uncheck('pageCheck1')
123
+ expect(find('#pageCheck1')).to_not be_checked
124
+ expect(find('#pageCheck2')).to_not be_checked
125
+ expect(find('#pageCheck3')).to have_content('')
126
+ end
127
+
128
+ it 'should load the bindings page and update checkboxes bound to params' do
129
+ visit '/'
130
+
131
+ click_link 'Bindings'
132
+
133
+ if ENV['BROWSER'] != 'phantom'
134
+ expect(current_path).to eq('/bindings')
135
+ end
136
+
137
+ expect(find('#paramsCheck3')).to have_content('')
138
+ # Fill in one field and see if it updates the rest
139
+ check('paramsCheck1')
140
+ expect(find('#paramsCheck1')).to be_checked
141
+ expect(find('#paramsCheck2')).to be_checked
142
+ expect(find('#paramsCheck3')).to have_content('true')
143
+
144
+ if ENV['BROWSER'] != 'phantom'
145
+ expect(current_url).to match(/\/bindings[?]check[=]true$/)
146
+ end
147
+
148
+ uncheck('paramsCheck1')
149
+ expect(find('#paramsCheck1')).to_not be_checked
150
+ expect(find('#paramsCheck2')).to_not be_checked
151
+ expect(find('#paramsCheck3')).to have_content('')
152
+
153
+ if ENV['BROWSER'] != 'phantom'
154
+ expect(current_url).to match(/\/bindings[?]check[=]false$/)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,15 @@
1
+ if ENV['BROWSER']
2
+ require 'spec_helper'
3
+
4
+ describe "bindings test", :type => :feature do
5
+ it "should change the title when changing pages" do
6
+ visit '/'
7
+
8
+ expect(page).to have_title 'KitchenSink - KitchenSink'
9
+ click_link 'Bindings'
10
+
11
+ expect(page).to have_title 'Bindings - KitchenSink'
12
+
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,6 @@
1
1
  require 'volt/models'
2
+ require 'volt/reactive/dependency'
3
+ require 'volt/reactive/computation'
2
4
 
3
5
 
4
6
  class TestItem < Model
@@ -15,195 +17,143 @@ describe Model do
15
17
  end
16
18
 
17
19
  it "should update other values off the same model" do
18
- a = ReactiveValue.new(Model.new)
19
- count = 0
20
- a._name.on('changed') { count += 1 }
21
- expect(count).to eq(0)
20
+ a = Model.new
21
+
22
+ values = []
23
+ -> { values << a._name }.watch!
24
+
25
+ expect(values).to eq([nil])
26
+ Computation.flush!
22
27
 
23
28
  a._name = 'Bob'
24
- expect(count).to eq(1)
29
+
30
+ Computation.flush!
31
+ expect(values).to eq([nil, 'Bob'])
25
32
  end
26
33
 
27
34
  it "should say unregistered attributes are nil" do
28
- a = ReactiveValue.new(Model.new)
35
+ a = Model.new
29
36
  b = a._missing == nil
30
- expect(b.cur).to eq(true)
37
+ expect(b).to eq(true)
31
38
  end
32
39
 
33
40
  it "should negate nil and false correctly" do
34
- a = ReactiveValue.new(Model.new)
35
- expect((!a._missing).cur).to eq(true)
41
+ a = Model.new
42
+ expect((!a._missing)).to eq(true)
36
43
 
37
44
  a._mis1 = nil
38
45
  a._false1 = false
39
46
 
40
- expect((!a._mis1).cur).to eq(true)
41
- expect((!a._false1).cur).to eq(true)
47
+ expect(!a._mis1).to eq(true)
48
+ expect(!a._false1).to eq(true)
42
49
  end
43
50
 
44
51
  it "should return a nil model for an underscore value that doesn't exist" do
45
52
  a = Model.new
46
- expect(a._something.cur.attributes).to eq(nil)
53
+ expect(a._something.attributes).to eq(nil)
47
54
  end
48
55
 
49
- it "should let you bind before something is defined" do
50
- a = ReactiveValue.new(Model.new)
51
-
52
- b = a._one + 5
53
- expect(b.cur.class).to eq(NoMethodError)
54
-
55
- count = 0
56
- b.on('changed') { count += 1 }
57
- expect(count).to eq(0)
58
-
59
- a._one = 1
60
- expect(count).to eq(1)
61
- expect(b.cur).to eq(6)
62
- end
63
-
64
- it "should let you access an array element before its defined" do
65
- # TODO: ...
66
- end
67
56
 
68
57
  it "should trigger changed once when a new value is assigned." do
69
- a = ReactiveValue.new(Model.new)
58
+ a = Model.new
70
59
 
71
60
  count = 0
72
- a._blue.on('changed') { count += 1 }
61
+ -> { a._blue ; count += 1 }.watch!
62
+ expect(count).to eq(1)
73
63
 
74
64
  a._blue = 'one'
75
- expect(count).to eq(1)
76
- a._blue = 'two'
65
+ Computation.flush!
77
66
  expect(count).to eq(2)
67
+
68
+ a._blue = 'two'
69
+ Computation.flush!
70
+ expect(count).to eq(3)
78
71
  end
79
72
 
80
- it "should not call changed on other attributes" do
81
- a = ReactiveValue.new(Model.new)
73
+ it "should not trigger changed on other attributes" do
74
+ a = Model.new
82
75
 
83
76
  blue_count = 0
84
77
  green_count = 0
85
- a._blue.on('changed') { blue_count += 1 }
86
- a._green.on('changed') { green_count += 1}
87
- expect(blue_count).to eq(0)
88
- expect(green_count).to eq(0)
89
78
 
90
- a._green = 'one'
91
- expect(blue_count).to eq(0)
92
- expect(green_count).to eq(1)
93
79
 
94
- a._blue = 'two'
80
+ -> { a._blue ; blue_count += 1 }.watch!
81
+ -> { a._green ; green_count += 1 }.watch!
95
82
  expect(blue_count).to eq(1)
96
83
  expect(green_count).to eq(1)
97
84
 
85
+ a._green = 'one'
86
+ Computation.flush!
87
+ expect(blue_count).to eq(1)
88
+ expect(green_count).to eq(2)
89
+
90
+ a._blue = 'two'
91
+ Computation.flush!
92
+ expect(blue_count).to eq(2)
93
+ expect(green_count).to eq(2)
98
94
  end
99
95
 
100
96
  it "should call change through arguments" do
101
- a = ReactiveValue.new(Model.new)
97
+ a = Model.new
102
98
  a._one = 1
103
99
  a._two = 2
100
+ a._three = 3
104
101
 
105
- c = a._one + a._two
106
-
102
+ c = nil
107
103
  count = 0
108
- c.on('changed') { count += 1}
109
- expect(count).to eq(0)
104
+ -> { c = a._one + a._two ; count += 1 }.watch!
110
105
 
111
- a._two = 5
112
106
  expect(count).to eq(1)
113
107
 
114
- expect(c.cur).to eq(6)
115
- end
116
-
117
- it "should store reactive values in arrays and trigger updates when those values change" do
118
- a = ReactiveValue.new(Model.new)
119
- b = ReactiveValue.new('blue')
120
- a._items << b
121
- b.cur = 'two'
122
-
123
-
124
- a = ReactiveValue.new(Model.new)
125
- b = ReactiveValue.new('blue')
126
- a._one = 1
127
- a._items << 0
128
-
129
- count_1 = 0
130
- a._items[1].on('changed') { count_1 += 1 }
131
- expect(count_1).to eq(0)
132
-
133
- a._items << b
134
- expect(count_1).to eq(1)
135
-
136
- b.cur = 'update'
137
- expect(count_1).to eq(2)
138
-
139
- count_2 = 0
140
- a._items[2].on('changed') { count_2 += 1 }
141
- expect(count_2).to eq(0)
142
-
143
- a._items << a._one
144
- expect(count_2).to eq(1)
145
-
146
- a._one = 'updated'
147
- expect(count_1).to eq(2)
148
- expect(count_2).to eq(2)
149
- end
108
+ a._two = 5
109
+ Computation.flush!
110
+ expect(count).to eq(2)
150
111
 
151
- it "should let you register events before it expands" do
152
- a = ReactiveValue.new(Model.new)
153
- count = 0
154
- a._something.on('changed') { count += 1 }
155
- expect(count).to eq(0)
112
+ a._one = 6
113
+ Computation.flush!
114
+ expect(count).to eq(3)
156
115
 
157
- a._something = 20
158
- expect(count).to eq(1)
116
+ a._three = 7
117
+ Computation.flush!
118
+ expect(count).to eq(3)
159
119
  end
160
120
 
161
- it "should trigger changed through concat" do
162
- model = ReactiveValue.new(Model.new)
163
-
164
- concat = model._one + model._two
121
+ it 'should update through a normal array' do
122
+ model = Model.new
123
+ array = []
124
+ array << model
165
125
 
166
- count = 0
167
- concat.on('changed') { count += 1 }
168
- expect(count).to eq(0)
169
-
170
- model._one = 'one'
171
- expect(count).to eq(1)
126
+ values = []
172
127
 
173
- model._two = 'two'
174
- expect(count).to eq(2)
128
+ -> { values << array[0]._prop }.watch!
175
129
 
176
- expect(concat.cur).to eq('onetwo')
177
- end
130
+ expect(values).to eq([nil])
178
131
 
179
- it "should allow a reactive value to be assigned as a value in a model" do
180
- model = ReactiveValue.new(Model.new)
132
+ model._prop = 'one'
133
+ Computation.flush!
181
134
 
182
- model._items << {_name: 'One'}
183
- model._items << {_name: 'Two'}
135
+ expect(values).to eq([nil, 'one'])
184
136
 
185
- current = model._items[model._index]
186
-
187
- model._current_item = current
188
137
  end
189
138
 
190
139
  it "should trigger changed for any indicies after a deleted index" do
191
- model = ReactiveValue.new(Model.new)
140
+ model = Model.new
192
141
 
193
142
  model._items << {_name: 'One'}
194
143
  model._items << {_name: 'Two'}
195
144
  model._items << {_name: 'Three'}
196
145
 
197
146
  count = 0
198
- model._items[2].on('changed') { count += 1 }
199
- expect(count).to eq(0)
147
+ -> { model._items[2] ; count += 1 }.watch!
148
+ expect(count).to eq(1)
200
149
 
201
150
  model._items.delete_at(1)
202
- expect(count).to eq(1)
151
+ Computation.flush!
152
+ expect(count).to eq(2)
203
153
  end
204
154
 
205
155
  it "should change the size and length when an item gets added" do
206
- model = ReactiveValue.new(Model.new)
156
+ model = Model.new
207
157
 
208
158
  model._items << {_name: 'One'}
209
159
  size = model._items.size
@@ -211,151 +161,113 @@ describe Model do
211
161
 
212
162
  count_size = 0
213
163
  count_length = 0
214
- size.on('changed') { count_size += 1 }
215
- length.on('changed') { count_length += 1 }
216
- expect(count_size).to eq(0)
217
- expect(count_length).to eq(0)
218
-
219
- model._items << {_name: 'Two'}
164
+ -> { model._items.size ; count_size += 1 }.watch!
165
+ -> { model._items.length ; count_length += 1 }.watch!
220
166
  expect(count_size).to eq(1)
221
167
  expect(count_length).to eq(1)
168
+
169
+ model._items << {_name: 'Two'}
170
+ Computation.flush!
171
+
172
+ expect(count_size).to eq(2)
173
+ expect(count_length).to eq(2)
222
174
  end
223
175
 
224
176
  it "should add doubly nested arrays" do
225
- model = ReactiveValue.new(Model.new)
177
+ model = Model.new
226
178
 
227
179
  model._items << {_name: 'Cool', _lists: []}
228
180
  model._items[0]._lists << {_name: 'worked'}
229
- expect(model._items[0]._lists[0]._name.cur).to eq('worked')
181
+ expect(model._items[0]._lists[0]._name).to eq('worked')
230
182
  end
231
183
 
232
184
  it "should make pushed subarrays into ArrayModels" do
233
- model = ReactiveValue.new(Model.new)
185
+ model = Model.new
234
186
 
235
187
  model._items << {_name: 'Test', _lists: []}
236
- expect(model._items[0]._lists.cur.class).to eq(ArrayModel)
188
+ expect(model._items[0]._lists.class).to eq(ArrayModel)
237
189
  end
238
190
 
239
191
  it "should make assigned subarrays into ArrayModels" do
240
- model = ReactiveValue.new(Model.new)
192
+ model = Model.new
241
193
 
242
194
  model._item._name = 'Test'
243
195
  model._item._lists = []
244
- expect(model._item._lists.cur.class).to eq(ArrayModel)
196
+ expect(model._item._lists.class).to eq(ArrayModel)
245
197
  end
246
198
 
247
199
  it "should call changed when a the reference to a submodel is assigned to another value" do
248
- a = ReactiveValue.new(Model.new)
200
+ a = Model.new
249
201
 
250
202
  count = 0
251
- a._blue._green.on('changed') { count += 1 }
252
- expect(count).to eq(0)
203
+ -> { a._blue && a._blue.respond_to?(:_green) && a._blue._green ; count += 1 }.watch!
204
+ expect(count).to eq(1)
253
205
 
254
206
  a._blue._green = 5
207
+ Computation.flush!
255
208
 
256
- # TODO: Should actually just equal one
209
+ # TODO: Should equal 2
257
210
  expect(count).to eq(2)
258
211
 
259
212
  a._blue = 22
213
+ Computation.flush!
260
214
  expect(count).to eq(3)
215
+
216
+ a._blue = {_green: 50}
217
+ expect(a._blue._green).to eq(50)
218
+ Computation.flush!
219
+ expect(count).to eq(4)
261
220
  end
262
221
 
263
222
  it "should trigger changed when a value is deleted" do
264
- a = ReactiveValue.new(Model.new)
223
+ a = Model.new
265
224
 
266
225
  count = 0
267
- a._blue.on('changed') { count += 1 }
268
- expect(count).to eq(0)
269
-
270
- a._blue = 1
226
+ -> { a._blue ; count += 1 }.watch!
271
227
  expect(count).to eq(1)
272
228
 
273
- a.delete(:_blue)
229
+ a._blue = 1
230
+ Computation.flush!
274
231
  expect(count).to eq(2)
275
- end
276
-
277
- it "should not trigger a change if the new value is exactly the same" do
278
232
 
233
+ a.delete(:_blue)
234
+ Computation.flush!
235
+ expect(count).to eq(3)
279
236
  end
280
237
 
281
238
  it "should let you append nested hashes" do
282
239
  a = Model.new
283
- # TODO: Fails
284
- # a._items << {_name: {_text: 'Name'}}
285
- end
286
-
287
- it "should work" do
288
- store = ReactiveValue.new(Model.new)
289
- # params = ReactiveValue.new(Params.new)
290
- index = ReactiveValue.new(0)
291
-
292
- a = store._todo_lists
293
- store._current_todo = a#[index]
294
-
295
- added_count = 0
296
- changed_count = 0
297
- # store._todo_lists.on('added') { added_count += 1 }
298
- store._current_todo.on('changed') { changed_count += 1 }
299
- # expect(added_count).to eq(0)
300
- expect(changed_count).to eq(0)
301
-
302
- a.cur = 1000
303
- # store._todo_lists << {_name: 'List 1', _todos: []}
304
240
 
241
+ a._items << {_name: {_text: 'Name'}}
305
242
 
306
- # store._todo_lists[0]._todos << {_name: 'Todo 1'}
307
-
308
- # expect(added_count).to eq(1)
309
- # expect(changed_count).to eq(1)
243
+ expect(a._items[0]._name._text).to eq('Name')
310
244
  end
311
245
 
312
- it "should handle a basic todo list with no setup" do
313
- store = ReactiveValue.new(Model.new)
314
- params = ReactiveValue.new(Model.new({}, persistor: Persistors::Params))
315
-
316
- a = store._todo_lists
317
- store._current_todo = store._todo_lists[params._index.or(0).to_i]
318
-
319
- added_count = 0
320
- changed_count = 0
321
- store._todo_lists.on('added') { added_count += 1 }
322
- store._current_todo.on('changed') { changed_count += 1 }
323
- expect(added_count).to eq(0)
324
- expect(changed_count).to eq(0)
325
-
326
- store._todo_lists << {_name: 'List 1', _todos: []}
327
- store._todo_lists[0]._todos << {_name: 'Todo 1'}
328
-
329
- expect(added_count).to eq(1)
330
- # expect(changed_count).to eq(1)
331
- end
332
246
 
333
247
  it "should not call added too many times" do
334
- a = ReactiveValue.new(Model.new)
248
+ a = Model.new
335
249
  a._list << 1
336
- ac = a._current_list = a._list[0]
337
250
 
338
251
  count = 0
339
- passed_count = 0
340
252
  a._list.on('added') { count += 1 }
341
- a._current_list.on('added') { passed_count += 1 }
342
253
  expect(count).to eq(0)
343
- expect(passed_count).to eq(0)
344
254
 
345
255
  a._list << 2
346
256
  expect(count).to eq(1)
347
- expect(passed_count).to eq(0)
348
257
  end
349
258
 
350
259
  it "should propigate to different branches" do
351
- a = ReactiveValue.new(Model.new)
260
+ a = Model.new
352
261
  count = 0
353
- # a._new_item = {}
354
- a._new_item._name.on('changed') { count += 1 }
355
- expect(count).to eq(0)
262
+ -> do
263
+ count += 1
264
+ a._new_item._name
265
+ end.watch!
266
+ expect(count).to eq(1)
356
267
 
357
268
  a._new_item._name = 'Testing'
358
- # expect(count).to eq(1)
269
+ Computation.flush!
270
+ expect(count).to eq(2)
359
271
  end
360
272
 
361
273
  describe "paths" do
@@ -389,45 +301,35 @@ describe Model do
389
301
  end
390
302
 
391
303
  it "should trigger added when added" do
392
- a = ReactiveValue.new(Model.new)
304
+ a = Model.new
393
305
  count = 0
394
306
  b = a._items
395
307
 
396
308
  b.on('added') { count += 1 }
397
309
  expect(count).to eq(0)
398
310
 
399
- c = b.cur
400
- c << {_name: 'one'}
401
-
402
- # TODO: Without fetching this again, this fails.
403
- c = b.cur
404
-
405
- c << {_name: 'two'}
311
+ b << {_name: 'one'}
312
+ b << {_name: 'two'}
406
313
 
407
314
  expect(count).to eq(2)
408
315
  end
409
316
  end
410
317
 
411
318
  it "should trigger on false assign" do
412
- a = ReactiveValue.new(Model.new)
319
+ a = Model.new
320
+ count = 0
413
321
 
414
- count1 = 0
415
- count2 = 0
322
+ -> { count += 1 ; a._complete }.watch!
416
323
 
417
- b = a._complete
418
- c = a._complete
419
- b.on('changed') { count1 += 1 }
420
- c.on('changed') { count2 += 1 }
421
- expect(count1).to eq(0)
324
+ expect(count).to eq(1)
422
325
 
423
326
  a._complete = true
424
- expect(count1).to eq(1)
425
- expect(count2).to eq(1)
327
+ Computation.flush!
328
+ expect(count).to eq(2)
426
329
 
427
330
  a._complete = false
428
- expect(count1).to eq(2)
429
- expect(count2).to eq(2)
430
-
331
+ Computation.flush!
332
+ expect(count).to eq(3)
431
333
  end
432
334
 
433
335
  it "should delete from an ArrayModel" do
@@ -461,11 +363,11 @@ describe Model do
461
363
  a._items << {_name: 'Test1', _other: {_time: 'Now'}}
462
364
  a._items << {_name: 'Test2', _other: {_time: 'Later'}}
463
365
 
464
- item1 = a._items[0].to_h.cur
366
+ item1 = a._items[0].to_h
465
367
  expect(item1[:_name]).to eq('Test1')
466
368
  expect(item1[:_other][:_time]).to eq('Now')
467
369
 
468
- all_items = a._items.to_a.cur
370
+ all_items = a._items.to_a
469
371
 
470
372
  a = [
471
373
  {:_name => "Test1", :_other => {:_time => "Now"}},
@@ -477,23 +379,23 @@ describe Model do
477
379
 
478
380
  describe "model paths" do
479
381
  before do
480
- @model = ReactiveValue.new(Model.new)
382
+ @model = Model.new
481
383
  end
482
384
 
483
385
  it "should set the model path" do
484
386
  @model._object._name = 'Test'
485
- expect(@model._object.path.cur).to eq([:_object])
387
+ expect(@model._object.path).to eq([:_object])
486
388
  end
487
389
 
488
390
  it "should set the model path for a sub array" do
489
391
  @model._items << {_name: 'Bob'}
490
- expect(@model._items.path.cur).to eq([:_items])
491
- expect(@model._items[0].path.cur).to eq([:_items, :[]])
392
+ expect(@model._items.path).to eq([:_items])
393
+ expect(@model._items[0].path).to eq([:_items, :[]])
492
394
  end
493
395
 
494
396
  it "should set the model path for sub sub arrays" do
495
397
  @model._lists << {_name: 'List 1', _items: []}
496
- expect(@model._lists[0]._items.path.cur).to eq([:_lists, :[], :_items])
398
+ expect(@model._lists[0]._items.path).to eq([:_lists, :[], :_items])
497
399
  end
498
400
 
499
401
  it "should update the path when added from a model instance to a collection" do