volt 0.8.14 → 0.8.15

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Readme.md +8 -2
  4. data/VERSION +1 -1
  5. data/app/volt/controllers/notices_controller.rb +1 -1
  6. data/app/volt/models/user.rb +2 -2
  7. data/app/volt/tasks/live_query/live_query_pool.rb +1 -1
  8. data/app/volt/tasks/query_tasks.rb +1 -1
  9. data/app/volt/tasks/store_tasks.rb +1 -1
  10. data/app/volt/tasks/user_tasks.rb +2 -2
  11. data/lib/volt/boot.rb +2 -2
  12. data/lib/volt/cli/asset_compile.rb +31 -27
  13. data/lib/volt/cli.rb +64 -65
  14. data/lib/volt/config.rb +25 -23
  15. data/lib/volt/console.rb +17 -16
  16. data/lib/volt/controllers/model_controller.rb +82 -80
  17. data/lib/volt/data_stores/data_store.rb +2 -2
  18. data/lib/volt/data_stores/mongo_driver.rb +2 -2
  19. data/lib/volt/extra_core/inflections.rb +2 -2
  20. data/lib/volt/extra_core/inflector/inflections.rb +185 -183
  21. data/lib/volt/extra_core/inflector/methods.rb +50 -48
  22. data/lib/volt/extra_core/string.rb +2 -2
  23. data/lib/volt/models/array_model.rb +93 -92
  24. data/lib/volt/models/cursor.rb +3 -2
  25. data/lib/volt/models/model.rb +248 -251
  26. data/lib/volt/models/model_hash_behaviour.rb +44 -44
  27. data/lib/volt/models/model_helpers.rb +38 -36
  28. data/lib/volt/models/model_state.rb +16 -17
  29. data/lib/volt/models/model_wrapper.rb +25 -24
  30. data/lib/volt/models/persistors/array_store.rb +145 -143
  31. data/lib/volt/models/persistors/base.rb +18 -16
  32. data/lib/volt/models/persistors/flash.rb +24 -22
  33. data/lib/volt/models/persistors/local_store.rb +46 -44
  34. data/lib/volt/models/persistors/model_identity_map.rb +10 -8
  35. data/lib/volt/models/persistors/model_store.rb +76 -76
  36. data/lib/volt/models/persistors/params.rb +19 -17
  37. data/lib/volt/models/persistors/query/query_listener.rb +65 -63
  38. data/lib/volt/models/persistors/query/query_listener_pool.rb +12 -10
  39. data/lib/volt/models/persistors/store.rb +28 -28
  40. data/lib/volt/models/persistors/store_factory.rb +12 -10
  41. data/lib/volt/models/persistors/store_state.rb +33 -31
  42. data/lib/volt/models/url.rb +96 -104
  43. data/lib/volt/models/validations.rb +56 -54
  44. data/lib/volt/models/validators/length_validator.rb +24 -22
  45. data/lib/volt/models/validators/presence_validator.rb +14 -12
  46. data/lib/volt/page/bindings/attribute_binding.rb +106 -106
  47. data/lib/volt/page/bindings/base_binding.rb +23 -21
  48. data/lib/volt/page/bindings/component_binding.rb +3 -1
  49. data/lib/volt/page/bindings/content_binding.rb +34 -34
  50. data/lib/volt/page/bindings/each_binding.rb +113 -113
  51. data/lib/volt/page/bindings/event_binding.rb +38 -34
  52. data/lib/volt/page/bindings/if_binding.rb +56 -54
  53. data/lib/volt/page/bindings/template_binding/grouped_controllers.rb +24 -22
  54. data/lib/volt/page/bindings/template_binding.rb +182 -185
  55. data/lib/volt/page/channel.rb +79 -77
  56. data/lib/volt/page/channel_stub.rb +29 -27
  57. data/lib/volt/page/document.rb +6 -5
  58. data/lib/volt/page/document_events.rb +54 -52
  59. data/lib/volt/page/page.rb +139 -138
  60. data/lib/volt/page/string_template_renderer.rb +36 -36
  61. data/lib/volt/page/sub_context.rb +26 -25
  62. data/lib/volt/page/targets/attribute_section.rb +27 -25
  63. data/lib/volt/page/targets/attribute_target.rb +7 -6
  64. data/lib/volt/page/targets/base_section.rb +27 -26
  65. data/lib/volt/page/targets/binding_document/base_node.rb +3 -1
  66. data/lib/volt/page/targets/binding_document/component_node.rb +85 -82
  67. data/lib/volt/page/targets/binding_document/html_node.rb +11 -9
  68. data/lib/volt/page/targets/dom_section.rb +78 -77
  69. data/lib/volt/page/targets/dom_target.rb +8 -6
  70. data/lib/volt/page/targets/dom_template.rb +90 -88
  71. data/lib/volt/page/targets/helpers/comment_searchers.rb +51 -49
  72. data/lib/volt/page/tasks.rb +59 -57
  73. data/lib/volt/page/template_renderer.rb +17 -14
  74. data/lib/volt/page/url_tracker.rb +26 -24
  75. data/lib/volt/reactive/computation.rb +87 -88
  76. data/lib/volt/reactive/dependency.rb +30 -28
  77. data/lib/volt/reactive/eventable.rb +64 -62
  78. data/lib/volt/reactive/hash_dependency.rb +25 -23
  79. data/lib/volt/reactive/reactive_accessors.rb +34 -32
  80. data/lib/volt/reactive/reactive_array.rb +162 -162
  81. data/lib/volt/reactive/reactive_hash.rb +37 -35
  82. data/lib/volt/router/routes.rb +99 -101
  83. data/lib/volt/server/component_handler.rb +20 -21
  84. data/lib/volt/server/component_templates.rb +72 -70
  85. data/lib/volt/server/html_parser/attribute_scope.rb +109 -99
  86. data/lib/volt/server/html_parser/each_scope.rb +17 -16
  87. data/lib/volt/server/html_parser/if_view_scope.rb +51 -49
  88. data/lib/volt/server/html_parser/sandlebars_parser.rb +184 -177
  89. data/lib/volt/server/html_parser/textarea_scope.rb +24 -22
  90. data/lib/volt/server/html_parser/view_handler.rb +66 -65
  91. data/lib/volt/server/html_parser/view_parser.rb +23 -21
  92. data/lib/volt/server/html_parser/view_scope.rb +142 -141
  93. data/lib/volt/server/rack/asset_files.rb +81 -79
  94. data/lib/volt/server/rack/component_code.rb +17 -15
  95. data/lib/volt/server/rack/component_html_renderer.rb +14 -12
  96. data/lib/volt/server/rack/component_paths.rb +72 -71
  97. data/lib/volt/server/rack/index_files.rb +36 -39
  98. data/lib/volt/server/rack/opal_files.rb +43 -41
  99. data/lib/volt/server/rack/source_map_server.rb +23 -21
  100. data/lib/volt/server/socket_connection_handler.rb +46 -45
  101. data/lib/volt/server/socket_connection_handler_stub.rb +21 -19
  102. data/lib/volt/server.rb +60 -58
  103. data/lib/volt/spec/setup.rb +3 -3
  104. data/lib/volt/tasks/dispatcher.rb +24 -23
  105. data/lib/volt/tasks/task_handler.rb +35 -33
  106. data/lib/volt/utils/ejson.rb +8 -6
  107. data/lib/volt/utils/generic_counting_pool.rb +33 -31
  108. data/lib/volt/utils/generic_pool.rb +73 -70
  109. data/lib/volt/utils/local_storage.rb +42 -38
  110. data/lib/volt/volt/environment.rb +1 -1
  111. data/lib/volt.rb +44 -42
  112. data/spec/apps/kitchen_sink/app/main/assets/css/todos.css +28 -0
  113. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  114. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
  115. data/spec/apps/kitchen_sink/app/main/controllers/todos_controller.rb +17 -0
  116. data/spec/apps/kitchen_sink/app/main/views/main/main.html +1 -0
  117. data/spec/apps/kitchen_sink/app/main/views/todos/index.html +24 -0
  118. data/spec/apps/kitchen_sink/config.ru +1 -1
  119. data/spec/controllers/reactive_accessors_spec.rb +5 -5
  120. data/spec/extra_core/inflector_spec.rb +2 -2
  121. data/spec/integration/list_spec.rb +68 -0
  122. data/spec/models/model_spec.rb +57 -57
  123. data/spec/models/persistors/params_spec.rb +6 -6
  124. data/spec/models/persistors/store_spec.rb +7 -7
  125. data/spec/models/validations_spec.rb +3 -3
  126. data/spec/page/bindings/content_binding_spec.rb +7 -7
  127. data/spec/page/bindings/template_binding_spec.rb +4 -5
  128. data/spec/page/sub_context_spec.rb +2 -2
  129. data/spec/reactive/computation_spec.rb +10 -10
  130. data/spec/reactive/dependency_spec.rb +2 -2
  131. data/spec/reactive/eventable_spec.rb +4 -4
  132. data/spec/reactive/reactive_array_spec.rb +13 -13
  133. data/spec/router/routes_spec.rb +5 -5
  134. data/spec/server/html_parser/sandlebars_parser_spec.rb +9 -9
  135. data/spec/server/html_parser/view_parser_spec.rb +27 -27
  136. data/spec/server/rack/asset_files_spec.rb +5 -5
  137. data/spec/server/rack/component_paths_spec.rb +2 -2
  138. data/spec/tasks/live_query_spec.rb +2 -2
  139. data/spec/tasks/query_tasks.rb +1 -1
  140. data/spec/tasks/query_tracker_spec.rb +1 -1
  141. data/spec/templates/targets/binding_document/component_node_spec.rb +2 -2
  142. data/spec/utils/generic_counting_pool_spec.rb +2 -2
  143. data/spec/utils/generic_pool_spec.rb +2 -2
  144. data/templates/component/controllers/main_controller.rb +1 -1
  145. data/templates/model/model.rb.tt +2 -2
  146. data/templates/newgem/app/newgem/controllers/main_controller.rb.tt +2 -2
  147. data/templates/project/app/main/controllers/main_controller.rb +1 -1
  148. data/templates/project/config.ru +1 -1
  149. metadata +10 -3
  150. data/app/volt/assets/js/vertxbus.js +0 -216
