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,222 +1,229 @@
1
1
  require 'strscan'
2
2
 
3
- class HTMLParseError < RuntimeError
4
- end
5
- # Parses html and bindings
6
- # based on http://ejohn.org/files/htmlparser.js
7
- #
8
- # takes the html and a handler object that will have the following methods
9
- # called as each is seen: comment, text, binding, start_tag, end_tag
10
- #
11
- # This is not a full html parser, but should cover most common cases.
12
- class SandlebarsParser
13
- def self.truth_hash(array)
14
- hash = {}
15
- array.each {|v| hash[v] = true }
16
-
17
- return hash
3
+ module Volt
4
+ class HTMLParseError < RuntimeError
18
5
  end
19
6
 
20
- # regex matchers
21
- START_TAG = /^<([-!\:A-Za-z0-9_]+)((?:\s+[\w\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/
22
- END_TAG = /^<\/([-!\:A-Za-z0-9_]+)[^>]*>/
23
- ATTRIBUTES = /([-\:A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/
7
+ # Parses html and bindings
8
+ # based on http://ejohn.org/files/htmlparser.js
9
+ #
10
+ # takes the html and a handler object that will have the following methods
11
+ # called as each is seen: comment, text, binding, start_tag, end_tag
12
+ #
13
+ # This is not a full html parser, but should cover most common cases.
14
+ class SandlebarsParser
15
+ def self.truth_hash(array)
16
+ hash = {}
17
+ array.each { |v| hash[v] = true }
18
+
19
+ return hash
20
+ end
24
21
 
25
- # Types of elements
26
- BLOCK = truth_hash(%w{a address applet blockquote button center dd del dir div dl dt fieldset form frameset hr iframe ins isindex li map menu noframes noscript object ol p pre script table tbody td tfoot th thead tr ul})
27
- EMPTY = truth_hash(%w{area base basefont br col frame hr img input isindex link meta param embed})
28
- INLINE = truth_hash(%w{abbr acronym applet b basefont bdo big br button cite code del dfn em font i iframe img input ins kbd label map object q s samp script select small span strike strong sub sup textarea tt u var})
29
- CLOSE_SELF = truth_hash(%w{colgroup dd dt li options p td tfoot th thead tr})
30
- SPECIAL = truth_hash(%w{script style})
22
+ # regex matchers
23
+ START_TAG = /^<([-!\:A-Za-z0-9_]+)((?:\s+[\w\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/
24
+ END_TAG = /^<\/([-!\:A-Za-z0-9_]+)[^>]*>/
25
+ ATTRIBUTES = /([-\:A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/
31
26
 
32
- FILL_IN_ATTRIBUTES = truth_hash(%w{checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected})
27
+ # Types of elements
28
+ BLOCK = truth_hash(%w{a address applet blockquote button center dd del dir div dl dt fieldset form frameset hr iframe ins isindex li map menu noframes noscript object ol p pre script table tbody td tfoot th thead tr ul})
29
+ EMPTY = truth_hash(%w{area base basefont br col frame hr img input isindex link meta param embed})
30
+ INLINE = truth_hash(%w{abbr acronym applet b basefont bdo big br button cite code del dfn em font i iframe img input ins kbd label map object q s samp script select small span strike strong sub sup textarea tt u var})
31
+ CLOSE_SELF = truth_hash(%w{colgroup dd dt li options p td tfoot th thead tr})
32
+ SPECIAL = truth_hash(%w{script style})
33
33
 
34
- def initialize(html, handler, file_path=nil)
35
- @html = StringScanner.new(html)
36
- @handler = handler
37
- @file_path = file_path
34
+ FILL_IN_ATTRIBUTES = truth_hash(%w{checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected})
38
35
 
39
- @stack = []
36
+ def initialize(html, handler, file_path=nil)
37
+ @html = StringScanner.new(html)
38
+ @handler = handler
39
+ @file_path = file_path
40
40
 
41
- parse
42
- end
41
+ @stack = []
43
42
 
44
- def last
45
- @stack.last
46
- end
43
+ parse
44
+ end
47
45
 
48
- def parse
49
- loop do
50
- if last && SPECIAL[last]
51
- # In a script or style tag, just look for the first end
52
- close_tag = "</#{last}>"
53
- body = @html.scan_until(/#{close_tag}/)
54
- body = body[0..((-1 * close_tag.size)-1)]
55
-
56
- body = body.gsub(/\<\!--(.*?)--\>/, "\\1").gsub(/\<\!\[CDATA\[(.*?)\]\]\>/, "\\1")
57
-
58
- text(body)
59
-
60
- end_tag(last, last)
61
- elsif @html.scan(/\<\!--/)
62
- # start comment
63
- comment = @html.scan_until(/--\>/)
64
- comment = comment[0..-4]
65
-
66
- @handler.comment(comment) if @handler.respond_to?(:comment)
67
- elsif (tag = @html.scan(START_TAG))
68
- tag_name = @html[1]
69
- rest = @html[2]
70
- unary = @html[3]
71
-
72
- start_tag(tag, tag_name, rest, unary)
73
- elsif @html.scan(END_TAG)
74
- tag_name = @html[1]
75
-
76
- end_tag(tag_name, tag_name)
77
- elsif (escaped = @html.scan(/\{\{\{(.*?)\}\}\}([^\}]|$)/))
78
- # Anything between {{{ and }}} is escaped and not processed (treaded as text)
79
- if escaped[-1] != '}'
80
- # Move back if we matched a new non } for close, skip if we hit the end
81
- @html.pos = @html.pos - 1
82
- end
46
+ def last
47
+ @stack.last
48
+ end
83
49
 
84
- text(@html[1])
85
- elsif (binding = @html.scan(/\{\{/))
86
- # We are in text mode and matched the start of a binding
87
- start_binding
88
- elsif (text = @html.scan(/\{/))
89
- # A single { outside of a binding
90
- text(text)
91
- elsif (text = @html.scan(/(?:[^\<\{]+)/))
92
- # matched text up until the next html tag
93
- text(text)
94
- else
95
- # Nothing left
96
- break
50
+ def parse
51
+ loop do
52
+ if last && SPECIAL[last]
53
+ # In a script or style tag, just look for the first end
54
+ close_tag = "</#{last}>"
55
+ body = @html.scan_until(/#{close_tag}/)
56
+ special_tag(close_tag, body)
57
+ elsif @html.scan(/\<\!--/)
58
+ # start comment
59
+ comment = @html.scan_until(/--\>/)
60
+ comment = comment[0..-4]
61
+
62
+ @handler.comment(comment) if @handler.respond_to?(:comment)
63
+ elsif (tag = @html.scan(START_TAG))
64
+ tag_name = @html[1]
65
+ rest = @html[2]
66
+ unary = @html[3]
67
+
68
+ start_tag(tag, tag_name, rest, unary)
69
+ elsif @html.scan(END_TAG)
70
+ tag_name = @html[1]
71
+
72
+ end_tag(tag_name, tag_name)
73
+ elsif (escaped = @html.scan(/\{\{\{(.*?)\}\}\}([^\}]|$)/))
74
+ # Anything between {{{ and }}} is escaped and not processed (treaded as text)
75
+ if escaped[-1] != '}'
76
+ # Move back if we matched a new non } for close, skip if we hit the end
77
+ @html.pos = @html.pos - 1
78
+ end
79
+
80
+ text(@html[1])
81
+ elsif (binding = @html.scan(/\{\{/))
82
+ # We are in text mode and matched the start of a binding
83
+ start_binding
84
+ elsif (text = @html.scan(/\{/))
85
+ # A single { outside of a binding
86
+ text(text)
87
+ elsif (text = @html.scan(/(?:[^\<\{]+)/))
88
+ # matched text up until the next html tag
89
+ text(text)
90
+ else
91
+ # Nothing left
92
+ break
93
+ end
97
94
  end
98
- end
99
95
 
100
- end_tag(nil, nil)
101
- end
96
+ end_tag(nil, nil)
97
+ end
102
98
 
103
- def text(text)
104
- @handler.text(text) if @handler.respond_to?(:text)
105
- end
99
+ def text(text)
100
+ @handler.text(text) if @handler.respond_to?(:text)
101
+ end
106
102
 
107
- # Findings the end of a binding
108
- def start_binding
109
- binding = ''
110
- open_count = 1
111
-
112
- # scan until we reach a {{ or }}
113
- loop do
114
- binding << @html.scan_until(/(\{\{|\}\}|\n|\Z)/)
115
-
116
- match = @html[1]
117
- if match == '}}'
118
- # close
119
- open_count -= 1
120
- break if open_count == 0
121
- elsif match == '{{'
122
- # open more
123
- open_count += 1
124
- elsif match == "\n" || @html.eos?
125
- # Starting new tag, should be closed before this
126
- # or end of doc before closed binding
127
- raise_parse_error("unclosed binding: {#{binding.strip}")
128
- else
129
- raise "should not reach here"
103
+ # Findings the end of a binding
104
+ def start_binding
105
+ binding = ''
106
+ open_count = 1
107
+
108
+ # scan until we reach a {{ or }}
109
+ loop do
110
+ binding << @html.scan_until(/(\{\{|\}\}|\n|\Z)/)
111
+
112
+ match = @html[1]
113
+ if match == '}}'
114
+ # close
115
+ open_count -= 1
116
+ break if open_count == 0
117
+ elsif match == '{{'
118
+ # open more
119
+ open_count += 1
120
+ elsif match == "\n" || @html.eos?
121
+ # Starting new tag, should be closed before this
122
+ # or end of doc before closed binding
123
+ raise_parse_error("unclosed binding: {#{binding.strip}")
124
+ else
125
+ raise "should not reach here"
126
+ end
130
127
  end
131
- end
132
128
 
133
- binding = binding[0..-3]
134
- @handler.binding(binding) if @handler.respond_to?(:binding)
135
- end
129
+ binding = binding[0..-3]
130
+ @handler.binding(binding) if @handler.respond_to?(:binding)
131
+ end
136
132
 
137
- def raise_parse_error(error)
138
- line_number = @html.pre_match.count("\n") + 1
133
+ def raise_parse_error(error)
134
+ line_number = @html.pre_match.count("\n") + 1
139
135
 
140
- error_str = error + " on line: #{line_number}"
141
- error_str += " of #{@file_path}" if @file_path
136
+ error_str = error + " on line: #{line_number}"
137
+ error_str += " of #{@file_path}" if @file_path
142
138
 
143
- raise HTMLParseError, error_str
144
- end
139
+ raise HTMLParseError, error_str
140
+ end
145
141
 
146
- def start_tag(tag, tag_name, rest, unary)
147
- section_tag = tag_name[0] == ':' && tag_name[1] =~ /[A-Z]/
142
+ def start_tag(tag, tag_name, rest, unary)
143
+ section_tag = tag_name[0] == ':' && tag_name[1] =~ /[A-Z]/
148
144
 
149
- tag_name = tag_name.downcase
145
+ tag_name = tag_name.downcase
150
146
 
151
- # handle doctype so we get it output exactly the same way
152
- if tag_name == '!doctype'
153
- @handler.text(tag) if @handler.respond_to?(:start_tag)
154
- return
155
- end
147
+ # handle doctype so we get it output exactly the same way
148
+ if tag_name == '!doctype'
149
+ @handler.text(tag) if @handler.respond_to?(:start_tag)
150
+ return
151
+ end
156
152
 
157
- # Auto-close the last inline tag if we started a new block
158
- if BLOCK[tag_name]
159
- if last && INLINE[last]
160
- end_tag(nil, last)
153
+ # Auto-close the last inline tag if we started a new block
154
+ if BLOCK[tag_name]
155
+ if last && INLINE[last]
156
+ end_tag(nil, last)
157
+ end
161
158
  end
162
- end
163
159
 
164
- # Some tags close themselves when a new one of themselves is reached.
165
- # ex, a tr will close the previous tr
166
- if CLOSE_SELF[tag_name] && last == tag_name
167
- end_tag(nil, tag_name)
168
- end
160
+ # Some tags close themselves when a new one of themselves is reached.
161
+ # ex, a tr will close the previous tr
162
+ if CLOSE_SELF[tag_name] && last == tag_name
163
+ end_tag(nil, tag_name)
164
+ end
169
165
 
170
- unary = EMPTY[tag_name] || !unary.blank?
166
+ unary = EMPTY[tag_name] || !unary.blank?
171
167
 
172
- # Section tag's are also unary
173
- unless unary || section_tag
174
- @stack.push(tag_name)
175
- end
168
+ # Section tag's are also unary
169
+ unless unary || section_tag
170
+ @stack.push(tag_name)
171
+ end
176
172
 
177
- if @handler.respond_to?(:start_tag)
178
- attributes = {}
173
+ if @handler.respond_to?(:start_tag)
174
+ attributes = {}
179
175
 
180
- # Take the rest string and extract the attributes, filling in any
181
- # "fill in" attribute values if not provided.
182
- rest.scan(ATTRIBUTES).each do |match|
183
- name = match[0]
176
+ # Take the rest string and extract the attributes, filling in any
177
+ # "fill in" attribute values if not provided.
178
+ rest.scan(ATTRIBUTES).each do |match|
179
+ name = match[0]
184
180
 
185
- value = match[1] || match[2] || match[3] || FILL_IN_ATTRIBUTES[name] || ''
181
+ value = match[1] || match[2] || match[3] || FILL_IN_ATTRIBUTES[name] || ''
186
182
 
187
- attributes[name] = value
188
- end
183
+ attributes[name] = value
184
+ end
189
185
 
190
- if section_tag
191
- @handler.start_section(tag_name, attributes, unary)
192
- else
193
- @handler.start_tag(tag_name, attributes, unary)
186
+ if section_tag
187
+ @handler.start_section(tag_name, attributes, unary)
188
+ else
189
+ @handler.start_tag(tag_name, attributes, unary)
190
+ end
194
191
  end
195
192
  end
196
- end
197
-
198
- def end_tag(tag, tag_name)
199
- # If no tag name is provided, close all the way up
200
- new_size = 0
201
193
 
202
- if tag
203
- # Find the closest tag that closes.
204
- (@stack.size-1).downto(0) do |index|
205
- if @stack[index] == tag_name
206
- new_size = index
207
- break
194
+ def end_tag(tag, tag_name)
195
+ # If no tag name is provided, close all the way up
196
+ new_size = 0
197
+
198
+ if tag
199
+ # Find the closest tag that closes.
200
+ (@stack.size-1).downto(0) do |index|
201
+ if @stack[index] == tag_name
202
+ new_size = index
203
+ break
204
+ end
208
205
  end
209
206
  end
210
- end
211
207
 
212
- if new_size >= 0
213
- if @handler.respond_to?(:end_tag)
214
- (@stack.size-1).downto(new_size) do |index|
215
- @handler.end_tag(@stack[index])
208
+ if new_size >= 0
209
+ if @handler.respond_to?(:end_tag)
210
+ (@stack.size-1).downto(new_size) do |index|
211
+ @handler.end_tag(@stack[index])
212
+ end
216
213
  end
214
+
215
+ @stack = @stack[0...new_size]
217
216
  end
217
+ end
218
+
219
+ def special_tag(close_tag, body)
220
+ body = body[0..((-1 * close_tag.size)-1)]
221
+
222
+ body = body.gsub(/\<\!--(.*?)--\>/, "\\1").gsub(/\<\!\[CDATA\[(.*?)\]\]\>/, "\\1")
218
223
 
219
- @stack = @stack[0...new_size]
224
+ text(body)
225
+
226
+ end_tag(last, last)
220
227
  end
221
228
  end
222
- end
229
+ end
@@ -1,31 +1,33 @@
1
- class TextareaScope < ViewScope
2
- def initialize(handler, path, attributes)
3
- super(handler, path)
1
+ module Volt
2
+ class TextareaScope < ViewScope
3
+ def initialize(handler, path, attributes)
4
+ super(handler, path)
4
5
 
5
- @attributes = attributes
6
- end
6
+ @attributes = attributes
7
+ end
7
8
 
8
- def add_binding(content)
9
- @html << "{{#{content}}}"
10
- end
9
+ def add_binding(content)
10
+ @html << "{{#{content}}}"
11
+ end
11
12
 
12
- def close_scope(pop=true)
13
- # Remove from the scope
14
- @handler.scope.pop
13
+ def close_scope(pop=true)
14
+ # Remove from the scope
15
+ @handler.scope.pop
15
16
 
16
- attributes = @attributes
17
+ attributes = @attributes
17
18
 
18
- if @html[/\{\{[^\}]+\}\}/]
19
- # If the html inside the textarea has a binding, process it as
20
- # a value attribute.
21
- attributes['value'] = @html
22
- @html = ''
23
- end
19
+ if @html[/\{\{[^\}]+\}\}/]
20
+ # If the html inside the textarea has a binding, process it as
21
+ # a value attribute.
22
+ attributes['value'] = @html
23
+ @html = ''
24
+ end
24
25
 
25
- # Normal tag
26
- attributes = @handler.last.process_attributes('textarea', attributes)
26
+ # Normal tag
27
+ attributes = @handler.last.process_attributes('textarea', attributes)
27
28
 
28
- @handler.last.html << "<textarea#{attribute_string(attributes)}>#{@html}</textarea>"
29
+ @handler.last.html << "<textarea#{attribute_string(attributes)}>#{@html}</textarea>"
29
30
 
31
+ end
30
32
  end
31
- end
33
+ end
@@ -1,82 +1,83 @@
1
- class ViewHandler
2
- attr_reader :templates, :scope
1
+ module Volt
2
+ class ViewHandler
3
+ attr_reader :templates, :scope
3
4
 
4
- def html
5
- last.html
6
- end
7
-
8
- def last
9
- @scope.last
10
- end
5
+ def html
6
+ last.html
7
+ end
11
8
 
12
- def initialize(initial_path, allow_sections=true)
13
- @original_path = initial_path
9
+ def last
10
+ @scope.last
11
+ end
14
12
 
15
- # Default to the body section
16
- initial_path += '/body' if allow_sections
13
+ def initialize(initial_path, allow_sections=true)
14
+ @original_path = initial_path
17
15
 
18
- @scope = [ViewScope.new(self, initial_path)]
19
- @templates = {}
20
- end
16
+ # Default to the body section
17
+ initial_path += '/body' if allow_sections
21
18
 
22
- def comment(comment)
23
- last << "<!--#{comment}-->"
24
- end
25
-
26
- def text(text)
27
- last << text
28
- end
19
+ @scope = [ViewScope.new(self, initial_path)]
20
+ @templates = {}
21
+ end
29
22
 
30
- def binding(binding)
31
- @scope.last.add_binding(binding)
32
- end
23
+ def comment(comment)
24
+ last << "<!--#{comment}-->"
25
+ end
33
26
 
34
- def start_tag(tag_name, attributes, unary)
35
- case tag_name[0]
36
- when ':'
37
- # Component
38
- last.add_component(tag_name, attributes, unary)
39
- else
40
- if tag_name == 'textarea'
41
- @in_textarea = true
42
- last.add_textarea(tag_name, attributes, unary)
43
- else
27
+ def text(text)
28
+ last << text
29
+ end
44
30
 
45
- # Normal tag
46
- attributes = last.process_attributes(tag_name, attributes)
47
- attr_str = last.attribute_string(attributes)
31
+ def binding(binding)
32
+ @scope.last.add_binding(binding)
33
+ end
48
34
 
49
- last << "<#{tag_name}#{attr_str}#{unary ? ' /' : ''}>"
35
+ def start_tag(tag_name, attributes, unary)
36
+ case tag_name[0]
37
+ when ':'
38
+ # Component
39
+ last.add_component(tag_name, attributes, unary)
40
+ else
41
+ if tag_name == 'textarea'
42
+ @in_textarea = true
43
+ last.add_textarea(tag_name, attributes, unary)
44
+ else
45
+
46
+ # Normal tag
47
+ attributes = last.process_attributes(tag_name, attributes)
48
+ attr_str = last.attribute_string(attributes)
49
+
50
+ last << "<#{tag_name}#{attr_str}#{unary ? ' /' : ''}>"
51
+ end
50
52
  end
51
53
  end
52
- end
53
54
 
54
- def end_tag(tag_name)
55
- if @in_textarea && tag_name == 'textarea'
56
- last.close_scope
57
- @in_textarea = nil
58
- else
59
- last << "</#{tag_name}>"
55
+ def end_tag(tag_name)
56
+ if @in_textarea && tag_name == 'textarea'
57
+ last.close_scope
58
+ @in_textarea = nil
59
+ else
60
+ last << "</#{tag_name}>"
61
+ end
60
62
  end
61
- end
62
63
 
63
- def start_section(tag_name, attributes, unary)
64
- path = last.path
65
- # Start of section
66
- if @in_section
67
- # Close any previous sections
68
- last.close_scope
69
- else
70
- # This is the first time we've hit a section header, everything
71
- # outside of the headers should be removed
72
- @templates = {}
73
- end
64
+ def start_section(tag_name, attributes, unary)
65
+ path = last.path
66
+ # Start of section
67
+ if @in_section
68
+ # Close any previous sections
69
+ last.close_scope
70
+ else
71
+ # This is the first time we've hit a section header, everything
72
+ # outside of the headers should be removed
73
+ @templates = {}
74
+ end
74
75
 
75
- @in_section = tag_name[1..-1]
76
+ @in_section = tag_name[1..-1]
76
77
 
77
- # Set the new path to include the section
78
- new_path = @original_path + '/' + @in_section
79
- @scope = [ViewScope.new(self, new_path)]
78
+ # Set the new path to include the section
79
+ new_path = @original_path + '/' + @in_section
80
+ @scope = [ViewScope.new(self, new_path)]
81
+ end
80
82
  end
81
-
82
- end
83
+ end
@@ -5,35 +5,37 @@ require 'volt/server/html_parser/view_handler'
5
5
  require 'volt/server/html_parser/each_scope'
6
6
  require 'volt/server/html_parser/textarea_scope'
7
7
 
8
- class ViewParser
9
- attr_reader :templates
8
+ module Volt
9
+ class ViewParser
10
+ attr_reader :templates
10
11
 
11
- def initialize(html, template_path)
12
- @template_path = template_path
12
+ def initialize(html, template_path)
13
+ @template_path = template_path
13
14
 
14
- handler = ViewHandler.new(template_path)
15
+ handler = ViewHandler.new(template_path)
15
16
 
16
- SandlebarsParser.new(html, handler)
17
+ SandlebarsParser.new(html, handler)
17
18
 
18
- # Close out the last scope
19
- handler.scope.last.close_scope
19
+ # Close out the last scope
20
+ handler.scope.last.close_scope
20
21
 
21
- @templates = handler.templates
22
- end
22
+ @templates = handler.templates
23
+ end
23
24
 
24
- # Returns a parsed version of the data (useful for backend rendering
25
- # and testing)
26
- def data
27
- templates = @templates.deep_clone
25
+ # Returns a parsed version of the data (useful for backend rendering
26
+ # and testing)
27
+ def data
28
+ templates = @templates.deep_clone
28
29
 
29
- templates.each_pair do |name, value|
30
- if value['bindings']
31
- value['bindings'].each_pair do |number, binding|
32
- value['bindings'][number] = binding.map {|code| eval(code) }
30
+ templates.each_pair do |name, value|
31
+ if value['bindings']
32
+ value['bindings'].each_pair do |number, binding|
33
+ value['bindings'][number] = binding.map { |code| eval(code) }
34
+ end
33
35
  end
34
36
  end
35
- end
36
37
 
37
- return templates
38
+ return templates
39
+ end
38
40
  end
39
- end
41
+ end