opulent 1.5.5 → 1.6.0

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +13 -0
  3. data/{LICENSE → LICENSE.md} +0 -0
  4. data/bin/opulent +0 -0
  5. data/lib/opulent.rb +10 -10
  6. data/lib/opulent/compiler.rb +15 -9
  7. data/lib/opulent/compiler/buffer.rb +123 -62
  8. data/lib/opulent/compiler/comment.rb +3 -4
  9. data/lib/opulent/compiler/control.rb +20 -26
  10. data/lib/opulent/compiler/define.rb +88 -36
  11. data/lib/opulent/compiler/doctype.rb +20 -22
  12. data/lib/opulent/compiler/eval.rb +23 -2
  13. data/lib/opulent/compiler/filter.rb +4 -5
  14. data/lib/opulent/compiler/node.rb +18 -12
  15. data/lib/opulent/compiler/root.rb +4 -5
  16. data/lib/opulent/compiler/text.rb +7 -2
  17. data/lib/opulent/compiler/yield.rb +2 -3
  18. data/lib/opulent/engine.rb +21 -20
  19. data/lib/opulent/exec.rb +21 -63
  20. data/lib/opulent/logger.rb +230 -3
  21. data/lib/opulent/parser.rb +14 -76
  22. data/lib/opulent/parser/comment.rb +45 -34
  23. data/lib/opulent/parser/control.rb +132 -111
  24. data/lib/opulent/parser/define.rb +15 -12
  25. data/lib/opulent/parser/doctype.rb +15 -15
  26. data/lib/opulent/parser/eval.rb +16 -6
  27. data/lib/opulent/parser/expression.rb +87 -84
  28. data/lib/opulent/parser/filter.rb +31 -25
  29. data/lib/opulent/parser/include.rb +38 -42
  30. data/lib/opulent/parser/node.rb +136 -118
  31. data/lib/opulent/parser/root.rb +24 -18
  32. data/lib/opulent/parser/text.rb +150 -123
  33. data/lib/opulent/parser/yield.rb +23 -23
  34. data/lib/opulent/settings.rb +70 -51
  35. data/lib/opulent/tokens.rb +17 -15
  36. data/lib/opulent/utils.rb +5 -4
  37. data/lib/opulent/version.rb +1 -1
  38. metadata +4 -43
  39. data/.libold/opulent.rb +0 -96
  40. data/.libold/opulent/context.rb +0 -80
  41. data/.libold/opulent/engine.rb +0 -88
  42. data/.libold/opulent/filter.rb +0 -101
  43. data/.libold/opulent/logger.rb +0 -67
  44. data/.libold/opulent/nodes.rb +0 -13
  45. data/.libold/opulent/nodes/block.rb +0 -29
  46. data/.libold/opulent/nodes/comment.rb +0 -35
  47. data/.libold/opulent/nodes/control.rb +0 -230
  48. data/.libold/opulent/nodes/define.rb +0 -42
  49. data/.libold/opulent/nodes/eval.rb +0 -41
  50. data/.libold/opulent/nodes/expression.rb +0 -28
  51. data/.libold/opulent/nodes/filter.rb +0 -70
  52. data/.libold/opulent/nodes/helper.rb +0 -69
  53. data/.libold/opulent/nodes/node.rb +0 -101
  54. data/.libold/opulent/nodes/root.rb +0 -62
  55. data/.libold/opulent/nodes/text.rb +0 -54
  56. data/.libold/opulent/nodes/theme.rb +0 -36
  57. data/.libold/opulent/parser.rb +0 -252
  58. data/.libold/opulent/parser/block.rb +0 -70
  59. data/.libold/opulent/parser/comment.rb +0 -32
  60. data/.libold/opulent/parser/control.rb +0 -83
  61. data/.libold/opulent/parser/define.rb +0 -39
  62. data/.libold/opulent/parser/eval.rb +0 -33
  63. data/.libold/opulent/parser/expression.rb +0 -350
  64. data/.libold/opulent/parser/filter.rb +0 -41
  65. data/.libold/opulent/parser/node.rb +0 -232
  66. data/.libold/opulent/parser/root.rb +0 -96
  67. data/.libold/opulent/parser/text.rb +0 -114
  68. data/.libold/opulent/parser/theme.rb +0 -36
  69. data/.libold/opulent/preprocessor.rb +0 -102
  70. data/.libold/opulent/runtime.rb +0 -144
  71. data/.libold/opulent/template.rb +0 -43
  72. data/.libold/opulent/tokens.rb +0 -276
  73. data/.libold/opulent/version.rb +0 -5
  74. data/.travis.yml +0 -4
  75. data/benchmark/benchmark.rb +0 -57
  76. data/benchmark/cases/node/node.haml +0 -7
  77. data/benchmark/cases/node/node.op +0 -7
  78. data/benchmark/cases/node/node.slim +0 -7