@@ -1,40 +1,40 @@
1
1
  require 'volt/models/persistors/base'
2
2
  require 'volt/models/persistors/model_identity_map'
3
3
 
4
- module Persistors
5
- class Store < Base
4
+ module Volt
5
+ module Persistors
6
+ class Store < Base
6
7
 
7
- @@identity_map = ModelIdentityMap.new
8
+ @@identity_map = ModelIdentityMap.new
8
9
 
9
- def initialize(model, tasks=nil)
10
- @tasks = tasks
11
- @model = model
10
+ def initialize(model, tasks=nil)
11
+ @tasks = tasks
12
+ @model = model
12
13
 
13
- @saved = false
14
- end
15
-
16
- def saved?
17
- @saved
18
- end
19
-
20
- # On stores, we store the model so we don't have to look it up
21
- # every time we do a read.
22
- def read_new_model(method_name)
23
- # On stores, plural associations are automatically assumed to be
24
- # collections.
25
- options = @model.options.merge(parent: @model, path: @model.path + [method_name])
26
- if method_name.plural?
27
- model = @model.new_array_model([], options)
28
- else
29
- model = @model.new_model(nil, options)
30
-
31
- # TODO: Might not need to assign this
32
- @model.attributes ||= {}
33
- @model.attributes[method_name] = model
14
+ @saved = false
34
15
  end
