volt 0.7.23 → 0.8.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 (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