@@ -2,62 +2,58 @@
2
2
  module Opulent
3
3
  # @Parser
4
4
  class Parser
5
- # Check if we match a new node definition to use within our page.
5
+ # Check if we have an include node, which will include a new file inside
6
+ # of the current one to be parsed
6
7
  #
7
- # Definitions will not be recursive because, by the time we parse
8
- # the definition children, the definition itself is not in the
9
- # knowledgebase yet.
8
+ # @param parent [Array] Parent node to which we append to
10
9
  #
11
- # However, we may use previously defined nodes inside new definitions,
12
- # due to the fact that they are known at parse time.
13
- #
14
- # @param nodes [Array] Parent node to which we append to
15
- #
16
- def include_file(parent, indent)
17
- if(match = accept :include)
10
+ def include_file(_parent, indent)
11
+ return unless accept :include
18
12
 
19
- # Process data
20
- name = accept :line_feed || ""
21
- name.strip!
13
+ # Process data
14
+ name = accept :line_feed || ''
15
+ name.strip!
22
16
 
17
+ # Check if there is any string after the include input
18
+ Logger.error :parse, @code, @i, @j, :include_end if name.empty?
23
19
 
24
- # Check if there is any string after the include input
25
- if name.empty?
26
- error :include_end
27
- end
28
-
29
- # Get the complete file path based on the current file being compiled
30
- include_path = File.expand_path name, File.dirname(@file[-1][0])
31
-
32
- # Try to see if it has any existing extension, otherwise add .op
33
- include_path += Settings::FILE_EXTENSION if File.extname(name).empty?
34
-
35
- # Throw an error if the file doesn't exist
36
- error :include, name unless Dir[include_path].any?
20
+ # Get the complete file path based on the current file being compiled
21
+ include_path = File.expand_path name, File.dirname(@file[-1][0])
37
22
 
38
- # include entire directory tree
39
- Dir[include_path].each do |file|
40
- # Skip current file when including from same directory
41
- next if file == @file[-1][0]
23
+ # Try to see if it has any existing extension, otherwise add .op
24
+ include_path += Settings::FILE_EXTENSION if File.extname(name).empty?
42
25
 
43
- @file << [include_path, indent]
26
+ # Throw an error if the file doesn't exist
27
+ unless Dir[include_path].any?
28
+ Logger.error :parse, @code, @i, @j, :include, name
29
+ end
44
30
 
45
- # Throw an error if the file doesn't exist
46
- error :include_dir, file if File.directory? file
31
+ # include entire directory tree
32
+ Dir[include_path].each do |file|
33
+ # Skip current file when including from same directory
34
+ next if file == @file[-1][0]
47
35
 
48
- # Throw an error if the file doesn't exist
49
- error :include, file unless File.file? file
36
+ @file << [include_path, indent]
50
37
 
51
- # Indent all lines and prepare them for the parser
52
- lines = indent_lines File.read(file), ' ' * indent
53
- lines << ' '
38
+ # Throw an error if the file doesn't exist
39
+ if File.directory? file
40
+ Logger.error :parse, @code, @i, @j, :include_dir, file
41
+ end
54
42
 