35
16
 
17
+ def saved?
18
+ @saved
19
+ end
36
20
 
37
- return model
21
+ # On stores, we store the model so we don't have to look it up
22
+ # every time we do a read.
23
+ def read_new_model(method_name)
24
+ # On stores, plural associations are automatically assumed to be
25
+ # collections.
26
+ options = @model.options.merge(parent: @model, path: @model.path + [method_name])
27
+ if method_name.plural?
28
+ model = @model.new_array_model([], options)
29
+ else
30
+ model = @model.new_model(nil, options)
31
+
32
+ # TODO: Might not need to assign this
33
+ @model.attributes ||= {}
34
+ @model.attributes[method_name] = model
35
+ end
36
+ model
37
+ end
38
38
  end
39
39
  end
40
40
  end
@@ -1,14 +1,16 @@
1
- module Persistors
2
- class StoreFactory
3
- def initialize(tasks)
4
- @tasks = tasks
5
- end
1
+ module Volt
2
+ module Persistors
3
+ class StoreFactory
4
+ def initialize(tasks)
5
+ @tasks = tasks
6
+ end
6
7
 
7
- def new(model)
8
- if model.is_a?(ArrayModel)
9
- ArrayStore.new(model, @tasks)
10
- else
11
- ModelStore.new(model, @tasks)
8
+ def new(model)
9
+ if model.is_a?(ArrayModel)
10
+ ArrayStore.new(model, @tasks)
11
+ else
12
+ ModelStore.new(model, @tasks)
13
+ end
12
14
  end
