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.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +13 -0
- data/{LICENSE → LICENSE.md} +0 -0
- data/bin/opulent +0 -0
- data/lib/opulent.rb +10 -10
- data/lib/opulent/compiler.rb +15 -9
- data/lib/opulent/compiler/buffer.rb +123 -62
- data/lib/opulent/compiler/comment.rb +3 -4
- data/lib/opulent/compiler/control.rb +20 -26
- data/lib/opulent/compiler/define.rb +88 -36
- data/lib/opulent/compiler/doctype.rb +20 -22
- data/lib/opulent/compiler/eval.rb +23 -2
- data/lib/opulent/compiler/filter.rb +4 -5
- data/lib/opulent/compiler/node.rb +18 -12
- data/lib/opulent/compiler/root.rb +4 -5
- data/lib/opulent/compiler/text.rb +7 -2
- data/lib/opulent/compiler/yield.rb +2 -3
- data/lib/opulent/engine.rb +21 -20
- data/lib/opulent/exec.rb +21 -63
- data/lib/opulent/logger.rb +230 -3
- data/lib/opulent/parser.rb +14 -76
- data/lib/opulent/parser/comment.rb +45 -34
- data/lib/opulent/parser/control.rb +132 -111
- data/lib/opulent/parser/define.rb +15 -12
- data/lib/opulent/parser/doctype.rb +15 -15
- data/lib/opulent/parser/eval.rb +16 -6
- data/lib/opulent/parser/expression.rb +87 -84
- data/lib/opulent/parser/filter.rb +31 -25
- data/lib/opulent/parser/include.rb +38 -42
- data/lib/opulent/parser/node.rb +136 -118
- data/lib/opulent/parser/root.rb +24 -18
- data/lib/opulent/parser/text.rb +150 -123
- data/lib/opulent/parser/yield.rb +23 -23
- data/lib/opulent/settings.rb +70 -51
- data/lib/opulent/tokens.rb +17 -15
- data/lib/opulent/utils.rb +5 -4
- data/lib/opulent/version.rb +1 -1
- metadata +4 -43
- data/.libold/opulent.rb +0 -96
- data/.libold/opulent/context.rb +0 -80
- data/.libold/opulent/engine.rb +0 -88
- data/.libold/opulent/filter.rb +0 -101
- data/.libold/opulent/logger.rb +0 -67
- data/.libold/opulent/nodes.rb +0 -13
- data/.libold/opulent/nodes/block.rb +0 -29
- data/.libold/opulent/nodes/comment.rb +0 -35
- data/.libold/opulent/nodes/control.rb +0 -230
- data/.libold/opulent/nodes/define.rb +0 -42
- data/.libold/opulent/nodes/eval.rb +0 -41
- data/.libold/opulent/nodes/expression.rb +0 -28
- data/.libold/opulent/nodes/filter.rb +0 -70
- data/.libold/opulent/nodes/helper.rb +0 -69
- data/.libold/opulent/nodes/node.rb +0 -101
- data/.libold/opulent/nodes/root.rb +0 -62
- data/.libold/opulent/nodes/text.rb +0 -54
- data/.libold/opulent/nodes/theme.rb +0 -36
- data/.libold/opulent/parser.rb +0 -252
- data/.libold/opulent/parser/block.rb +0 -70
- data/.libold/opulent/parser/comment.rb +0 -32
- data/.libold/opulent/parser/control.rb +0 -83
- data/.libold/opulent/parser/define.rb +0 -39
- data/.libold/opulent/parser/eval.rb +0 -33
- data/.libold/opulent/parser/expression.rb +0 -350
- data/.libold/opulent/parser/filter.rb +0 -41
- data/.libold/opulent/parser/node.rb +0 -232
- data/.libold/opulent/parser/root.rb +0 -96
- data/.libold/opulent/parser/text.rb +0 -114
- data/.libold/opulent/parser/theme.rb +0 -36
- data/.libold/opulent/preprocessor.rb +0 -102
- data/.libold/opulent/runtime.rb +0 -144
- data/.libold/opulent/template.rb +0 -43
- data/.libold/opulent/tokens.rb +0 -276
- data/.libold/opulent/version.rb +0 -5
- data/.travis.yml +0 -4
- data/benchmark/benchmark.rb +0 -57
- data/benchmark/cases/node/node.haml +0 -7
- data/benchmark/cases/node/node.op +0 -7
- data/benchmark/cases/node/node.slim +0 -7
data/lib/opulent/parser/text.rb
CHANGED
@@ -1,123 +1,150 @@
|
|
1
|
-
# @Opulent
|
2
|
-
module Opulent
|
3
|
-
# @Parser
|
4
|
-
class Parser
|
5
|
-
# Match one line or multiline, escaped or unescaped text
|
6
|
-
#
|
7
|
-
# @param parent [Array] Parent node element
|
8
|
-
# @param indent [Fixnum] Size of the current indentation
|
9
|
-
# @param multiline_or_print [Boolean] Allow only multiline text or print
|
10
|
-
#
|
11
|
-
def text(parent, indent = nil, multiline_or_print = true)
|
12
|
-
# Try to see if we can match a multiline operator. If we can accept_stripped only
|
13
|
-
# multiline, which is the case for filters, undo the operation.
|
14
|
-
if accept :multiline
|
15
|
-
multiline = true
|
16
|
-
elsif multiline_or_print
|
17
|
-
return nil unless lookahead :print_lookahead
|
18
|
-
end
|
19
|
-
|
20
|
-
# Get text node type
|
21
|
-
type =
|
22
|
-
|
23
|
-
# Check if the text or print node is escaped or unescaped
|
24
|
-
escaped = accept(:unescaped_value) ? false : true
|
25
|
-
|
26
|
-
# Get
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
#
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match one line or multiline, escaped or unescaped text
|
6
|
+
#
|
7
|
+
# @param parent [Array] Parent node element
|
8
|
+
# @param indent [Fixnum] Size of the current indentation
|
9
|
+
# @param multiline_or_print [Boolean] Allow only multiline text or print
|
10
|
+
#
|
11
|
+
def text(parent, indent = nil, multiline_or_print = true)
|
12
|
+
# Try to see if we can match a multiline operator. If we can accept_stripped only
|
13
|
+
# multiline, which is the case for filters, undo the operation.
|
14
|
+
if accept :multiline
|
15
|
+
multiline = true
|
16
|
+
elsif multiline_or_print
|
17
|
+
return nil unless lookahead :print_lookahead
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get text node type
|
21
|
+
type = accept(:print) ? :print : :text
|
22
|
+
|
23
|
+
# Check if the text or print node is escaped or unescaped
|
24
|
+
escaped = accept(:unescaped_value) ? false : true
|
25
|
+
|
26
|
+
# Get leading whitespace
|
27
|
+
leading_whitespace = accept(:leading_whitespace)
|
28
|
+
|
29
|
+
# Get trailing whitespace
|
30
|
+
trailing_whitespace = accept(:trailing_whitespace)
|
31
|
+
|
32
|
+
# Get text value
|
33
|
+
value = accept :line_feed
|
34
|
+
value = value[1..-1] if value[0] == '\\'
|
35
|
+
|
36
|
+
# Create the text node using input data
|
37
|
+
text_node = [
|
38
|
+
:plain,
|
39
|
+
type,
|
40
|
+
{
|
41
|
+
value: value.strip,
|
42
|
+
escaped: escaped,
|
43
|
+
leading_whitespace: leading_whitespace,
|
44
|
+
trailing_whitespace: trailing_whitespace
|
45
|
+
},
|
46
|
+
nil,
|
47
|
+
indent
|
48
|
+
]
|
49
|
+
|
50
|
+
# If we have a multiline node, get all the text which has higher
|
51
|
+
# indentation than our indentation node.
|
52
|
+
if multiline
|
53
|
+
text_node[@options][:value] += accept(:newline) || ''
|
54
|
+
text_node[@options][:value] += get_indented_lines(indent)
|
55
|
+
text_node[@options][:value].strip!
|
56
|
+
elsif value.empty?
|
57
|
+
# If our value is empty and we're not going to add any more lines to
|
58
|
+
# our buffer, skip the node
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Increase indentation if this is an inline text node
|
63
|
+
text_node[@indent] += @settings[:indent] unless multiline_or_print
|
64
|
+
|
65
|
+
# Add text node to the parent element
|
66
|
+
parent[@children] << text_node
|
67
|
+
end
|
68
|
+
|
69
|
+
# Match one line or multiline, escaped or unescaped text
|
70
|
+
#
|
71
|
+
def html_text(parent, indent)
|
72
|
+
return unless (text_feed = accept :html_text)
|
73
|
+
|
74
|
+
text_node = [
|
75
|
+
:plain,
|
76
|
+
:text,
|
77
|
+
{
|
78
|
+
value: text_feed.strip,
|
79
|
+
escaped: false
|
80
|
+
},
|
81
|
+
nil,
|
82
|
+
indent
|
83
|
+
]
|
84
|
+
|
85
|
+
parent[@children] << text_node
|
86
|
+
end
|
87
|
+
|
88
|
+
# Match a whitespace by preventing code trimming
|
89
|
+
#
|
90
|
+
def whitespace(required = false)
|
91
|
+
accept :whitespace, required
|
92
|
+
end
|
93
|
+
|
94
|
+
# Gather all the lines which have higher indentation than the one given as
|
95
|
+
# parameter and put them into the buffer
|
96
|
+
#
|
97
|
+
# @param indentation [Fixnum] parent node strating indentation
|
98
|
+
#
|
99
|
+
def get_indented_lines(indent)
|
100
|
+
buffer = ''
|
101
|
+
|
102
|
+
# Gather multiple blank lines between lines of text
|
103
|
+
blank_lines = proc do
|
104
|
+
while lookahead_next_line :line_whitespace
|
105
|
+
@line = @code[(@i += 1)]
|
106
|
+
@offset = 0
|
107
|
+
|
108
|
+
buffer += accept :line_whitespace
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get blank lines until we match something
|
113
|
+
blank_lines[]
|
114
|
+
|
115
|
+
# Get the next indentation after the parent line
|
116
|
+
# and set it as primary indent
|
117
|
+
first_indent = (lookahead_next_line(:indent).to_s || '').size
|
118
|
+
next_indent = first_indent
|
119
|
+
|
120
|
+
# While the indentation is smaller, add the line feed to our buffer
|
121
|
+
while next_indent > indent
|
122
|
+
# Advance current line and reset offset
|
123
|
+
@line = @code[(@i += 1)]
|
124
|
+
@offset = 0
|
125
|
+
|
126
|
+
# Get leading whitespace trimmed with first_indent's size
|
127
|
+
next_line_indent = accept(:indent)[first_indent..-1] || ''
|
128
|
+
next_line_indent = next_line_indent.size
|
129
|
+
|
130
|
+
# Add next line feed, prepend the indent and append the newline
|
131
|
+
buffer += ' ' * next_line_indent if next_line_indent > 0
|
132
|
+
buffer += accept_stripped(:line_feed) || ''
|
133
|
+
buffer += accept(:newline) || ''
|
134
|
+
|
135
|
+
# Get blank lines until we match something
|
136
|
+
blank_lines[]
|
137
|
+
|
138
|
+
# Check the indentation on the following line. When we reach EOF,
|
139
|
+
# set the indentation to 0 and cause the loop to stop
|
140
|
+
if (next_indent = lookahead_next_line :indent)
|
141
|
+
next_indent = next_indent[0].size
|
142
|
+
else
|
143
|
+
next_indent = 0
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
buffer
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/lib/opulent/parser/yield.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
# @Opulent
|
2
|
-
module Opulent
|
3
|
-
# @Parser
|
4
|
-
class Parser
|
5
|
-
# Match a yield with a explicit or implicit target
|
6
|
-
#
|
7
|
-
# yield target
|
8
|
-
#
|
9
|
-
# @param parent [Node] Parent node to which we append the definition
|
10
|
-
#
|
11
|
-
def block_yield(parent, indent)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
1
|
+
# @Opulent
|
2
|
+
module Opulent
|
3
|
+
# @Parser
|
4
|
+
class Parser
|
5
|
+
# Match a yield with a explicit or implicit target
|
6
|
+
#
|
7
|
+
# yield target
|
8
|
+
#
|
9
|
+
# @param parent [Node] Parent node to which we append the definition
|
10
|
+
#
|
11
|
+
def block_yield(parent, indent)
|
12
|
+
return unless accept :yield
|
13
|
+
|
14
|
+
# Consume the newline from the end of the element
|
15
|
+
error :yield unless accept(:line_feed).strip.empty?
|
16
|
+
|
17
|
+
# Create a new node
|
18
|
+
yield_node = [:yield, nil, {}, [], indent]
|
19
|
+
|
20
|
+
parent[@children] << yield_node
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/opulent/settings.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# @Opulent
|
2
2
|
module Opulent
|
3
3
|
# @Settings
|
4
|
-
|
4
|
+
class Settings
|
5
5
|
# Set buffer variable name
|
6
6
|
BUFFER = :@_opulent_buffer
|
7
7
|
|
@@ -9,76 +9,95 @@ module Opulent
|
|
9
9
|
FILE_EXTENSION = '.op'
|
10
10
|
|
11
11
|
# Default yield target which is used for child block replacements
|
12
|
-
|
12
|
+
DEFAULT_EACH_KEY = :key
|
13
13
|
|
14
14
|
# Default yield target which is used for child block replacements
|
15
|
-
|
15
|
+
DEFAULT_EACH_VALUE = :value
|
16
16
|
|
17
17
|
# List of self enclosing node elements
|
18
|
-
|
18
|
+
SELF_ENCLOSING = %i(
|
19
|
+
img link input meta br hr area base col command embed keygen param source
|
20
|
+
track wbr
|
21
|
+
)
|
19
22
|
|
20
23
|
# List of inline node parents which can be either inline or have complex
|
21
24
|
# structures inside of them, such as anchor tags
|
22
|
-
|
25
|
+
MULTI_NODE = %i(a)
|
23
26
|
|
24
27
|
# List of inline node names
|
25
|
-
|
28
|
+
INLINE_NODE = %i(
|
29
|
+
text a span strong em br i b small label sub sup abbr var code kbd
|
30
|
+
)
|
26
31
|
|
27
32
|
# Check whether text should or shouldn't be evaluated
|
28
|
-
|
33
|
+
INTERPOLATION_CHECK = /(?<!\\)\#\{.*\}/
|
29
34
|
|
30
35
|
# Check if the attribute value is a bare string
|
31
|
-
|
36
|
+
EVALUATION_CHECK = /\A(("((?:[^"\\]|\\.)*?)")|('(?:[^'\\]|\\.)*?')|true|false|nil)\Z/
|
37
|
+
|
38
|
+
# Check to see if we need to insert an end block for the current evaluation
|
39
|
+
# control do || .* end
|
40
|
+
END_INSERTION = /\A(if|begin|unless|else|elsif|when|rescue|ensure)\b|\bdo\s*(\|[^\|]*\|)?\s*$/
|
41
|
+
END_REMOVAL = /\A(else|elsif|when|rescue|ensure)/
|
42
|
+
END_EXPLICIT = /\A(end)/
|
32
43
|
|
33
44
|
# Shorthand attribute associations
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
45
|
+
SHORTHAND = {
|
46
|
+
'.': :class,
|
47
|
+
'#': :id,
|
48
|
+
'&': :name
|
38
49
|
}
|
39
50
|
|
40
|
-
#
|
41
|
-
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
pretty: false, # Under work
|
49
|
-
default_layout: :'views/layouts/application'
|
50
|
-
}
|
51
|
-
|
52
|
-
# Set defaults as initial options
|
53
|
-
@@options = Defaults
|
54
|
-
|
55
|
-
# Get an option at runtime
|
56
|
-
#
|
57
|
-
# @param name [Symbol] Identifier for the option
|
58
|
-
#
|
59
|
-
def [](name)
|
60
|
-
@@options[name]
|
61
|
-
end
|
51
|
+
# Opulent runtime settings
|
52
|
+
DEFAULTS = {
|
53
|
+
# dependency_manager: true, # Soon to be implemented
|
54
|
+
indent: 2,
|
55
|
+
layouts: false,
|
56
|
+
pretty: false,
|
57
|
+
default_layout: :'views/layouts/application'
|
58
|
+
}
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
# Set defaults as initial settings
|
61
|
+
#
|
62
|
+
def initialize
|
63
|
+
@settings = DEFAULTS
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get an option at runtime
|
67
|
+
#
|
68
|
+
# @param name [Symbol] Identifier for the option
|
69
|
+
#
|
70
|
+
def [](name)
|
71
|
+
@settings[name]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set a new option at runtime
|
75
|
+
#
|
76
|
+
# @param name [Symbol] Identifier for the option
|
77
|
+
# @param value Option value to be set
|
78
|
+
#
|
79
|
+
def []=(name, value)
|
80
|
+
@settings[name] = value
|
81
|
+
end
|
82
|
+
|
83
|
+
# Remove an option at runtime
|
84
|
+
#
|
85
|
+
# @param name [Symbol] Identifier for the option
|
86
|
+
# @param value Option value to be set
|
87
|
+
#
|
88
|
+
def delete(name)
|
89
|
+
@settings.delete name
|
90
|
+
end
|
71
91
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
92
|
+
# Update the engine settings with the required option changes
|
93
|
+
#
|
94
|
+
# @param opts [Hash] Option extension hash
|
95
|
+
#
|
96
|
+
def update_settings(opts)
|
97
|
+
@settings = DEFAULTS
|
78
98
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
99
|
+
opts.each do |key, value|
|
100
|
+
@settings[key] = value
|
82
101
|
end
|
83
102
|
end
|
84
103
|
end
|