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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +37 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +23 -0
- data/Readme.md +34 -0
- data/VERSION +1 -0
- data/bin/volt +4 -0
- data/docs/GETTING_STARTED.md +7 -0
- data/docs/GUIDE.md +33 -0
- data/lib/volt.rb +15 -0
- data/lib/volt/benchmark/benchmark.rb +25 -0
- data/lib/volt/cli.rb +34 -0
- data/lib/volt/console.rb +19 -0
- data/lib/volt/controllers/model_controller.rb +29 -0
- data/lib/volt/extra_core/array.rb +10 -0
- data/lib/volt/extra_core/blank.rb +88 -0
- data/lib/volt/extra_core/extra_core.rb +7 -0
- data/lib/volt/extra_core/numeric.rb +9 -0
- data/lib/volt/extra_core/object.rb +36 -0
- data/lib/volt/extra_core/string.rb +29 -0
- data/lib/volt/extra_core/stringify_keys.rb +7 -0
- data/lib/volt/extra_core/true_false.rb +44 -0
- data/lib/volt/extra_core/try.rb +31 -0
- data/lib/volt/models.rb +5 -0
- data/lib/volt/models/array_model.rb +37 -0
- data/lib/volt/models/model.rb +210 -0
- data/lib/volt/models/model_wrapper.rb +23 -0
- data/lib/volt/models/params.rb +67 -0
- data/lib/volt/models/url.rb +192 -0
- data/lib/volt/page/url_tracker.rb +36 -0
- data/lib/volt/reactive/array_extensions.rb +13 -0
- data/lib/volt/reactive/event_chain.rb +126 -0
- data/lib/volt/reactive/events.rb +283 -0
- data/lib/volt/reactive/object_tracker.rb +99 -0
- data/lib/volt/reactive/object_tracking.rb +15 -0
- data/lib/volt/reactive/reactive_array.rb +222 -0
- data/lib/volt/reactive/reactive_tags.rb +64 -0
- data/lib/volt/reactive/reactive_value.rb +368 -0
- data/lib/volt/reactive/string_extensions.rb +34 -0
- data/lib/volt/router/routes.rb +83 -0
- data/lib/volt/server.rb +121 -0
- data/lib/volt/server/binding_setup.rb +2 -0
- data/lib/volt/server/channel_handler.rb +31 -0
- data/lib/volt/server/component_handler.rb +88 -0
- data/lib/volt/server/if_binding_setup.rb +29 -0
- data/lib/volt/server/request_handler.rb +16 -0
- data/lib/volt/server/scope.rb +43 -0
- data/lib/volt/server/source_map_server.rb +31 -0
- data/lib/volt/server/template_parser.rb +452 -0
- data/lib/volt/store/mongo.rb +5 -0
- data/lib/volt/templates/attribute_binding.rb +110 -0
- data/lib/volt/templates/base_binding.rb +37 -0
- data/lib/volt/templates/channel.rb +48 -0
- data/lib/volt/templates/content_binding.rb +35 -0
- data/lib/volt/templates/document_events.rb +80 -0
- data/lib/volt/templates/each_binding.rb +115 -0
- data/lib/volt/templates/event_binding.rb +51 -0
- data/lib/volt/templates/if_binding.rb +74 -0
- data/lib/volt/templates/memory_test.rb +26 -0
- data/lib/volt/templates/page.rb +146 -0
- data/lib/volt/templates/reactive_template.rb +38 -0
- data/lib/volt/templates/render_queue.rb +5 -0
- data/lib/volt/templates/sub_context.rb +23 -0
- data/lib/volt/templates/targets/attribute_section.rb +33 -0
- data/lib/volt/templates/targets/attribute_target.rb +18 -0
- data/lib/volt/templates/targets/base_section.rb +14 -0
- data/lib/volt/templates/targets/binding_document/base_node.rb +3 -0
- data/lib/volt/templates/targets/binding_document/component_node.rb +112 -0
- data/lib/volt/templates/targets/binding_document/html_node.rb +11 -0
- data/lib/volt/templates/targets/dom_section.rb +147 -0
- data/lib/volt/templates/targets/dom_target.rb +11 -0
- data/lib/volt/templates/template_binding.rb +159 -0
- data/lib/volt/templates/template_renderer.rb +50 -0
- data/spec/models/event_chain_spec.rb +129 -0
- data/spec/models/model_spec.rb +340 -0
- data/spec/models/old_model_spec.rb +109 -0
- data/spec/models/reactive_array_spec.rb +262 -0
- data/spec/models/reactive_tags_spec.rb +35 -0
- data/spec/models/reactive_value_spec.rb +336 -0
- data/spec/models/string_extensions_spec.rb +57 -0
- data/spec/router/routes_spec.rb +24 -0
- data/spec/server/template_parser_spec.rb +50 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/store/mongo_spec.rb +4 -0
- data/spec/templates/targets/binding_document/component_node_spec.rb +18 -0
- data/spec/templates/template_binding_spec.rb +98 -0
- data/templates/.gitignore +12 -0
- data/templates/Gemfile.tt +8 -0
- data/templates/app/.empty_directory +0 -0
- data/templates/app/home/config/routes.rb +1 -0
- data/templates/app/home/controllers/index_controller.rb +5 -0
- data/templates/app/home/css/.empty_directory +0 -0
- data/templates/app/home/models/.empty_directory +0 -0
- data/templates/app/home/views/index/about.html +9 -0
- data/templates/app/home/views/index/home.html +7 -0
- data/templates/app/home/views/index/index.html +28 -0
- data/templates/config.ru +4 -0
- data/templates/public/css/ansi.css +0 -0
- data/templates/public/css/bootstrap-theme.css +459 -0
- data/templates/public/css/bootstrap.css +7098 -0
- data/templates/public/css/jumbotron.css +79 -0
- data/templates/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/templates/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/templates/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/templates/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/templates/public/index.html +25 -0
- data/templates/public/js/bootstrap.js +0 -0
- data/templates/public/js/jquery-2.0.3.js +8829 -0
- data/templates/public/js/sockjs-0.2.1.min.js +27 -0
- data/templates/spec/spec_helper.rb +20 -0
- data/volt.gemspec +41 -0
- 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
|