55
- # Indent all the output lines with the current indentation
56
- @code.insert @i + 1, *lines.lines
43
+ # Throw an error if the file doesn't exist
44
+ unless File.file? file
45
+ Logger.error :parse, @code, @i, @j, :include, file
57
46
  end
58
47
 
59
- return true
48
+ # Indent all lines and prepare them for the parser
49
+ lines = indent_lines File.read(file), ' ' * indent
50
+ lines << ' '
51
+
52
+ # Indent all the output lines with the current indentation
53
+ @code.insert @i + 1, *lines.lines
60
54
  end
55
+
56
+ true
61
57
  end
62
58
  end
63
59
  end
@@ -10,83 +10,82 @@ module Opulent
10
10
  # @param parent [Node] Parent node to which we append the node
11
11
  #
12
12
  def node(parent, indent = nil)
13
- if (name = lookahead(:node_lookahead) || lookahead(:shorthand_lookahead))
14
- return nil if KEYWORDS.include? name[0].to_sym
15
-
16
- # Accept either explicit node_name or implicit :div node_name
17
- # with shorthand attributes
18
- if (node_name = accept :node)
19
- node_name = node_name.to_sym
20
- shorthand = shorthand_attributes
21
- elsif (shorthand = shorthand_attributes)
22
- node_name = :div
23
- end
13
+ return unless (name = lookahead(:node_lookahead) ||
14
+ lookahead(:shorthand_lookahead))
15
+
16
+ return nil if KEYWORDS.include? name[0].to_sym
17
+
18
+ # Accept either explicit node_name or implicit :div node_name
19
+ # with shorthand attributes
20
+ if (node_name = accept :node)
21
+ node_name = node_name.to_sym
22
+ shorthand = shorthand_attributes
23
+ elsif (shorthand = shorthand_attributes)
24
+ node_name = :div
25
+ end
24
26
 
25
- # Node creation options
26
- options = {}
27
+ # Node creation options
28
+ options = {}
27
29
 
28
- # Get leading and trailing whitespace
29
- if accept_stripped :leading_whitespace
30
- options[:leading_whitespace] = true
31
- if accept :leading_trailing_whitespace
32
- options[:trailing_whitespace] = true
33
- end
34
- elsif accept_stripped :trailing_whitespace
35
- options[:trailing_whitespace] = true
36
- end
30
+ # Get leading whitespace
31
+ options[:leading_whitespace] = accept_stripped(:leading_whitespace)
37
32
 
38
- # Get wrapped node attributes
39
- atts = attributes(shorthand) || {}
33
+ # Get trailing whitespace
34
+ options[:trailing_whitespace] = accept_stripped(:trailing_whitespace)
40
35
 
41
- # Inherit attributes from definition
42
- options[:extension] = extension = extend_attributes
36
+ # Get wrapped node attributes
37
+ atts = attributes(shorthand) || {}
43
38
 
44
- # Get unwrapped node attributes
45
- options[:attributes] = attributes_assignments atts, false
39
+ # Inherit attributes from definition
40
+ options[:extension] = extend_attributes
46
41
 
47
- # Create node
48
- current_node = [:node, node_name, options, [], indent]
42
+ # Get unwrapped node attributes
43
+ options[:attributes] = attributes_assignments atts, false
49
44
 
50
- # Check if the node is explicitly self enclosing
51
- if(close = accept_stripped :self_enclosing) || (!@definitions.keys.include?(node_name) && Settings::SelfEnclosing.include?(node_name))
52
- current_node[@options][:self_enclosing] = true
45
+ # Create node
46
+ current_node = [:node, node_name, options, [], indent]
53
47
 
54
- unless close.nil? || close.strip.empty?
55
- undo close; error :self_enclosing
56
- end
48
+ # Check for self enclosing tags and definitions
49
+ def_check = !@definitions.keys.include?(node_name) &&
50
+ Settings::SELF_ENCLOSING.include?(node_name)
57
51
 
58
- # For self enclosing tag error reporting purposes
59
- line = @i
60
- end
52
+ # Check if the node is explicitly self enclosing
53
+ if (close = accept_stripped :self_enclosing) || def_check
54
+ current_node[@options][:self_enclosing] = true
61
55
 