13
15
  end
14
16
  end
@@ -1,37 +1,39 @@
1
- # StoreState provides method for a store to track its loading state.
2
- module StoreState
3
-
4
- # Called when a collection loads
5
- def loaded(initial_state=nil)
6
- change_state_to(initial_state || :not_loaded)
7
- end
8
-
9
- def state
10
- @state_dep ||= Dependency.new
11
- @state_dep.depend
12
-
13
- return @state
14
- end
15
-
16
- # Called from the QueryListener when the data is loaded
17
- def change_state_to(new_state, skip_trigger=false)
18
- old_state = @state
19
- @state = new_state
20
-
21
- # Trigger changed on the 'state' method
22
- unless skip_trigger
23
- if old_state != @state
24
- @state_dep.changed! if @state_dep
1
+ module Volt
2
+ module Persistors
3
+ # StoreState provides method for a store to track its loading state.
4
+ module StoreState
5
+
6
+ # Called when a collection loads
7
+ def loaded(initial_state=nil)
8
+ change_state_to(initial_state || :not_loaded)
25
9
  end
26
- end
27
10
 
28
- if @state == :loaded && @fetch_promises
29
- # Trigger each waiting fetch
30
- @fetch_promises.compact.each {|fp| fp.resolve(@model) }
31
- @fetch_promises = nil
11
+ def state
12
+ @state_dep ||= Dependency.new
13
+ @state_dep.depend
14
+ @state
15
+ end
32
16
 
33
- stop_listening
17
+ # Called from the QueryListener when the data is loaded
18
+ def change_state_to(new_state, skip_trigger=false)
19
+ old_state = @state
20
+ @state = new_state
21
+
22
+ # Trigger changed on the 'state' method
23
+ unless skip_trigger
24
+ if old_state != @state
25
+ @state_dep.changed! if @state_dep
26
+ end
27
+ end
28
+
29
+ if @state == :loaded && @fetch_promises
30
+ # Trigger each waiting fetch
31
+ @fetch_promises.compact.each { |fp| fp.resolve(@model) }
32
+ @fetch_promises = nil
33
+
34
+ stop_listening
35
+ end
36
+ end
34
37
  end
35
38
  end
36
-
37
39
  end
@@ -1,124 +1,117 @@
1
1
  # The url class handles parsing and updating the url
2
2
  require 'volt/reactive/reactive_accessors'
3
+ module Volt
4
+ class URL
5
+ include ReactiveAccessors
3
6
 
4
- class URL
5
- include ReactiveAccessors
7
+ # TODO: we need to make it so change events only trigger on changes
8
+ reactive_accessor :scheme, :host, :port, :path, :query, :params, :fragment
9
+ attr_accessor :router
6
10
 
7
- # TODO: we need to make it so change events only trigger on changes
8
- reactive_accessor :scheme, :host, :port, :path, :query, :params, :fragment
9
- attr_accessor :router
10
-
11
- def initialize(router=nil)
12
- @router = router
13
- @params = Model.new({}, persistor: Persistors::Params)
14
- end
11
+ def initialize(router = nil)
12
+ @router = router
13
+ @params = Model.new({}, persistor: Persistors::Params)
14
+ end
15
15
 
