opulent 1.5.5 → 1.6.0

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