62
- # Check whether we have explicit inline elements and add them
63
- # with increased base indentation
64
- if (accept :inline_child)
65
- # Inline node element
66
- unless (child_node = node current_node, indent)
67
- error :inline_child
68
- end
69
- else
70
- # Inline text element
71
- text_node = text current_node, indent, false
56
+ unless close.nil? || close.strip.empty?
57
+ undo close
58
+ Logger.error :parse, @code, @i, @j, :self_enclosing
72
59
  end
60
+ end
73
61
 
74
- # Add the current node to the root
75
- root(current_node, indent)
62
+ # Check whether we have explicit inline elements and add them
63
+ # with increased base indentation
64
+ if accept :inline_child
65
+ # Inline node element
66
+ Logger.error :parse,
67
+ @code,
68
+ @i,
69
+ @j,
70
+ :inline_child unless node current_node, indent
71
+ elsif comment current_node, indent
72
+ # Accept same line comments
73
+ else
74
+ # Accept inline text element
75
+ text current_node, indent, false
76
+ end
76
77
 
77
- # if current_node[@options][:self_enclosing] && current_node[@children].any?
78
- # error :self_enclosing_children, line
79
- # end
78
+ # Add the current node to the root
79
+ root current_node, indent
80
80
 
81
- # Create a clone of the definition model. Cloning the options is also
82
- # necessary because it's a shallow copy
83
- if @definitions.keys.include?(node_name)
84
- @definition_stack << node_name
85
- parent[@children] << process_definition(node_name, current_node)
86
- @definition_stack.pop
87
- else
88
- parent[@children] << current_node
89
- end
81
+ # Create a clone of the definition model. Cloning the options is also
82
+ # necessary because it's a shallow copy
83
+ if @definitions.keys.include?(node_name)
84
+ @definition_stack << node_name
85
+ parent[@children] << process_definition(node_name, current_node)
86
+ @definition_stack.pop
87
+ else
88
+ parent[@children] << current_node
90
89
  end
91
90
  end
92
91
 
@@ -107,13 +106,18 @@ module Opulent
107
106
  process_definition_child model[@options][:call]
108
107
  process_definition_child model
109
108
 
110
- return model
109
+ model
111
110
  end
112
111
 
112
+ # Process definition children for the current node.
113
+ #
114
+ # @param node [Node] Callee node
115
+ #
113
116
  def process_definition_child(node)
114
117
  node[@children].map! do |child|
115
118
  if child[@type] == :node
116
- if !@definition_stack.include?(child[@value]) && @definitions.keys.include?(child[@value])
119
+ if !@definition_stack.include?(child[@value]) &&
120
+ @definitions.keys.include?(child[@value])
117
121
  process_definition child[@value], child
118
122
  else
119
123
  process_definition_child child if child[@children]
@@ -154,20 +158,20 @@ module Opulent
154
158
  #
155
159
  def shorthand_attributes(atts = {})
156
160
  while (key = accept :shorthand)
157
- key = Settings::Shorthand[key.to_sym]
161
+ key = Settings::SHORTHAND[key.to_sym]
158
162
 
159
163
  # Check whether the value is escaped or unescaped
160
164
  escaped = accept(:unescaped_value) ? false : true
161
165
 
162
166
  # Get the attribute value and process it
163
167
  if (value = accept(:node))
164
- value = [:expression, value.inspect, {escaped: escaped}]
168
+ value = [:expression, value.inspect, { escaped: escaped }]
165
169
  elsif (value = accept(:exp_string))
166
- value = [:expression, value, {escaped: escaped}]
170
+ value = [:expression, value, { escaped: escaped }]
167
171
  elsif (value = paranthesis)
168
- value = [:expression, value, {escaped: escaped}]
172
+ value = [:expression, value, { escaped: escaped }]
169
173
  else
170
- error :shorthand
174
+ Logger.error :parse, @code, @i, @j, :shorthand
171
175
  end
172
176
 
173
177
  # IDs are unique, the rest of the attributes turn into arrays in