16
- # Parse takes in a url and extracts each sections.
17
- # It also assigns and changes to the params.
18
- def parse(url)
19
- if url[0] == '#'
20
- # url only updates fragment
21
- self.fragment = url[1..-1]
22
- update!
23
- else
24
- host = `document.location.host`
25
- protocol = `document.location.protocol`
26
-
27
- if url !~ /[:]\/\//
28
- # Add the host for local urls
29
- url = protocol + "//#{host}" + url
16
+ # Parse takes in a url and extracts each sections.
17
+ # It also assigns and changes to the params.
18
+ def parse(url)
19
+ if url[0] == '#'
20
+ # url only updates fragment
21
+ self.fragment = url[1..-1]
22
+ update!
30
23
  else
31
- # Make sure its on the same protocol and host, otherwise its external.
32
- if url !~ /#{protocol}\/\/#{host}/
33
- # Different host, don't process
34
- return false
24
+ host = `document.location.host`
25
+ protocol = `document.location.protocol`
26
+
27
+ if url !~ /[:]\/\//
28
+ # Add the host for local urls
29
+ url = protocol + "//#{host}" + url
30
+ else
31
+ # Make sure its on the same protocol and host, otherwise its external.
32
+ if url !~ /#{protocol}\/\/#{host}/
33
+ # Different host, don't process
34
+ return false
35
+ end
35
36
  end
36
- end
37
37
 
