volt 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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