@@ -175,17 +179,19 @@ module Opulent
175
179
  add_attribute(atts, key, value)
176
180
  end
177
181
 
178
- return atts
182
+ atts
179
183
  end
180
184
 
185
+ # Get element attributes
186
+ #
187
+ # @atts [Hash] Accumulator for node attributes
188
+ #
181
189
  def attributes(atts = {})
182
190
  wrapped_attributes atts
183
191
  attributes_assignments atts, false
184
-
185
- return atts
192
+ atts
186
193
  end
187
194
 
188
-
189
195
  # Check if we match node attributes
190
196
  #
191
197
  # [ assignments ]
@@ -194,11 +200,14 @@ module Opulent
194
200
  #
195
201
  def wrapped_attributes(list)
196
202
  if (bracket = accept :brackets)
197
- attributes_assignments list
198
- accept bracket.to_sym, :*
203
+ accept_newline
204
+ attributes_assignments list, true
205
+ accept_newline
206
+
207
+ accept_stripped bracket.to_sym, :*
199
208
  end
200
209
 
201
- return list
210
+ list
202
211
  end
203
212
 
204
213
  # Check if we match an expression node or
@@ -206,53 +215,63 @@ module Opulent
206
215
  #
207
216
  # [ assignments ]
208
217
  #
209
- # @param parent [Hash] Parent to which we append nodes
218
+ # @param list [Hash] Parent to which we append nodes
210
219
  # @param as_parameters [Boolean] Accept or reject identifier nodes
211
220
  #
212
- def attributes_assignments(parent, wrapped = true)
213
- unless wrapped
214
- return parent if lookahead(:assignment_lookahead).nil?
221
+ def attributes_assignments(list, wrapped = true)
222
+ if wrapped && lookahead(:exp_identifier_stripped_lookahead).nil? ||
223
+ !wrapped && lookahead(:assignment_lookahead).nil?
224
+ return list
215
225
  end
216
226
 
217
- if (argument = accept_stripped :node)
218
- argument = argument.to_sym
227
+ return unless (argument = accept_stripped :node)
219
228
 
220
- if accept :assignment
221
- # Check if we have an attribute escape or not
222
- escaped = if accept :assignment_unescaped
223
- false
224
- else
225
- true
226
- end
229
+ argument = argument.to_sym
227
230
 
228
- # Get the argument value if we have an assignment
229
- if (value = expression(false, wrapped))
230
- value[@options][:escaped] = escaped
231
+ if accept_stripped :assignment
232
+ # Check if we have an attribute escape or not
233
+ escaped = if accept :assignment_unescaped
234
+ false
235
+ else
236
+ true
237
+ end
231
238
 
232
- # IDs are unique, the rest of the attributes turn into arrays in
233
- # order to allow multiple values or identifiers
234
- add_attribute(parent, argument, value)
235
- else
236
- error :assignments_colon
237
- end
239
+ # Get the argument value if we have an assignment
240
+ if (value = expression(false, wrapped))
241
+ value[@options][:escaped] = escaped
242
+
243
+ # IDs are unique, the rest of the attributes turn into arrays in
244
+ # order to allow multiple values or identifiers
245
+ add_attribute(list, argument, value)
238
246
  else
239
- parent[argument] = [:expression, "nil", {escaped: false}] unless parent[argument]
247
+ Logger.error :parse, @code, @i, @j, :assignments_colon
240
248
  end
241
-
242
- # If our attributes are wrapped, we allow method calls without
243
- # paranthesis, ruby style, therefore we need a terminator to signify
244
- # the expression end. If they are not wrapped (inline), we require
245
- # paranthesis and allow inline calls
246
- if wrapped && accept_stripped(:assignment_terminator)
247
- attributes_assignments parent, wrapped
248
- elsif !wrapped && lookahead(:assignment_lookahead)
249
- attributes_assignments parent, wrapped
249
+ else
250
+ unless list[argument]
251
+ list[argument] = [:expression, 'true', { escaped: false }]
250
252
  end
253
+ end
251
254
 
