volt 0.2.3

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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +37 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.txt +22 -0
  8. data/Rakefile +23 -0
  9. data/Readme.md +34 -0
  10. data/VERSION +1 -0
  11. data/bin/volt +4 -0
  12. data/docs/GETTING_STARTED.md +7 -0
  13. data/docs/GUIDE.md +33 -0
  14. data/lib/volt.rb +15 -0
  15. data/lib/volt/benchmark/benchmark.rb +25 -0
  16. data/lib/volt/cli.rb +34 -0
  17. data/lib/volt/console.rb +19 -0
  18. data/lib/volt/controllers/model_controller.rb +29 -0
  19. data/lib/volt/extra_core/array.rb +10 -0
  20. data/lib/volt/extra_core/blank.rb +88 -0
  21. data/lib/volt/extra_core/extra_core.rb +7 -0
  22. data/lib/volt/extra_core/numeric.rb +9 -0
  23. data/lib/volt/extra_core/object.rb +36 -0
  24. data/lib/volt/extra_core/string.rb +29 -0
  25. data/lib/volt/extra_core/stringify_keys.rb +7 -0
  26. data/lib/volt/extra_core/true_false.rb +44 -0
  27. data/lib/volt/extra_core/try.rb +31 -0
  28. data/lib/volt/models.rb +5 -0
  29. data/lib/volt/models/array_model.rb +37 -0
  30. data/lib/volt/models/model.rb +210 -0
  31. data/lib/volt/models/model_wrapper.rb +23 -0
  32. data/lib/volt/models/params.rb +67 -0
  33. data/lib/volt/models/url.rb +192 -0
  34. data/lib/volt/page/url_tracker.rb +36 -0
  35. data/lib/volt/reactive/array_extensions.rb +13 -0
  36. data/lib/volt/reactive/event_chain.rb +126 -0
  37. data/lib/volt/reactive/events.rb +283 -0
  38. data/lib/volt/reactive/object_tracker.rb +99 -0
  39. data/lib/volt/reactive/object_tracking.rb +15 -0
  40. data/lib/volt/reactive/reactive_array.rb +222 -0
  41. data/lib/volt/reactive/reactive_tags.rb +64 -0
  42. data/lib/volt/reactive/reactive_value.rb +368 -0
  43. data/lib/volt/reactive/string_extensions.rb +34 -0
  44. data/lib/volt/router/routes.rb +83 -0
  45. data/lib/volt/server.rb +121 -0
  46. data/lib/volt/server/binding_setup.rb +2 -0
  47. data/lib/volt/server/channel_handler.rb +31 -0
  48. data/lib/volt/server/component_handler.rb +88 -0
  49. data/lib/volt/server/if_binding_setup.rb +29 -0
  50. data/lib/volt/server/request_handler.rb +16 -0
  51. data/lib/volt/server/scope.rb +43 -0
  52. data/lib/volt/server/source_map_server.rb +31 -0
  53. data/lib/volt/server/template_parser.rb +452 -0
  54. data/lib/volt/store/mongo.rb +5 -0
  55. data/lib/volt/templates/attribute_binding.rb +110 -0
  56. data/lib/volt/templates/base_binding.rb +37 -0
  57. data/lib/volt/templates/channel.rb +48 -0
  58. data/lib/volt/templates/content_binding.rb +35 -0
  59. data/lib/volt/templates/document_events.rb +80 -0
  60. data/lib/volt/templates/each_binding.rb +115 -0
  61. data/lib/volt/templates/event_binding.rb +51 -0
  62. data/lib/volt/templates/if_binding.rb +74 -0
  63. data/lib/volt/templates/memory_test.rb +26 -0
  64. data/lib/volt/templates/page.rb +146 -0
  65. data/lib/volt/templates/reactive_template.rb +38 -0
  66. data/lib/volt/templates/render_queue.rb +5 -0
  67. data/lib/volt/templates/sub_context.rb +23 -0
  68. data/lib/volt/templates/targets/attribute_section.rb +33 -0
  69. data/lib/volt/templates/targets/attribute_target.rb +18 -0
  70. data/lib/volt/templates/targets/base_section.rb +14 -0
  71. data/lib/volt/templates/targets/binding_document/base_node.rb +3 -0
  72. data/lib/volt/templates/targets/binding_document/component_node.rb +112 -0
  73. data/lib/volt/templates/targets/binding_document/html_node.rb +11 -0
  74. data/lib/volt/templates/targets/dom_section.rb +147 -0
  75. data/lib/volt/templates/targets/dom_target.rb +11 -0
  76. data/lib/volt/templates/template_binding.rb +159 -0
  77. data/lib/volt/templates/template_renderer.rb +50 -0
  78. data/spec/models/event_chain_spec.rb +129 -0
  79. data/spec/models/model_spec.rb +340 -0
  80. data/spec/models/old_model_spec.rb +109 -0
  81. data/spec/models/reactive_array_spec.rb +262 -0
  82. data/spec/models/reactive_tags_spec.rb +35 -0
  83. data/spec/models/reactive_value_spec.rb +336 -0
  84. data/spec/models/string_extensions_spec.rb +57 -0
  85. data/spec/router/routes_spec.rb +24 -0
  86. data/spec/server/template_parser_spec.rb +50 -0
  87. data/spec/spec_helper.rb +20 -0
  88. data/spec/store/mongo_spec.rb +4 -0
  89. data/spec/templates/targets/binding_document/component_node_spec.rb +18 -0
  90. data/spec/templates/template_binding_spec.rb +98 -0
  91. data/templates/.gitignore +12 -0
  92. data/templates/Gemfile.tt +8 -0
  93. data/templates/app/.empty_directory +0 -0
  94. data/templates/app/home/config/routes.rb +1 -0
  95. data/templates/app/home/controllers/index_controller.rb +5 -0
  96. data/templates/app/home/css/.empty_directory +0 -0
  97. data/templates/app/home/models/.empty_directory +0 -0
  98. data/templates/app/home/views/index/about.html +9 -0
  99. data/templates/app/home/views/index/home.html +7 -0
  100. data/templates/app/home/views/index/index.html +28 -0
  101. data/templates/config.ru +4 -0
  102. data/templates/public/css/ansi.css +0 -0
  103. data/templates/public/css/bootstrap-theme.css +459 -0
  104. data/templates/public/css/bootstrap.css +7098 -0
  105. data/templates/public/css/jumbotron.css +79 -0
  106. data/templates/public/fonts/glyphicons-halflings-regular.eot +0 -0
  107. data/templates/public/fonts/glyphicons-halflings-regular.svg +229 -0
  108. data/templates/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  109. data/templates/public/fonts/glyphicons-halflings-regular.woff +0 -0
  110. data/templates/public/index.html +25 -0
  111. data/templates/public/js/bootstrap.js +0 -0
  112. data/templates/public/js/jquery-2.0.3.js +8829 -0
  113. data/templates/public/js/sockjs-0.2.1.min.js +27 -0
  114. data/templates/spec/spec_helper.rb +20 -0
  115. data/volt.gemspec +41 -0
  116. metadata +412 -0
