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,35 @@
1
+ require 'volt/models'
2
+
3
+ class TestCustomClass
4
+ include ReactiveTags
5
+
6
+ tag_method(:cool) do
7
+ destructive!
8
+ end
9
+ end
10
+
11
+ class TestSubClass < TestCustomClass
12
+
13
+ end
14
+
15
+ class TestInherit < TestCustomClass
16
+ tag_method(:cool) do
17
+ pass_reactive!
18
+ end
19
+ end
20
+
21
+ describe ReactiveTags do
22
+ it "should tag correctly" do
23
+ expect(TestCustomClass.new.reactive_method_tag(:cool, :destructive)).to eq(true)
24
+ end
25
+
26
+ it "should include tags in a subclass" do
27
+ expect(TestSubClass.new.reactive_method_tag(:cool, :destructive)).to eq(true)
28
+ expect(TestSubClass.new.reactive_method_tag(:cool, :pass_reactive)).to eq(nil)
29
+ end
30
+
31
+ it "should inherit" do
32
+ expect(TestInherit.new.reactive_method_tag(:cool, :destructive)).to eq(true)
33
+ expect(TestInherit.new.reactive_method_tag(:cool, :pass_reactive)).to eq(true)
34
+ end
35
+ end
@@ -0,0 +1,336 @@
1
+ require 'volt/models'
2
+
3
+ class TestYield
4
+ def call_with_yield
5
+ yield(1)
6
+ yield(2)
7
+ # rescue => e
8
+ # puts "ERROR: #{e.inspect}"
9
+ end
10
+ end
11
+ class SampleClass
12
+ include ReactiveTags
13
+
14
+ tag_method(:break_stuff) do
15
+ destructive!
16
+ end
17
+ def break_stuff
18
+ 5
19
+ end
20
+
21
+ tag_method(:receive_reactive?) do
22
+ pass_reactive!
23
+ end
24
+ def receive_reactive?(arg1)
25
+ return arg1.reactive?
26
+ end
27
+
28
+ def receive_non_reactive?(arg1)
29
+ return arg1.reactive?
30
+ end
31
+
32
+ tag_method(:destructive_receive_non_reactive?) do
33
+ destructive!
34
+ end
35
+ def destructive_receive_non_reactive?(arg1)
36
+ return arg1.reactive?
37
+ end
38
+ end
39
+
40
+
41
+ class SampleTriggerClass
42
+ include ReactiveTags
43
+
44
+ tag_method(:method_that_triggers) { destructive! }
45
+ def method_that_triggers
46
+ trigger!('changed')
47
+ end
48
+ end
49
+
50
+ class SampleNonTriggerClass
51
+ include ReactiveTags
52
+
53
+ tag_method(:method_that_triggers) { destructive! }
54
+ def method_that_triggers
55
+ # does not trigger
56
+ end
57
+ end
58
+
59
+ class SampleTriggerClass2
60
+ include ReactiveTags
61
+
62
+ tag_method(:method_that_triggers) { destructive! }
63
+ def method_that_triggers
64
+ trigger!('other')
65
+ end
66
+ end
67
+
68
+
69
+ describe ReactiveValue do
70
+ describe "the basics" do
71
+ it "should have a with method that returns a new reactive value" do
72
+ a = ReactiveValue.new(1)
73
+ b = a.with { |a| a + 1 }
74
+ expect(a.cur).to eq(1)
75
+ expect(b.cur).to eq(2)
76
+
77
+ a.cur = 5
78
+ expect(b.cur).to eq(6)
79
+ end
80
+
81
+ it "should say its reactive" do
82
+ a = 1
83
+ b = ReactiveValue.new(a)
84
+
85
+ expect(a.reactive?).to eq(false)
86
+ expect(b.reactive?).to eq(true)
87
+ end
88
+
89
+ it "should return a reactive value from any method call" do
90
+ a = ReactiveValue.new(5)
91
+ b = 10
92
+
93
+ c = a + b
94
+ d = b + a
95
+ e = c + d
96
+
97
+ expect(c.reactive?).to eq(true)
98
+ expect(d.reactive?).to eq(true)
99
+ expect(e.reactive?).to eq(true)
100
+ end
101
+
102
+ it "should work with objects not just numbers" do
103
+ a = ReactiveValue.new([1,2,3])
104
+ b = [4]
105
+
106
+ c = a + b
107
+ d = b + a
108
+ e = c + d
109
+
110
+ expect(c.reactive?).to eq(true)
111
+ expect(d.reactive?).to eq(true)
112
+ expect(e.reactive?).to eq(true)
113
+ end
114
+
115
+ it "should return different listeners" do
116
+ a = ReactiveValue.new(1)
117
+
118
+ count = 0
119
+ listener1 = a.on('changed') { count += 1 }
120
+ listener2 = a.on('changed') { count += 1 }
121
+
122
+ expect(listener1).not_to eq(listener2)
123
+ end
124
+
125
+ it "should return a reactive on .is_a?" do
126
+ a = ReactiveValue.new(1)
127
+ b = a.is_a?(Fixnum)
128
+
129
+ expect(b.reactive?).to eq(true)
130
+ expect(b.cur).to eq(true)
131
+ end
132
+
133
+ it "should return true for a nil? on a nil value" do
134
+ a = ReactiveValue.new(nil)
135
+ b = a.nil?
136
+ expect(b.reactive?).to eq(true)
137
+ expect(a.cur).to eq(nil)
138
+
139
+ a = ReactiveValue.new(1)
140
+ b = a.nil?
141
+ expect(b.reactive?).to eq(true)
142
+ expect(a.cur).not_to eq(nil)
143
+ end
144
+ end
145
+
146
+ describe "events" do
147
+ it "should bind and trigger" do
148
+ a = ReactiveValue.new(1)
149
+ count = 0
150
+ a.on('changed') { count += 1 }
151
+ expect(count).to eq(0)
152
+
153
+ a.trigger!('changed')
154
+ expect(count).to eq(1)
155
+ end
156
+
157
+ it "should bind and trigger on children" do
158
+ a = ReactiveValue.new(1)
159
+ b = a + 10
160
+
161
+ count = 0
162
+ b.on('changed') { count += 1 }
163
+ expect(count).to eq(0)
164
+
165
+ a.trigger!('changed')
166
+ expect(count).to eq(1)
167
+ end
168
+
169
+ it "should handle events, even when triggered from the parent" do
170
+ a = ReactiveValue.new(5)
171
+ b = ReactiveValue.new(20)
172
+
173
+ c = a + b
174
+
175
+ @called = false
176
+ c.on('changed') { @called = true }
177
+ expect(@called).to eq(false)
178
+
179
+ a.trigger!('changed')
180
+ expect(@called).to eq(true)
181
+
182
+ @called = false
183
+
184
+ b.trigger!('changed')
185
+ expect(@called).to eq(true)
186
+
187
+ end
188
+ end
189
+
190
+ describe "arrays" do
191
+ it "should add wrapped arrays" do
192
+ a = ReactiveValue.new([1,2])
193
+ b = ReactiveValue.new([3,4])
194
+
195
+ c = a + b
196
+ expect(c.size.cur).to eq(4)
197
+ end
198
+ end
199
+
200
+ describe "tagged methods" do
201
+
202
+ it "should let a class specify methods as destructive" do
203
+ a = ReactiveValue.new(SampleClass.new)
204
+ result = a.break_stuff
205
+ expect(result).to eq(5)
206
+ expect(result.reactive?).to eq(false)
207
+ end
208
+
209
+ it "should pass reactive values when asked" do
210
+ a = ReactiveValue.new(SampleClass.new)
211
+ expect(a.receive_reactive?(ReactiveValue.new(1)).cur).to eq(true)
212
+ end
213
+
214
+ it "should not pass reactive when not asked" do
215
+ a = ReactiveValue.new(SampleClass.new)
216
+ expect(a.receive_non_reactive?(ReactiveValue.new(1)).cur).to eq(false)
217
+ end
218
+
219
+ it "should not pass a reactive value to a destructive method unless it asked for it" do
220
+ a = ReactiveValue.new(SampleClass.new)
221
+ expect(a.destructive_receive_non_reactive?(ReactiveValue.new(1)).cur).to eq(false)
222
+ end
223
+ end
224
+
225
+ describe "triggers from methods" do
226
+
227
+ it "should trigger on any ReactiveValue's that are wrapping it" do
228
+ a = ReactiveValue.new(SampleTriggerClass.new)
229
+
230
+ count = 0
231
+ a.on('changed') { count += 1 }
232
+ expect(count).to eq(0)
233
+
234
+ a.method_that_triggers
235
+ expect(count).to eq(1)
236
+ end
237
+
238
+ it "should trigger on any ReactiveValue's that are wrapping it" do
239
+ a = ReactiveValue.new(SampleNonTriggerClass.new)
240
+
241
+ count = 0
242
+ a.on('changed') { count += 1 }
243
+ expect(count).to eq(0)
244
+
245
+ a.method_that_triggers
246
+ expect(count).to eq(0)
247
+
248
+ a.cur = SampleTriggerClass.new
249
+ expect(count).to eq(1)
250
+
251
+ a.method_that_triggers
252
+ expect(count).to eq(2)
253
+ end
254
+
255
+ it "should trigger the correct event" do
256
+ a = ReactiveValue.new(SampleNonTriggerClass.new)
257
+
258
+ count = 0
259
+ other_count = 0
260
+ a.on('changed') { count += 1 }
261
+ a.on('other') { other_count += 1 }
262
+ expect(count).to eq(0)
263
+
264
+ a.method_that_triggers
265
+ expect(count).to eq(0)
266
+
267
+ a.cur = SampleTriggerClass.new
268
+ expect(count).to eq(1)
269
+
270
+ a.method_that_triggers
271
+ expect(count).to eq(2)
272
+
273
+ # Note: .cur= triggers changed
274
+ a.cur = SampleTriggerClass2.new
275
+ expect(other_count).to eq(0)
276
+
277
+ a.method_that_triggers
278
+ expect(count).to eq(3)
279
+ expect(other_count).to eq(1)
280
+ end
281
+
282
+ it "should trigger through two different paths" do
283
+ source = SampleTriggerClass.new
284
+ a = ReactiveValue.new(source)
285
+ b = ReactiveValue.new(source)
286
+
287
+ count = 0
288
+ count2 = 0
289
+ a.on('changed') { count += 1 }
290
+ b.on('changed') { count2 += 1 }
291
+
292
+ expect(count).to eq(0)
293
+ expect(count2).to eq(0)
294
+
295
+ a.method_that_triggers
296
+
297
+ expect(count).to eq(1)
298
+ expect(count2).to eq(1)
299
+ end
300
+ end
301
+
302
+ it "should setup a ReactiveManager" do
303
+ a = ReactiveValue.new(1)
304
+ expect(a.reactive_manager.class).to eq(ReactiveManager)
305
+ end
306
+
307
+ describe "similar to base object" do
308
+ it "should return a reactive comparator" do
309
+ a = ReactiveValue.new(1)
310
+ b = ReactiveValue.new(2)
311
+
312
+ compare = (a == b)
313
+ expect(compare.cur).to eq(false)
314
+ b.cur = 1
315
+ expect(compare.cur).to eq(true)
316
+ end
317
+ end
318
+
319
+ describe "blocks" do
320
+ before do
321
+
322
+ end
323
+ it "should call blocks through the reactive value, and the returned reactive value should depend on the results of the block" do
324
+ a = ReactiveValue.new(TestYield.new)
325
+
326
+ count = 0
327
+ a.call_with_yield do |value|
328
+ count += 1
329
+ # value.reactive?.should == true
330
+ # value.even?
331
+ end.cur
332
+
333
+ expect(count).to eq(2)
334
+ end
335
+ end
336
+ end
@@ -0,0 +1,57 @@
1
+ require 'volt/models'
2
+
3
+ describe ReactiveValue do
4
+ it "should concat reactive strings" do
5
+ a = ReactiveValue.new('cool')
6
+ b = ReactiveValue.new('beans')
7
+
8
+ c = a + b
9
+ expect(c.cur).to eq('coolbeans')
10
+ expect(c.reactive?).to eq(true)
11
+ end
12
+
13
+ it "should concat reactive and non-reactive" do
14
+ a = ReactiveValue.new('cool')
15
+ b = 'beans'
16
+
17
+ c = a + b
18
+ expect(c.cur).to eq('coolbeans')
19
+ expect(c.reactive?).to eq(true)
20
+ end
21
+
22
+ it "should concat non-reactive and reactive" do
23
+ a = 'cool'
24
+ b = ReactiveValue.new('beans')
25
+
26
+ c = a + b
27
+ expect(c.cur).to eq('coolbeans')
28
+ expect(c.reactive?).to eq(true)
29
+ end
30
+
31
+ if RUBY_PLATFORM != 'opal'
32
+ it "should append reactive to reactive" do
33
+ a = ReactiveValue.new('cool')
34
+ b = ReactiveValue.new('beans')
35
+
36
+ a << b
37
+ expect(a.cur).to eq('coolbeans')
38
+ expect(a.reactive?).to eq(true)
39
+ end
40
+ end
41
+
42
+ it "should raise an exception when appending non-reactive and reactive" do
43
+ a = 'cool'
44
+ b = ReactiveValue.new('beans')
45
+
46
+ exception_count = 0
47
+ begin
48
+ a << b
49
+ rescue => e
50
+ expect(e.message[/Cannot append a reactive/].cur.true?).to eq(true)
51
+ exception_count += 1
52
+ end
53
+
54
+ expect(exception_count).to eq(1)
55
+ end
56
+
57
+ end
@@ -0,0 +1,24 @@
1
+ require 'volt/router/routes'
2
+ require 'volt/models'
3
+
4
+ def routes(&block)
5
+ @routes = Routes.new
6
+ @routes.define(&block)
7
+ end
8
+
9
+ describe Routes do
10
+ it "should match routes" do
11
+ params = Params.new
12
+ params._controller = 'blog'
13
+ params._index = '5'
14
+
15
+ routes do
16
+ get '/', _controller: 'index'
17
+ get '/blog', _controller: 'blog'
18
+ end
19
+
20
+ path, cleaned_params = @routes.url_for_params(params)
21
+ expect(path).to eq('/blog')
22
+ expect(cleaned_params).to eq({_index: '5'})
23
+ end
24
+ end