252
- return parent
253
- elsif !parent.empty?
254
- error :assignments_comma
255
+ # If our attributes are wrapped, we allow method calls without
256
+ # paranthesis, ruby style, therefore we need a terminator to signify
257
+ # the expression end. If they are not wrapped (inline), we require
258
+ # paranthesis and allow inline calls
259
+ if wrapped
260
+ # Accept optional comma between attributes
261
+ accept_stripped :assignment_terminator
262
+
263
+ # Lookahead for attributes on the current line and the next one
264
+ if lookahead(:exp_identifier_stripped_lookahead)
265
+ attributes_assignments list, wrapped
266
+ elsif lookahead_next_line(:exp_identifier_stripped_lookahead)
267
+ accept_newline
268
+ attributes_assignments list, wrapped
269
+ end
270
+ elsif !wrapped && lookahead(:assignment_lookahead)
271
+ attributes_assignments list, wrapped
255
272
  end
273
+
274
+ list
256
275
  end
257
276
 
258
277
  # Extend node attributes with hash from
@@ -262,14 +281,13 @@ module Opulent
262
281
  # +(paranthesis)
263
282
  #
264
283
  def extend_attributes
265
- if (accept :extend_attributes)
266
- unescaped = accept :unescaped_value
284
+ return unless accept :extend_attributes
285
+ unescaped = accept :unescaped_value
267
286
 
268
- extension = expression(false, false, false)
269
- extension[@options][:escaped] = false if unescaped
287
+ extension = expression(false, false, false)
288
+ extension[@options][:escaped] = !unescaped
270
289
 
271
- return extension
272
- end
290
+ extension
273
291
  end
274
292
  end
275
293
  end
@@ -9,9 +9,12 @@ module Opulent
9
9
  # @param nodes [Array] Parent node to which we append to
10
10
  #
11
11
  def root(parent = @root, min_indent = -1)
12
- while(@line = @code[(@i += 1)])
12
+ while (@line = @code[(@i += 1)])
13
+ # Reset character position cursor
14
+ @j = 0
15
+
13
16
  # Skip to next iteration if we have a blank line
14
- if @line =~ /\A\s*\Z/ then next end
17
+ next if @line =~ /\A\s*\Z/
15
18
 
16
19
  # Reset the line offset
17
20
  @offset = 0
@@ -23,7 +26,8 @@ module Opulent
23
26
  # Stop using the current parent as root if it does not match the
24
27
  # minimum indentation includements
25
28
  unless min_indent < indent
26
- @i -= 1; break
29
+ @i -= 1
30
+ break
27
31
  end
28
32
 
29
33
  # If last include path had a greater indentation, pop the last file path
@@ -31,23 +35,25 @@ module Opulent
31
35
 
32
36
  # Try the main Opulent node types and process each one of them using
33
37
  # their matching evaluation procedure
34
- current_node = node(parent, indent) ||
35
- text(parent, indent) ||
36
- comment(parent, indent) ||
37
- define(parent, indent) ||
38
- control(parent, indent) ||
39
- evaluate(parent, indent) ||
40
- filter(parent, indent) ||
41
- block_yield(parent, indent) ||
42
- include_file(parent, indent)||
43
- html_text(parent, indent) ||
44
- doctype(parent, indent)
45
-
46
- # Throw an error if we couldn't find a valid node
47
- error :unknown_node_type unless current_node
38
+ current_node = node(parent, indent) ||
39
+ text(parent, indent) ||
40
+ comment(parent, indent) ||
41
+ define(parent, indent) ||
42
+ control(parent, indent) ||
43
+ evaluate(parent, indent) ||
44
+ filter(parent, indent) ||
45
+ block_yield(parent, indent) ||
46
+ include_file(parent, indent) ||
47
+ html_text(parent, indent) ||
48
+ doctype(parent, indent)
49
+
50
+ # Throw an error if we couldn't find any valid node
51
+ unless current_node
52
+ Logger.error :parse, @code, @i, @j, :unknown_node_type
53
+ end
48
54
  end
49
55
 
50
- return parent
56
+ parent
51
57
  end
52
58
  end
53
59
  end