38
- matcher = url.match(/^(#{protocol[0..-2]})[:]\/\/([^\/]+)(.*)$/)
39
- self.scheme = matcher[1]
40
- host, port = matcher[2].split(':')
38
+ matcher = url.match(/^(#{protocol[0..-2]})[:]\/\/([^\/]+)(.*)$/)
39
+ self.scheme = matcher[1]
40
+ self.host, port = matcher[2].split(':')
41
41
 
42
- self.host = host
43
- self.port = (port || 80).to_i
42
+ self.port = (port || 80).to_i
44
43
 
45
- path = matcher[3]
46
- path, fragment = path.split('#', 2)
47
- path, query = path.split('?', 2)
44
+ path = matcher[3]
45
+ path, fragment = path.split('#', 2)
46
+ path, query = path.split('?', 2)
48
47
 
49
- self.path = path
50
- self.fragment = fragment
51
- self.query = query
48
+ self.path = path
49
+ self.fragment = fragment
50
+ self.query = query
52
51
 
53
- assign_query_hash_to_params
54
- end
52
+ assign_query_hash_to_params
53
+ end
55
54
 
56
- scroll
55
+ scroll
57
56
 
58
- return true
59
- end
57
+ return true
58
+ end
60
59
 
61
- # Full url rebuilds the url from it's constituent parts
62
- def full_url
63
- if port && port != 80
64
- host_with_port = "#{host}:#{port}"
65
- else
60
+ # Full url rebuilds the url from it's constituent parts
61
+ def full_url
66
62
  host_with_port = host
67
- end
63
+ host_with_port += ":#{port}" if port && port != 80
68
64
 
69
- path, params = @router.params_to_url(@params.to_h)
65
+ self.path, params = @router.params_to_url(@params.to_h)
70
66
 
71
- self.path = path if path
67
+ new_url = "#{scheme}://#{host_with_port}#{path.chomp('/')}"
72
68
 
73
- new_url = "#{scheme}://#{host_with_port}#{(path || self.path).chomp('/')}"
69
+ # Add query params
70
+ params_str = ''
71
+ unless params.empty?
72
+ query_parts = []
73
+ nested_params_hash(params).each_pair do |key, value|
74
+ # remove the _ from the front
75
+ value = `encodeURI(value)`
76
+ query_parts << "#{key[1..-1]}=#{value}"
77
+ end
74
78
 
75
- params_str = ''
76
- unless params.empty?
77
- query_parts = []
78
- nested_params_hash(params).each_pair do |key,value|
79
- # remove the _ from the front
80
- value = `encodeURI(value)`
81
- query_parts << "#{key[1..-1]}=#{value}"
79
+ if query_parts.size > 0
80
+ self.query = query_parts.join('&')
81
+ new_url += '?' + self.query
82
+ end
82
83
  end
83
84
 
84
- if query_parts.size > 0
85
- self.query = query_parts.join('&')
86
- new_url += '?' + self.query
87
- end
88
- end
85
+ # Add fragment
86
+ frag = self.fragment
87
+ new_url += '#' + frag if frag.present?
89
88
 
90
- frag = self.fragment
91
- if frag.present?
92
- self.fragment = frag
93
- new_url += '#' + frag
89
+ return new_url
94
90
  end
95
91
 
96
- return new_url
97
- end
98
-
99
- # Called when the state has changed and the url in the
100
- # browser should be updated
101
- # Called when an attribute changes to update the url
102
- def update!
103
- if Volt.client?
104
- new_url = full_url()
92
+ # Called when the state has changed and the url in the
93
+ # browser should be updated
94
+ # Called when an attribute changes to update the url
95
+ def update!
96
+ if Volt.client?
97
+ new_url = full_url()
105
98
 
106
- # Push the new url if pushState is supported
107
- # TODO: add fragment fallback
108
- %x{
99
+ # Push the new url if pushState is supported
100
+ # TODO: add fragment fallback
101
+ %x{
109
102
  if (document.location.href != new_url && history && history.pushState) {
110
103
  history.pushState(null, null, new_url);
111
104
  }
112
105
  }
106
+ end
113
107
  end
114
- end
115
108
 
116
- def scroll
117
- if Volt.client?
118
- frag = self.fragment
119
- if frag
120
- # Scroll to anchor via http://www.w3.org/html/wg/drafts/html/master/browsers.html#scroll-to-fragid
121
- %x{
109
+ def scroll
110
+ if Volt.client?
111
+ frag = self.fragment
112
+ if frag
113
+ # Scroll to anchor via http://www.w3.org/html/wg/drafts/html/master/browsers.html#scroll-to-fragid
114
+ %x{
122
115
  var anchor = $('#' + frag);
123
116
  if (anchor.length == 0) {
124
117
  anchor = $('*[name="' + frag + '"]:first');
@@ -128,14 +121,14 @@ class URL
128
121
  $(document.body).scrollTop(anchor.offset().top);
129
122
  }
130
123
  }
131
- else
132
- # Scroll to the top by default
133
- `$(document.body).scrollTop(0);`
124
+ else
125
+ # Scroll to the top by default
126
+ `$(document.body).scrollTop(0);`
127
+ end
134
128
  end
135
129
  end
136
- end
137
130
 
138
- private
131
+ private
139
132
  # Assigning the params is tricky since we don't want to trigger changed on
140
133
  # any values that have not changed. So we first loop through all current
141
134
  # url params, removing any not present in the params, while also removing
@@ -165,7 +158,7 @@ class URL
165
158
  def assign_from_old(params, new_params)
166
159
  queued_deletes = []
167
160
 
168
- params.attributes.each_pair do |name,old_val|
161
+ params.attributes.each_pair do |name, old_val|
169
162
  # If there is a new value, see if it has [name]
170
163
  new_val = new_params ? new_params[name] : nil
171
164
 
@@ -183,7 +176,7 @@ class URL
183
176
  end
184
177
  end
185
178
 
186
- queued_deletes.each {|name| params.delete(name) }
179
+ queued_deletes.each { |name| params.delete(name) }
187
180
  end
188
181
 
189
182
  # Assign any new params, which weren't in the old params.
@@ -200,10 +193,10 @@ class URL
200
193
 
201
194
  def query_hash
202
195
  query_hash = {}
203
- qury = self.query
196
+ qury = self.query
204
197
  if qury
205
- qury.split('&').reject {|v| v == '' }.each do |part|
206
- parts = part.split('=').reject {|v| v == '' }
198
+ qury.split('&').reject { |v| v == '' }.each do |part|
199
+ parts = part.split('=').reject { |v| v == '' }
207
200
 
208
201
  # Decode string
209
202
  # parts[0] = `decodeURI(parts[0])`
@@ -212,7 +205,7 @@ class URL
212
205
  sections = query_key_sections(parts[0])
213
206
 
214
207
  hash_part = query_hash
215
- sections.each_with_index do |section,index|
208
+ sections.each_with_index do |section, index|
216
209
  if index == sections.size-1
217
210
  # Last part, assign the value
218
211
  hash_part[section] = parts[1]
@@ -231,14 +224,13 @@ class URL
231
224
  # Example:
232
225
  # user[name]=Ryan would parse as [:_user, :_name]
233
226
  def query_key_sections(key)
234
- key.split(/\[([^\]]+)\]/).reject(&:empty?).map {|v| :"_#{v}"}
227
+ key.split(/\[([^\]]+)\]/).reject(&:empty?).map { |v| :"_#{v}" }
235
228
  end
236
229
 
237
230
  # Generate the key for a nested param attribute
238
231
  def query_key(path)
239
232
  i = 0
240
233
  path.map do |v|
241
- # v = v[1..-1]
242
234
  i += 1
243
235
  if i != 1
244
236
  "[#{v}]"
@@ -251,7 +243,7 @@ class URL
251
243
  def nested_params_hash(params, path=[])
252
244
  results = {}
253
245
 
254
- params.each_pair do |key,value|
246
+ params.each_pair do |key, value|
255
247
  unless value.nil?
256
248
  if value.respond_to?(:persistor) && value.persistor && value.persistor.is_a?(Persistors::Params)
257
249
  # TODO: Should be a param
@@ -264,5 +256,5 @@ class URL
264
256
 
265
257
  return results
266
258
  end
267
-
259
+ end
268
260
  end
@@ -2,77 +2,78 @@
2
2
  require 'volt/models/validators/length_validator'
3
3
  require 'volt/models/validators/presence_validator'
4
4
 
5
- # Include in any class to get validation logic
6
- module Validations
7
- module ClassMethods
8
- def validate(field_name, options)
9
- @validations ||= {}
10
- @validations[field_name] = options
11
- end
5
+ module Volt
6
+ # Include in any class to get validation logic
7
+ module Validations
8
+ module ClassMethods
9
+ def validate(field_name, options)
10
+ @validations ||= {}
11
+ @validations[field_name] = options
12
+ end
12
13
 
13
- def validations
14
- @validations
14
+ def validations
15
+ @validations
16
+ end
15
17
  end
16
- end
17
18
 
18
- def self.included(base)
19
- base.send :extend, ClassMethods
20
- end
19
+ def self.included(base)
20
+ base.send :extend, ClassMethods
21
+ end
21
22
 
22
- # Once a field is ready, we can use include_in_errors! to start
23
- # showing its errors.
24
- def mark_field!(field_name, trigger_changed=true)
25
- marked_fields[field_name] = true
26
- end
23
+ # Once a field is ready, we can use include_in_errors! to start
24
+ # showing its errors.
25
+ def mark_field!(field_name, trigger_changed=true)
26
+ marked_fields[field_name] = true
27
+ end
27
28
 
28
- def marked_fields
29
- @marked_fields ||= ReactiveHash.new
30
- end
29
+ def marked_fields
30
+ @marked_fields ||= ReactiveHash.new
31
+ end
31
32
 
32
- def marked_errors
33
- errors(true)
34
- end
33
+ def marked_errors
34
+ errors(true)
35
+ end
35
36
 
36
- # TODO: Errors is being called for any validation change. We should have errors return a
37
- # hash like object that only calls the validation for each one.
38
- def errors(marked_only=false)
39
- errors = {}
37
+ # TODO: Errors is being called for any validation change. We should have errors return a
38
+ # hash like object that only calls the validation for each one.
39
+ def errors(marked_only=false)
40
+ errors = {}
40
41
 
41
- validations = self.class.validations
42
+ validations = self.class.validations
42
43
 
43
- if validations
44
- # Merge into errors, combining any error arrays
45
- merge = Proc.new do |new_errors|
46
- errors.merge!(new_errors) do |key, new_val, old_val|
47
- new_val + old_val
44
+ if validations
45
+ # Merge into errors, combining any error arrays
46
+ merge = Proc.new do |new_errors|
47
+ errors.merge!(new_errors) do |key, new_val, old_val|
48
+ new_val + old_val
49
+ end
48
50
  end
49
- end
50
51
 
51
- # Run through each validation
52
- validations.each_pair do |field_name, options|
53
- if marked_only
54
- # When marked only, skip any validations on non-marked fields
55
- next unless marked_fields[field_name]
56
- end
52
+ # Run through each validation
53
+ validations.each_pair do |field_name, options|
54
+ if marked_only
55
+ # When marked only, skip any validations on non-marked fields
56
+ next unless marked_fields[field_name]
57
+ end
57
58
 
58
- options.each_pair do |validation, args|
59
- # Call the specific validator, then merge the results back
60
- # into one large errors hash.
61
- klass = validation_class(validation, args)
59
+ options.each_pair do |validation, args|
60
+ # Call the specific validator, then merge the results back
61
+ # into one large errors hash.
62
+ klass = validation_class(validation, args)
62
63
 
63
- if klass
64
- validate_with(merge, klass, field_name, args)
65
- else
66
- raise "validation type #{validation} is not specified."
64
+ if klass
65
+ validate_with(merge, klass, field_name, args)
66
+ else
67
+ raise "validation type #{validation} is not specified."
68
+ end
67
69
  end
68
70
  end
69
71
  end
70
- end
71
72
 
72
- return errors
73
- end
73
+ return errors
74
+ end
74
75
 
75
- private
76
+ private
76
77
  # calls the validate method on the class, passing the right arguments.
77
78
  def validate_with(merge, klass, field_name, args)
78
79
  return merge.call(klass.validate(self, field_name, args))
@@ -80,9 +81,10 @@ module Validations
80
81
 
81
82
  def validation_class(validation, args)
82
83
  begin
83
- Object.const_get(:"#{validation.camelize}Validator")
84
+ Volt.const_get(:"#{validation.camelize}Validator")
84
85
  rescue NameError => e
85
86
  puts "Unable to find #{validation} validator"
86
87
  end
87
88
  end
89
+ end
88
90
  end
@@ -1,28 +1,30 @@
1
- class LengthValidator
2
- def self.validate(model, field_name, args)
3
- errors = {}
4
- value = model.send(field_name)
1
+ module Volt
2
+ class LengthValidator
3
+ def self.validate(model, field_name, args)
4
+ errors = {}
5
+ value = model.send(field_name)
5
6
 
6
- if args.is_a?(Fixnum)
7
- min = args
8
- max = nil
9
- message = nil
10
- elsif args.is_a?(Hash)
11
- min = args[:length] || args[:minimum]
12
- max = args[:maximum]
13
- raise "length or minimum must be specified" unless min.is_a?(Fixnum)
7
+ if args.is_a?(Fixnum)
8
+ min = args
9
+ max = nil
10
+ message = nil
11
+ elsif args.is_a?(Hash)
12
+ min = args[:length] || args[:minimum]
13
+ max = args[:maximum]
14
+ raise "length or minimum must be specified" unless min.is_a?(Fixnum)
14
15
 
15
- message = args[:message]
16
- else
17
- raise "The arguments to length must be a number or a hash"
18
- end
16
+ message = args[:message]
17
+ else
18
+ raise "The arguments to length must be a number or a hash"
19
+ end
19
20
 
20
- if !value || value.size < min
21
- errors[field_name] = [message || "must be at least #{args} characters"]
22
- elsif max && value.size > max
23
- errors[field_name] = [message || "must be less than #{args} characters"]
24
- end
21
+ if !value || value.size < min
22
+ errors[field_name] = [message || "must be at least #{args} characters"]
23
+ elsif max && value.size > max
24
+ errors[field_name] = [message || "must be less than #{args} characters"]
25
+ end
25
26
 
26
- return errors
27
+ return errors
28
+ end
27
29
  end
28
30
  end