@@ -0,0 +1,340 @@
1
+ require 'volt/models'
2
+
3
+ describe Model do
4
+
5
+ it "should allow _ methods to be used to store values without predefining them" do
6
+ a = Model.new
7
+ a._stash = 'yes'
8
+
9
+ expect(a._stash).to eq('yes')
10
+ end
11
+
12
+ it "should update other values off the same model" do
13
+ a = ReactiveValue.new(Model.new)
14
+ count = 0
15
+ a._name.on('changed') { count += 1 }
16
+ expect(count).to eq(0)
17
+
18
+ a._name = 'Bob'
19
+ expect(count).to eq(1)
20
+ end
21
+
22
+ it "should say unregistered attributes are nil" do
23
+ a = ReactiveValue.new(Model.new)
24
+ b = a._missing == nil
25
+ expect(b.cur).to eq(true)
26
+ end
27
+
28
+ it "should negate nil and false correctly" do
29
+ a = ReactiveValue.new(Model.new)
30
+ expect((!a._missing).cur).to eq(true)
31
+
32
+ a._mis1 = nil
33
+ a._false1 = false
34
+
35
+ expect((!a._mis1).cur).to eq(true)
36
+ expect((!a._false1).cur).to eq(true)
37
+ end
38
+
39
+ it "should return a nil model for an underscore value that doesn't exist" do
40
+ a = Model.new
41
+ expect(a._something.cur.attributes).to eq(nil)
42
+ end
43
+
44
+ it "should let you bind before something is defined" do
45
+ a = ReactiveValue.new(Model.new)
46
+
47
+ b = a._one + 5
48
+ expect(b.cur.class).to eq(NoMethodError)
49
+
50
+ count = 0
51
+ b.on('changed') { count += 1 }
52
+ expect(count).to eq(0)
53
+
54
+ a._one = 1
55
+ expect(count).to eq(1)
56
+ expect(b.cur).to eq(6)
57
+ end
58
+
59
+ it "should let you access an array element before its defined" do
60
+ # TODO: ...
61
+ end
62
+
63
+ it "should trigger changed once when a new value is assigned." do
64
+ a = ReactiveValue.new(Model.new)
65
+
66
+ count = 0
67
+ a._blue.on('changed') { count += 1 }
68
+
69
+ a._blue = 'one'
70
+ expect(count).to eq(1)
71
+ a._blue = 'two'
72
+ expect(count).to eq(2)
73
+ end
74
+
75
+ it "should not call changed on other attributes" do
76
+ a = ReactiveValue.new(Model.new)
77
+
78
+ count = 0
79
+ a._blue.on('changed') { count += 1 }
80
+ expect(count).to eq(0)
81
+
82
+ a._green = 'one'
83
+ expect(count).to eq(0)
84
+
85
+ a._blue = 'two'
86
+ expect(count).to eq(1)
87
+
88
+ end
89
+
90
+ it "should call change through arguments" do
91
+ a = ReactiveValue.new(Model.new)
92
+ a._one = 1
93
+ a._two = 2
94
+
95
+ c = a._one + a._two
96
+
97
+ count = 0
98
+ c.on('changed') { count += 1}
99
+ expect(count).to eq(0)
100
+
101
+ a._two = 5
102
+ expect(count).to eq(1)
103
+
104
+ expect(c.cur).to eq(6)
105
+ end
106
+
107
+ it "should store reactive values in arrays and trigger updates when those values change" do
108
+ a = ReactiveValue.new(Model.new)
109
+ b = ReactiveValue.new('blue')
110
+ a._one = 1
111
+ a._items << 0
112
+
113
+ count_1 = 0
114
+ a._items[1].on('changed') { count_1 += 1 }
115
+ expect(count_1).to eq(0)
116
+
117
+ a._items << b
118
+ expect(count_1).to eq(1)
119
+
120
+ b.cur = 'update'
121
+ expect(count_1).to eq(2)
122
+
123
+ count_2 = 0
124
+ a._items[2].on('changed') { count_2 += 1 }
125
+ expect(count_2).to eq(0)
126
+
127
+ a._items << a._one
128
+ expect(count_2).to eq(1)
129
+
130
+ a._one = 'updated'
131
+ expect(count_1).to eq(2)
132
+ expect(count_2).to eq(2)
133
+ end
134
+
135
+ it "should let you register events before it expands" do
136
+ a = ReactiveValue.new(Model.new)
137
+ count = 0
138
+ a._something.on('changed') { count += 1 }
139
+ expect(count).to eq(0)
140
+
141
+ a._something = 20
142
+ expect(count).to eq(1)
143
+ end
144
+
145
+ it "should trigger changed through concat" do
146
+ model = ReactiveValue.new(Model.new)
147
+
148
+ concat = model._one + model._two
149
+
150
+ count = 0
151
+ concat.on('changed') { count += 1 }
152
+ expect(count).to eq(0)
153
+
154
+ model._one = 'one'
155
+ expect(count).to eq(1)
156
+
157
+ model._two = 'two'
158
+ expect(count).to eq(2)
159
+
160
+ expect(concat.cur).to eq('onetwo')
161
+ end
162
+
163
+ it "should allow a reactive value to be assigned as a value in a model" do
164
+ model = ReactiveValue.new(Model.new)
165
+
166
+ model._items << {_name: 'One'}
167
+ model._items << {_name: 'Two'}
168
+
169
+ current = model._items[model._index]
170
+
171
+ model._current_item = current
172
+ end
173
+
174
+ it "should trigger changed for any indicies after a deleted index" do
175
+ model = ReactiveValue.new(Model.new)
176
+
177
+ model._items << {_name: 'One'}
178
+ model._items << {_name: 'Two'}
179
+ model._items << {_name: 'Three'}
180
+
181
+ count = 0
182
+ model._items[2].on('changed') { count += 1 }
183
+ expect(count).to eq(0)
184
+
185
+ model._items.delete_at(1)
186
+ expect(count).to eq(1)
187
+ end
188
+
189
+ it "should change the size and length when an item gets added" do
190
+ model = ReactiveValue.new(Model.new)
191
+
192
+ model._items << {_name: 'One'}
193
+ size = model._items.size
194
+ length = model._items.length
195
+
196
+ count_size = 0
197
+ count_length = 0
198
+ size.on('changed') { count_size += 1 }
199
+ length.on('changed') { count_length += 1 }
200
+ expect(count_size).to eq(0)
201
+ expect(count_length).to eq(0)
202
+
203
+ model._items << {_name: 'Two'}
204
+ expect(count_size).to eq(1)
205
+ expect(count_length).to eq(1)
206
+ end
207
+
208
+ it "should add doubly nested arrays" do
209
+ model = ReactiveValue.new(Model.new)
210
+
211
+ model._items << {_name: 'Cool', _lists: []}
212
+ model._items[0]._lists << {_name: 'worked'}
213
+ expect(model._items[0]._lists[0]._name.cur).to eq('worked')
214
+ end
215
+
216
+ it "should make pushed subarrays into ArrayModels" do
217
+ model = ReactiveValue.new(Model.new)
218
+
219
+ model._items << {_name: 'Test', _lists: []}
220
+ expect(model._items[0]._lists.cur.class).to eq(ArrayModel)
221
+ end
222
+
223
+ it "should make assigned subarrays into ArrayModels" do
224
+ model = ReactiveValue.new(Model.new)
225
+
226
+ model._item._name = 'Test'
227
+ model._item._lists = []
228
+ expect(model._item._lists.cur.class).to eq(ArrayModel)
229
+ end
230
+
231
+ # it "should call changed when a the reference to a submodel is assigned to another value" do
232
+ # a = ReactiveValue.new(Model.new)
233
+ #
234
+ # count = 0
235
+ # a._blue._green.on('changed') { count += 1 }
236
+ # count.should == 0
237
+ #
238
+ # a._blue._green = 5
239
+ # count.should == 1
240
+ #
241
+ # a._blue = 22
242
+ # count.should == 2
243
+ # end
244
+
245
+ it "should trigger changed when a value is deleted" do
246
+ a = ReactiveValue.new(Model.new)
247
+
248
+ count = 0
249
+ a._blue.on('changed') { count += 1 }
250
+ expect(count).to eq(0)
251
+
252
+ a._blue = 1
253
+ expect(count).to eq(1)
254
+
255
+ a.delete(:_blue)
256
+ expect(count).to eq(2)
257
+ end
258
+
259
+ it "should not trigger a change if the new value is exactly the same" do
260
+
261
+ end
262
+
263
+
264
+ it "should work" do
265
+ store = ReactiveValue.new(Model.new)
266
+ # params = ReactiveValue.new(Params.new)
267
+ index = ReactiveValue.new(0)
268
+
269
+ a = store._todo_lists
270
+ store._current_todo = a#[index]
271
+
272
+ added_count = 0
273
+ changed_count = 0
274
+ # store._todo_lists.on('added') { added_count += 1 }
275
+ store._current_todo.on('changed') { puts "CHANGED TRIGGERED" ; changed_count += 1 }
276
+ # expect(added_count).to eq(0)
277
+ expect(changed_count).to eq(0)
278
+
279
+ puts "Append-----------"
280
+ a.cur = 1000
281
+ # store._todo_lists << {_name: 'List 1', _todos: []}
282
+
283
+
284
+ # store._todo_lists[0]._todos << {_name: 'Todo 1'}
285
+
286
+ # expect(added_count).to eq(1)
287
+ # expect(changed_count).to eq(1)
288
+ end
289
+
290
+ it "should handle a basic todo list exvoltle with no setup" do
291
+ store = ReactiveValue.new(Model.new)
292
+ params = ReactiveValue.new(Params.new)
293
+
294
+ a = store._todo_lists
295
+ store._current_todo = store._todo_lists[params._index.or(0).to_i]
296
+
297
+ added_count = 0
298
+ changed_count = 0
299
+ store._todo_lists.on('added') { added_count += 1 }
300
+ store._current_todo.on('changed') { changed_count += 1 }
301
+ expect(added_count).to eq(0)
302
+ expect(changed_count).to eq(0)
303
+
304
+ store._todo_lists << {_name: 'List 1', _todos: []}
305
+ store._todo_lists[0]._todos << {_name: 'Todo 1'}
306
+
307
+ expect(added_count).to eq(1)
308
+ # expect(changed_count).to eq(1)
309
+ end
310
+
311
+ it "should not call added too many times" do
312
+ a = ReactiveValue.new(Model.new)
313
+ a._list << 1
314
+ ac = a._current_list = a._list[0]
315
+
316
+ count = 0
317
+ passed_count = 0
318
+ a._list.on('added') { count += 1 }
319
+ a._current_list.on('added') { passed_count += 1 }
320
+ expect(count).to eq(0)
321
+ expect(passed_count).to eq(0)
322
+
323
+ # puts a._list.cur.event_followers.inspect
324
+
325
+ a._list << 2
326
+ expect(count).to eq(1)
327
+ expect(passed_count).to eq(0)
328
+ end
329
+
330
+ it "should propigate to different branches" do
331
+ a = ReactiveValue.new(Model.new)
332
+ count = 0
333
+ # a._new_item = {}
334
+ a._new_item._name.on('changed') { count += 1 }
335
+ expect(count).to eq(0)
336
+
337
+ a._new_item._name = 'Testing'
338
+ # expect(count).to eq(1)
339
+ end
340
+ end
@@ -0,0 +1,109 @@
1
+ # # require 'volt/spec_helper'
2
+ # require 'volt/models'
3
+ #
4
+ # describe Model do
5
+ #
6
+ # describe "model paths" do
7
+ # before do
8
+ # @model = ReactiveValue.new(Model.new)
9
+ # end
10
+ #
11
+ # it "should set the model path" do
12
+ # @model._object._name = 'Test'
13
+ # @model._object.path.cur.should == ['_object']
14
+ # end
15
+ #
16
+ # it "should set the model path for a sub array" do
17
+ # @model._items << {_name: 'Bob'}
18
+ # @model._items.path.cur.should == ['_items']
19
+ # @model._items[0].path.cur.should == ['_items', '[]']
20
+ # end
21
+ #
22
+ # it "should set the model path for sub sub arrays" do
23
+ # @model._lists << {_name: 'List 1', _items: []}
24
+ # @model._lists[0]._items.path.cur.should == ['_lists', '[]', '_items']
25
+ # end
26
+ # end
27
+ #
28
+ #
29
+ # describe "paths" do
30
+ # before do
31
+ # @model = ReactiveValue.new(Model.new({}, nil, 'model'))
32
+ # end
33
+ #
34
+ # it "should track paths" do
35
+ # @model._test.path.cur.should == ['model', '_test']
36
+ # end
37
+ #
38
+ # it "should track nested paths" do
39
+ # @model._test._blue.path.cur.should == ['model', '_test', '_blue']
40
+ # end
41
+ #
42
+ # it "should track paths with array lookup's" do
43
+ # @model._test._green << {}
44
+ # @model._test._green.path.cur.should == ['model', '_test', '_green']
45
+ # @model._test._green[0].path.cur.should == ['model', '_test', '_green', '[]']
46
+ # end
47
+ # end
48
+ #
49
+ # describe "user models" do
50
+ # class User < Model
51
+ # def full_name
52
+ # _first_name + _last_name
53
+ # end
54
+ # end
55
+ #
56
+ # class Info < Model ; end
57
+ #
58
+ # class Todo < Model ; end
59
+ #
60
+ # before do
61
+ # class_models = {
62
+ # ['*', '_user'] => User,
63
+ # ['*', '_info'] => Info,
64
+ # ['*', '_todo'] => Todo
65
+ # }
66
+ #
67
+ # @model = ReactiveValue.new(Model.new({}, nil, 'page', class_models))
68
+ # end
69
+ #
70
+ # it "should be loaded as the correct class" do
71
+ # @model._users << {_name: 'Test'}
72
+ # @model._users[0].cur.is_a?(User).should == true
73
+ # end
74
+ #
75
+ # it "should be loaded in as the correct class for single items" do
76
+ # @model._info._total_users = 5
77
+ # @model._info.cur.is_a?(Info).should == true
78
+ # end
79
+ #
80
+ # it "should load the correct nested class" do
81
+ # @model._todo_lists << {_name: 'Test1', _todos: []}
82
+ # @model._todo_lists[0]._todos << {_label: 'Do something'}
83
+ # @model._todo_lists[0]._todos[0].cur.is_a?(Todo).should == true
84
+ # end
85
+ #
86
+ # it "should assume the default model if used incorrectly" do
87
+ # @model._infos._something = 10
88
+ # @model._infos.cur.is_a?(Info).should == false
89
+ # end
90
+ #
91
+ # it "should keep lookups as children for any looked up value" do
92
+ # @model._users << {_first_name: 'Jim', _last_name: 'Bob'}
93
+ #
94
+ # @model._users.last.cur.is_a?(User).should == true
95
+ # # @model._users.last.full_name.dependents.parents.size.should == 2
96
+ # end
97
+ #
98
+ # it "should call changed on methods that depend on other values" do
99
+ # @model._users << {_first_name: 'Jim', _last_name: 'Bob'}
100
+ #
101
+ # count = 0
102
+ # @model._users.last.full_name.on('changed') { count += 1 }
103
+ # count.should == 0
104
+ #
105
+ # @model._users.last._first_name = 'James'
106
+ # count.should == 1
107
+ # end
108
+ # end
109
+ # end
@@ -0,0 +1,262 @@
1
+ require 'volt/models'
2
+
3
+ describe ReactiveArray do
4
+ it "should trigger a change event on any ReactiveValues derived from items in the array" do
5
+ model = ReactiveValue.new(Model.new)
6
+
7
+ model._my_ary = [1,2,3]
8
+
9
+ array_one_item = model._my_ary[4]
10
+
11
+ @changed = false
12
+ array_one_item.on('changed') { @changed = true }
13
+ expect(@changed).to eq(false)
14
+
15
+ model._my_ary.insert(0,1,2)
16
+
17
+ expect(@changed).to eq(true)
18
+ end
19
+
20
+ it "should trigger changed on methods of an array model that involve just one cell" do
21
+ model = ReactiveValue.new(ReactiveArray.new)
22
+
23
+ model << 1
24
+ model << 2
25
+ model << 3
26
+
27
+ max = model.max
28
+ expect(max.cur).to eq(3)
29
+
30
+ count = 0
31
+ max.on('changed') { count += 1 }
32
+ expect(count).to eq(0)
33
+
34
+ model[0] = 10
35
+
36
+ expect(count).to eq(1)
37
+ expect(max.cur).to eq(10)
38
+ end
39
+
40
+ it "should not trigger changed events on cells that are not being updated" do
41
+ model = ReactiveValue.new(ArrayModel.new([]))
42
+
43
+ model << 1
44
+ model << 2
45
+ model << 3
46
+
47
+ index_0_count = 0
48
+ last_count = 0
49
+ sum_count = 0
50
+ model[0].on('changed') { index_0_count += 1 }
51
+ model.last.on('changed') { last_count += 1 }
52
+ model.sum.on('changed') { sum_count += 1 }
53
+ model[1] = 20
54
+
55
+ expect(index_0_count).to eq(0)
56
+ expect(sum_count).to eq(1)
57
+ expect(last_count).to eq(0)
58
+
59
+ expect(model[0].cur).to eq(1)
60
+ expect(model[1].cur).to eq(20)
61
+ expect(model[2].cur).to eq(3)
62
+ expect(model.last.cur).to eq(3)
63
+ expect(model.sum.cur).to eq(24)
64
+
65
+ model[2] = 100
66
+ expect(last_count).to eq(1)
67
+ end
68
+
69
+ it "should trigger added when an element is added" do
70
+ a = ReactiveValue.new(Model.new)
71
+ count = 0
72
+ a._items.on('added') { count += 1 }
73
+ expect(count).to eq(0)
74
+
75
+ a._items << 1
76
+ expect(count).to eq(1)
77
+ end
78
+
79
+ it "should trigger updates when appending" do
80
+ [:size, :length, :count, :last].each do |attribute|
81
+ a = ReactiveValue.new(ReactiveArray.new([1,2,3]))
82
+
83
+ count = 0
84
+ val = a.send(attribute)
85
+ old_value = val.cur
86
+ val.on('changed') { count += 1 }
87
+ expect(count).to eq(0)
88
+
89
+ added_count = 0
90
+ a.on('added') { added_count += 1 }
91
+ expect(added_count).to eq(0)
92
+
93
+ a << 4
94
+
95
+ expect(val.cur).to eq(old_value + 1)
96
+ expect(count).to eq(1)
97
+
98
+ expect(added_count).to eq(1)
99
+ end
100
+ end
101
+
102
+ describe "real world type specs" do
103
+ it "should let you add in another array" do
104
+ a = ReactiveValue.new(ReactiveArray.new([1,2,3]))
105
+
106
+ pos_4 = a[4]
107
+ expect(pos_4.cur).to eq(nil)
108
+ pos_4_changed = 0
109
+ pos_4.on('changed') { pos_4_changed += 1 }
110
+
111
+ count = 0
112
+ a.on('added') { count += 1 }
113
+
114
+ a += [4,5,6]
115
+ expect(a.cur).to eq([1,2,3,4,5,6])
116
+ expect(pos_4_changed).to eq(1)
117
+
118
+ expect(count).to eq(3)
119
+ end
120
+
121
+ it "should trigger changes when an index that is Reactive changes" do
122
+ index = ReactiveValue.new(0)
123
+ model = ReactiveValue.new(Model.new)
124
+ model._array << 1
125
+ model._array << 2
126
+ model._array << 3
127
+ b = model._array[index]
128
+
129
+ direct_count = 0
130
+ b.on('changed') { direct_count += 1 }
131
+ expect(direct_count).to eq(0)
132
+
133
+ model._current_array = b
134
+
135
+ count = 0
136
+
137
+ model._current_array.on('changed') { count += 1 }
138
+ expect(count).to eq(0)
139
+
140
+ index.cur = 1
141
+ expect(count).to eq(1)
142
+ expect(direct_count).to eq(1)
143
+ end
144
+
145
+ it "should trigger changes when cell data changes when using ReactiveValue's as indicies" do
146
+ index = ReactiveValue.new(0)
147
+ index2 = ReactiveValue.new(0)
148
+ model = ReactiveValue.new(Model.new)
149
+ model._array << 1
150
+ model._array << 2
151
+ model._array << 3
152
+
153
+ zero_cell = model._array[index]
154
+ zero_cell2 = model._array[index2]
155
+
156
+ count = 0
157
+ count2 = 0
158
+ zero_cell.on('changed') { count += 1 }
159
+ zero_cell2.on('changed') { count2 += 1 }
160
+
161
+ zero_cell.cur = 3
162
+
163
+ expect(count).to eq(1)
164
+ expect(count2).to eq(1)
165
+ end
166
+
167
+
168
+ it "should call added on an array within an array" do
169
+ a = ReactiveValue.new(Model.new)
170
+ index = ReactiveValue.new(0)
171
+ count = 0
172
+ a._items << ArrayModel.new([])
173
+
174
+ a._items[0].on('added') { count += 1 }
175
+ expect(count).to eq(0)
176
+
177
+ a._items[0] << 1
178
+ expect(count).to eq(1)
179
+
180
+ end
181
+
182
+ it "should call added through an index from one array to a sub array" do
183
+ model = ReactiveValue.new(Model.new)
184
+ index = ReactiveValue.new(nil)
185
+
186
+ count = 0
187
+ model._current_todo._todos.on('added') { count += 1 }
188
+ # model._current_todo._todos.on('changed') { puts "AC" }
189
+ expect(count).to eq(0)
190
+
191
+ model._todo_lists << Model.new(_name: 'One', _todos: [])
192
+ model._todo_lists << Model.new(_name: 'Two', _todos: [])
193
+
194
+ model._current_todo = model._todo_lists[0]
195
+
196
+ # model.trigger!('added')
197
+ model._current_todo._todos << "Svoltle todo"
198
+ expect(count).to eq(1)
199
+ end
200
+
201
+ it "should trigger changed when an item is deleted" do
202
+ model = ReactiveValue.new(Model.new)
203
+ model._items = [1,2,3]
204
+
205
+ cur = model._current = model._items[0]
206
+
207
+ count = 0
208
+ # model._items[0].on('changed') { count += 1}
209
+ model._current.on('changed') { count += 1 }
210
+ expect(count).to eq(0)
211
+
212
+ ObjectTracker.process_queue
213
+ model._items.delete_at(0)
214
+
215
+ expect(count).to eq(1)
216
+ end
217
+
218
+ it "should not trigger changed on the array when an element is added" do
219
+ a = ReactiveValue.new(Model.new)
220
+ a._items = []
221
+
222
+ count = 0
223
+ a._items.on('changed') { count += 1}
224
+ expect(count).to eq(0)
225
+
226
+ a._items << 1
227
+ expect(count).to eq(0)
228
+ end
229
+
230
+ it "should trigger changed for a Reactive index and a non-reactive index with the same value" do
231
+ a = ReactiveValue.new(Model.new)
232
+ index = ReactiveValue.new(0)
233
+ a._items << 0
234
+ a._items << 1
235
+
236
+ count = 0
237
+ a._items[0].on('changed') { count += 1 }
238
+ expect(count).to eq(0)
239
+
240
+ a._items[index] = 5
241
+ expect(count).to eq(1)
242
+
243
+ # Reversed
244
+ count2 = 0
245
+ a._items[index].on('changed') { count2 += 1 }
246
+ expect(count2).to eq(0)
247
+
248
+ index.cur = 1
249
+
250
+ # Double update since one is bound to a Integer and one to a ReactiveValue
251
+ # TODO: Any way to combine these
252
+ expect(count2).to eq(2)
253
+
254
+ a._items[1] = 2
255
+ expect(count2).to eq(3)
256
+
257
+ # a._items[index] = 10
258
+
259
+
260
+ end
261
+ end
262
+ end