opulent 1.4.0 → 1.4.1
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/benchmark/benchmark.rb +18 -7
- data/benchmark/cases/node/node.haml +6 -16
- data/benchmark/cases/node/node.op +6 -13
- data/benchmark/cases/node/node.slim +6 -18
- data/docs/comments.md +5 -0
- data/docs/filters.md +31 -0
- data/docs/includes.md +0 -0
- data/docs/nodes.md +88 -0
- data/docs/reference.md +7 -6
- data/lib/opulent.rb +2 -1
- data/lib/opulent/compiler.rb +19 -18
- data/lib/opulent/compiler/buffer.rb +260 -0
- data/lib/opulent/compiler/comment.rb +4 -9
- data/lib/opulent/compiler/control.rb +65 -67
- data/lib/opulent/compiler/define.rb +91 -63
- data/lib/opulent/compiler/doctype.rb +1 -5
- data/lib/opulent/compiler/eval.rb +1 -1
- data/lib/opulent/compiler/node.rb +10 -194
- data/lib/opulent/compiler/root.rb +1 -1
- data/lib/opulent/compiler/text.rb +3 -40
- data/lib/opulent/compiler/yield.rb +15 -0
- data/lib/opulent/context.rb +2 -2
- data/lib/opulent/engine.rb +56 -57
- data/lib/opulent/parser.rb +10 -10
- data/lib/opulent/parser/control.rb +2 -3
- data/lib/opulent/parser/expression.rb +1 -1
- data/lib/opulent/parser/{require.rb → include.rb} +17 -15
- data/lib/opulent/parser/node.rb +22 -17
- data/lib/opulent/parser/root.rb +3 -4
- data/lib/opulent/parser/text.rb +3 -7
- data/lib/opulent/parser/yield.rb +23 -0
- data/lib/opulent/settings.rb +5 -4
- data/lib/opulent/template.rb +12 -30
- data/lib/opulent/tokens.rb +5 -9
- data/lib/opulent/utils.rb +41 -0
- data/lib/opulent/version.rb +1 -1
- metadata +9 -5
- data/lib/opulent/compiler/block.rb +0 -31
- data/lib/opulent/parser/block.rb +0 -56
@@ -9,15 +9,10 @@ module Opulent
|
|
9
9
|
# @param context [Context] Processing environment data
|
10
10
|
#
|
11
11
|
def comment(node, indent, context)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
comment_tag = "#{"\n" if node[@options][:newline]}#{indentation}<!-- #{value.strip} -->\n"
|
18
|
-
|
19
|
-
@node_stack << :comment
|
20
|
-
@code += comment_tag
|
12
|
+
buffer_freeze "\n" if node[@options][:newline]
|
13
|
+
buffer_freeze "<!-- "
|
14
|
+
buffer_split_by_interpolation node[@value].strip, false
|
15
|
+
buffer_freeze " -->"
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
@@ -10,17 +10,23 @@ module Opulent
|
|
10
10
|
#
|
11
11
|
def if_node(node, indent, context)
|
12
12
|
# Check if we have any condition met, or an else branch
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
node[@value].each_with_index do |value, index|
|
14
|
+
# If we have a branch that meets the condition, generate code for the
|
15
|
+
# children related to that specific branch
|
16
|
+
case value
|
17
|
+
when node[@value].first then buffer_eval "if #{value}"
|
18
|
+
when node[@value].last then buffer_eval "else"
|
19
|
+
else buffer_eval "elsif #{value}"
|
20
|
+
end
|
16
21
|
|
17
|
-
|
18
|
-
# children related to that specific branch
|
19
|
-
if index
|
22
|
+
# Evaluate child nodes
|
20
23
|
node[@children][index].each do |child|
|
21
24
|
root child, indent, context
|
22
25
|
end
|
23
26
|
end
|
27
|
+
|
28
|
+
# End
|
29
|
+
buffer_eval "end"
|
24
30
|
end
|
25
31
|
|
26
32
|
# Generate the code for a unless-else control structure
|
@@ -31,17 +37,22 @@ module Opulent
|
|
31
37
|
#
|
32
38
|
def unless_node(node, indent, context)
|
33
39
|
# Check if we have any condition met, or an else branch
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
node[@value].each_with_index do |value, index|
|
41
|
+
# If we have a branch that meets the condition, generate code for the
|
42
|
+
# children related to that specific branch
|
43
|
+
case value
|
44
|
+
when node[@value].first then buffer_eval "unless #{value}"
|
45
|
+
else buffer_eval "else"
|
46
|
+
end
|
37
47
|
|
38
|
-
|
39
|
-
# children related to that specific branch
|
40
|
-
if index
|
48
|
+
# Evaluate child nodes
|
41
49
|
node[@children][index].each do |child|
|
42
50
|
root child, indent, context
|
43
51
|
end
|
44
52
|
end
|
53
|
+
|
54
|
+
# End
|
55
|
+
buffer_eval "end"
|
45
56
|
end
|
46
57
|
|
47
58
|
# Generate the code for a case-when-else control structure
|
@@ -52,20 +63,25 @@ module Opulent
|
|
52
63
|
#
|
53
64
|
def case_node(node, indent, context)
|
54
65
|
# Evaluate the switching condition
|
55
|
-
|
66
|
+
buffer_eval "case #{node[@options][:condition]}"
|
56
67
|
|
57
68
|
# Check if we have any condition met, or an else branch
|
58
|
-
|
59
|
-
|
60
|
-
|
69
|
+
node[@value].each_with_index do |value, index|
|
70
|
+
# If we have a branch that meets the condition, generate code for the
|
71
|
+
# children related to that specific branch
|
72
|
+
case value
|
73
|
+
when node[@value].last then buffer_eval "else"
|
74
|
+
else buffer_eval "when #{value}"
|
75
|
+
end
|
61
76
|
|
62
|
-
|
63
|
-
# children related to that specific branch
|
64
|
-
if index
|
77
|
+
# Evaluate child nodes
|
65
78
|
node[@children][index].each do |child|
|
66
79
|
root child, indent, context
|
67
80
|
end
|
68
81
|
end
|
82
|
+
|
83
|
+
# End
|
84
|
+
buffer_eval "end"
|
69
85
|
end
|
70
86
|
|
71
87
|
# Generate the code for a while control structure
|
@@ -77,11 +93,15 @@ module Opulent
|
|
77
93
|
def while_node(node, indent, context)
|
78
94
|
# While we have a branch that meets the condition, generate code for the
|
79
95
|
# children related to that specific branch
|
80
|
-
while
|
81
|
-
|
82
|
-
|
83
|
-
|
96
|
+
buffer_eval "while #{node[@value]}"
|
97
|
+
|
98
|
+
# Evaluate child nodes
|
99
|
+
node[@children].each do |child|
|
100
|
+
root child, indent, context
|
84
101
|
end
|
102
|
+
|
103
|
+
#End
|
104
|
+
buffer_eval "end"
|
85
105
|
end
|
86
106
|
|
87
107
|
# Generate the code for a while control structure
|
@@ -93,11 +113,15 @@ module Opulent
|
|
93
113
|
def until_node(node, indent, context)
|
94
114
|
# Until we have a branch that doesn't meet the condition, generate code for the
|
95
115
|
# children related to that specific branch
|
96
|
-
until
|
97
|
-
|
98
|
-
|
99
|
-
|
116
|
+
buffer_eval "until #{node[@value]}"
|
117
|
+
|
118
|
+
# Evaluate child nodes
|
119
|
+
node[@children].each do |child|
|
120
|
+
root child, indent, context
|
100
121
|
end
|
122
|
+
|
123
|
+
# End
|
124
|
+
buffer_eval "end"
|
101
125
|
end
|
102
126
|
|
103
127
|
# Generate the code for a while control structure
|
@@ -107,10 +131,8 @@ module Opulent
|
|
107
131
|
# @param context [Context] Processing environment data
|
108
132
|
#
|
109
133
|
def each_node(node, indent, context)
|
110
|
-
result = []
|
111
|
-
|
112
134
|
# Process named variables for each structure
|
113
|
-
variables = node[@value][
|
135
|
+
variables = node[@value][1].clone
|
114
136
|
|
115
137
|
# The each structure accept missing arguments as well, therefore we need to
|
116
138
|
# substitute them with our defaults
|
@@ -129,46 +151,22 @@ module Opulent
|
|
129
151
|
variables[1] = Settings::DefaultEachValue
|
130
152
|
end
|
131
153
|
|
132
|
-
#
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
}
|
140
|
-
context.extend_locals locals
|
141
|
-
|
142
|
-
# Add the mapped child elements
|
143
|
-
node[@children].each do |child|
|
144
|
-
root child, indent, context
|
145
|
-
end
|
154
|
+
# Choose whether to apply each with index (Arrays) or each (Hashes) methods
|
155
|
+
#buffer_eval "_opulent_send_method = (#{node[@value][1]}.is_a?(Array) ? :each_with_index : :each)"
|
156
|
+
case node[@value][0][0]
|
157
|
+
when '[]'
|
158
|
+
buffer_eval "#{node[@value][0][1]}.each_with_index do |#{variables.reverse.join ', '}|"
|
159
|
+
else
|
160
|
+
buffer_eval "#{node[@value][0][1]}.each do |#{variables.join ', '}|"
|
146
161
|
end
|
147
162
|
|
148
|
-
#
|
149
|
-
|
150
|
-
|
151
|
-
each_context = Context.new Hash.new, &block
|
152
|
-
each_context.parent = context
|
153
|
-
|
154
|
-
# Evaluate the iterable object
|
155
|
-
enumerable = context.evaluate(node[@value][1])
|
156
|
-
|
157
|
-
# Check if input can be iterated
|
158
|
-
self.error :enumerable, node[@value][1] unless enumerable.respond_to? :each
|
159
|
-
|
160
|
-
# Selectively iterate through the input and add the result using the previously
|
161
|
-
# defined proc object
|
162
|
-
case enumerable
|
163
|
-
when Hash
|
164
|
-
enumerable.each do |key, value|
|
165
|
-
evaluate_children[key, value, context]
|
166
|
-
end
|
167
|
-
else
|
168
|
-
enumerable.each_with_index do |value, key|
|
169
|
-
evaluate_children[key, value, context]
|
170
|
-
end
|
163
|
+
# Evaluate child nodes
|
164
|
+
node[@children].each do |child|
|
165
|
+
root child, indent, context
|
171
166
|
end
|
167
|
+
|
168
|
+
# End
|
169
|
+
buffer_eval "end"
|
172
170
|
end
|
173
171
|
end
|
174
172
|
end
|
@@ -9,87 +9,115 @@ module Opulent
|
|
9
9
|
# @param context [Context] Context holding environment variables
|
10
10
|
#
|
11
11
|
def def_node(node, indent, context)
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# within a definition (it might be a nice feature)
|
16
|
-
#
|
17
|
-
definition_context = Context.new &context.block
|
18
|
-
definition_context.extend_nonlocals context.binding
|
19
|
-
definition_context.name = node[@value]
|
20
|
-
definition_context.parent = context
|
12
|
+
# Set a namespace for the current node definition and make it a valid ruby
|
13
|
+
# method name
|
14
|
+
key = "_opulent_definition_#{node[@value]}_#{@current_definition += 1}".gsub '-', '_'
|
21
15
|
|
22
|
-
# Set call
|
16
|
+
# Set call variable
|
23
17
|
call_node = node[@options][:call]
|
24
18
|
|
25
|
-
#
|
26
|
-
|
19
|
+
# Create the definition
|
20
|
+
buffer_eval "instance_eval do"
|
21
|
+
buffer_eval "def #{key}(attributes = {}, &block)"
|
27
22
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
23
|
+
# Set each parameter as a local variable
|
24
|
+
node[@options][:parameters].each do |parameter, value|
|
25
|
+
set_argument_code = "#{parameter} = attributes.delete(:#{parameter})"
|
26
|
+
set_argument_code += " || #{value[@value]}" if value[@value]
|
27
|
+
buffer_eval set_argument_code
|
33
28
|
end
|
34
29
|
|
35
|
-
# Evaluate
|
36
|
-
|
37
|
-
|
38
|
-
call_node[@options][:attributes].each do |key, attribute|
|
39
|
-
unless node[@options][:parameters].has_key? key
|
40
|
-
attributes[key] = map_attribute key, attribute, context
|
41
|
-
end
|
30
|
+
# Evaluate definition child elements
|
31
|
+
node[@children].each do |child|
|
32
|
+
root child, indent + Settings[:indent], context
|
42
33
|
end
|
43
34
|
|
44
|
-
#
|
45
|
-
|
35
|
+
# End
|
36
|
+
buffer_eval "end"
|
37
|
+
buffer_eval "end"
|
46
38
|
|
47
|
-
#
|
48
|
-
|
39
|
+
# If we have attributes set for our defined node, we will need to create
|
40
|
+
# an extension parameter which will be o
|
41
|
+
if call_node[@options][:attributes].empty?
|
42
|
+
# Call method without any extension
|
43
|
+
buffer_eval "#{key}() do"
|
44
|
+
else
|
45
|
+
call_attributes_code = buffer_attributes_to_hash call_node[@options][:attributes]
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
# parameter value.
|
53
|
-
#
|
54
|
-
# Definition arguments (parameters which are set in definition header)
|
55
|
-
# will be passed unescaped, to allow node definition to handle escaping
|
56
|
-
# properly
|
57
|
-
node[@options][:parameters].each do |key, value|
|
58
|
-
if call_node[@options][:attributes].has_key? key
|
59
|
-
arguments[key] = context.evaluate call_node[@options][:attributes][key][@value]
|
60
|
-
else
|
61
|
-
arguments[key] = definition_context.evaluate value[@value]
|
62
|
-
end
|
63
|
-
end
|
47
|
+
# Set call node parameters
|
48
|
+
call_attributes = buffer_set_variable :call_attributes, call_attributes_code
|
64
49
|
|
65
|
-
|
66
|
-
|
50
|
+
# If the call node is extended as well, merge the call attributes hash with
|
51
|
+
# the extension hash
|
52
|
+
if call_node[@options][:extension]
|
53
|
+
extension_attributes = buffer_set_variable :extension, call_node[@options][:extension][@value]
|
54
|
+
buffer_eval "#{call_attributes}.merge!(#{extension_attributes}) do |#{OpulentKey}, #{OpulentValue}1, #{OpulentValue}2|"
|
55
|
+
buffer_eval "#{OpulentKey} == :class ? (#{OpulentValue}1 += #{OpulentValue}2) : (#{OpulentValue}2)"
|
56
|
+
buffer_eval "end"
|
57
|
+
end
|
67
58
|
|
68
|
-
|
69
|
-
|
70
|
-
@block_stack << { @default_yield => [] }
|
59
|
+
buffer_eval "#{key}(#{call_attributes}) do"
|
60
|
+
end
|
71
61
|
|
72
|
-
#
|
73
|
-
#
|
62
|
+
# Set call node children as block evaluation. Very useful for
|
63
|
+
# performance and evaluating them in the parent context
|
74
64
|
call_node[@children].each do |child|
|
75
|
-
|
76
|
-
@block_stack[-1][child[@value]] ||= []
|
77
|
-
@block_stack[-1][child[@value]] += child[@children]
|
78
|
-
else
|
79
|
-
@block_stack[-1][@default_yield] << child
|
80
|
-
end
|
65
|
+
root child, indent + Settings[:indent], context
|
81
66
|
end
|
82
67
|
|
83
|
-
#
|
84
|
-
|
68
|
+
# End block
|
69
|
+
buffer_eval "end"
|
85
70
|
|
86
|
-
# Create local variables from argument variables
|
87
|
-
definition_context.extend_locals arguments
|
88
71
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
72
|
+
|
73
|
+
# definition_context.parent = context
|
74
|
+
#
|
75
|
+
# # # Set call node
|
76
|
+
# # call_node = node[@options][:call]
|
77
|
+
# #
|
78
|
+
# # # Get call node attributes
|
79
|
+
# # attributes = call_node[@options][:attributes]
|
80
|
+
# #
|
81
|
+
# # Evaluate node extension in the current context
|
82
|
+
# if call_node[@options][:extension]
|
83
|
+
# extension = context.evaluate call_node[@options][:extension][@value]
|
84
|
+
# else
|
85
|
+
# extension = {}
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # Evaluate and generate node attributes, then process each one to
|
89
|
+
# # by generating the required attribute code
|
90
|
+
# attributes = {}
|
91
|
+
# call_node[@options][:attributes].each do |key, attribute|
|
92
|
+
# unless node[@options][:parameters].has_key? key
|
93
|
+
# attributes[key] = map_attribute key, attribute, context
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# # Go through each extension attribute and use the value where applicable
|
98
|
+
# extend_attributes attributes, extension
|
99
|
+
#
|
100
|
+
# # Definition call arguments
|
101
|
+
# arguments = {}
|
102
|
+
#
|
103
|
+
# # Extract values which appear as definition parameters. If we have the
|
104
|
+
# # key passed as argument, get its value. Otherwise, set the default
|
105
|
+
# # parameter value.
|
106
|
+
# #
|
107
|
+
# # Definition arguments (parameters which are set in definition header)
|
108
|
+
# # will be passed unescaped, to allow node definition to handle escaping
|
109
|
+
# # properly
|
110
|
+
# node[@options][:parameters].each do |key, value|
|
111
|
+
# if call_node[@options][:attributes].has_key? key
|
112
|
+
# arguments[key] = context.evaluate call_node[@options][:attributes][key][@value]
|
113
|
+
# else
|
114
|
+
# arguments[key] = definition_context.evaluate value[@value]
|
115
|
+
# end
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# # Set the remaining attributes as a value in the arguments
|
119
|
+
# arguments[:attributes] = attributes
|
120
|
+
|
93
121
|
|
94
122
|
# Remove last set of blocks from the block stack
|
95
123
|
@block_stack.pop
|
@@ -10,8 +10,6 @@ module Opulent
|
|
10
10
|
# @param context [Context] Processing environment data
|
11
11
|
#
|
12
12
|
def doctype_node(node, indent, context)
|
13
|
-
indentation = " " * indent
|
14
|
-
|
15
13
|
value = case node[@value]
|
16
14
|
when :"", :"html", :"5"
|
17
15
|
"!DOCTYPE html"
|
@@ -33,10 +31,8 @@ module Opulent
|
|
33
31
|
'?xml version="1.0" encoding="iso-8859-1" ?'
|
34
32
|
end
|
35
33
|
|
36
|
-
doctype_tag = "#{indentation}<#{value}>\n"
|
37
|
-
|
38
34
|
@node_stack << :doctype
|
39
|
-
|
35
|
+
buffer_freeze "<#{value}>"
|
40
36
|
end
|
41
37
|
end
|
42
38
|
end
|
@@ -12,223 +12,39 @@ module Opulent
|
|
12
12
|
def node(node, indent, context)
|
13
13
|
indentation = " " * indent
|
14
14
|
|
15
|
-
# Check if the current node and last node should be displayed inline
|
16
|
-
inline_current = @inline_node.include? node[@value]
|
17
|
-
inline_last = @inline_node.include? @node_stack.last
|
18
|
-
|
19
|
-
# Check if the node is a special node which can be either inline or
|
20
|
-
# block structure. Write the special node as inline if its children
|
21
|
-
# are all inline nodes
|
22
|
-
if @multi_node.include?(node[@value])
|
23
|
-
# First condition should be removed to ignore preceding node and make
|
24
|
-
# it be inline no matter what. Using the first check, we write it
|
25
|
-
# inline only if the element before it was inline
|
26
|
-
unless @sibling_stack.last > 1 && node[@children].all? do |child|
|
27
|
-
@inline_node.include?(child[@value])
|
28
|
-
end
|
29
|
-
inline_current = false
|
30
|
-
multi = true
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# If we have an inline node, we remove the trailing newline character
|
35
|
-
# and write the tag code directly. Otherwise we add the tag code with
|
36
|
-
# normal indentation
|
37
|
-
if inline_last && inline_current
|
38
|
-
remove_trailing_newline
|
39
|
-
else
|
40
|
-
@code += indentation
|
41
|
-
end
|
42
|
-
|
43
15
|
# Add the tag opening, with leading whitespace to the code buffer
|
44
|
-
|
45
|
-
|
46
|
-
@code += tag_open
|
16
|
+
buffer_freeze " " if node[@options][:leading_whitespace]
|
17
|
+
buffer_freeze "<#{node[@value]}"
|
47
18
|
|
48
19
|
# Evaluate node extension in the current context
|
49
|
-
if node[@options][:extension]
|
50
|
-
extension
|
51
|
-
else
|
52
|
-
extension = {}
|
20
|
+
extension = if node[@options][:extension]
|
21
|
+
buffer_set_variable :extension, node[@options][:extension][@value]
|
53
22
|
end
|
54
23
|
|
55
24
|
# Evaluate and generate node attributes, then process each one to
|
56
25
|
# by generating the required attribute code
|
57
26
|
attributes = {}
|
58
|
-
node[@options][:attributes]
|
59
|
-
attributes[key] = map_attribute key, attribute, context
|
60
|
-
end
|
27
|
+
buffer_attributes node[@options][:attributes], extension
|
61
28
|
|
62
|
-
# Go through each extension attribute and use the value where applicable
|
63
|
-
extend_attributes attributes, extension
|
64
|
-
|
65
|
-
# Join arrays, create new attributes by hash and set the
|
66
|
-
# value otherwise
|
67
|
-
attributes.each do |key, value|
|
68
|
-
@code += attribute_code key, value
|
69
|
-
end
|
70
|
-
|
71
|
-
# Set the current node as a parent for the node elements to follow
|
72
|
-
@node_stack << (multi ? :multi : node[@value])
|
73
29
|
|
74
30
|
# Check if the current node is self enclosing. Self enclosing nodes
|
75
31
|
# do not have any child elements
|
76
32
|
if node[@options][:self_enclosing]
|
77
33
|
# If the tag is self enclosing, it cannot have any child elements.
|
78
|
-
|
79
|
-
tag_close += "\n"
|
80
|
-
|
81
|
-
@code += tag_close
|
34
|
+
buffer_freeze ">"
|
82
35
|
else
|
83
36
|
# Set tag ending code
|
84
|
-
|
85
|
-
|
86
|
-
# If the node is an inline node and doesn't have any child elements,
|
87
|
-
# we close it on the same line, without adding indentation
|
88
|
-
tag_end += "\n" unless inline_current || node[@children].empty?
|
89
|
-
|
90
|
-
# Set tag closing code
|
91
|
-
tag_close = "</#{node[@value]}>"
|
92
|
-
tag_close += " " if node[@options][:trailing_whitespace]
|
93
|
-
tag_close += "\n"
|
94
|
-
|
95
|
-
# Add tag ending to the buffer
|
96
|
-
@code += tag_end
|
97
|
-
|
98
|
-
# Get number of siblings
|
99
|
-
@sibling_stack << node[@children].size
|
37
|
+
buffer_freeze ">"
|
100
38
|
|
101
39
|
# Process each child element recursively, increasing indentation
|
102
40
|
node[@children].each do |child|
|
103
41
|
root child, indent + Settings[:indent], context
|
104
42
|
end
|
105
43
|
|
106
|
-
#
|
107
|
-
@
|
108
|
-
|
109
|
-
# Remove all child nodes of the current node from the node stack
|
110
|
-
@node_stack.pop(node[@children].size)
|
111
|
-
|
112
|
-
# If we have an inline node, we remove the trailing newline from
|
113
|
-
# our buffer, otherwise add indentation
|
114
|
-
if inline_current
|
115
|
-
remove_trailing_newline
|
116
|
-
|
117
|
-
# If the node doesn't have any child elements, we close it on the same
|
118
|
-
# line, without adding indentation
|
119
|
-
elsif node[@children].any?
|
120
|
-
@code += indentation
|
121
|
-
end
|
122
|
-
|
123
|
-
# Close the current tag
|
124
|
-
@code += tag_close
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# Map attributes by evaluating them in the current working context
|
129
|
-
#
|
130
|
-
# @param key [Symbol] Name of the attribute being processed
|
131
|
-
# @param attribute [Array] Attribute instance data
|
132
|
-
# @param context [Context] Processing environment data
|
133
|
-
#
|
134
|
-
def map_attribute(key, attribute, context)
|
135
|
-
# Process input value depending on its type. When array or hash, iterate
|
136
|
-
# and escape each string value.
|
137
|
-
process = Proc.new do |value|
|
138
|
-
case value
|
139
|
-
when Array
|
140
|
-
value.map do |v|
|
141
|
-
v.is_a?(String) ? escape(v) : v
|
142
|
-
end
|
143
|
-
when Hash
|
144
|
-
value.each do |k,v|
|
145
|
-
value[k] = value[k].is_a?(String) ? escape(v) : v
|
146
|
-
end
|
147
|
-
when String
|
148
|
-
escape value
|
149
|
-
else
|
150
|
-
value
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# Process each attribute depending on whether it's an array of values,
|
155
|
-
# exclusive to the class attribute, or an individual attribute value
|
156
|
-
if key == :class
|
157
|
-
attribute.map do |attrib|
|
158
|
-
value = context.evaluate attrib[@value]
|
159
|
-
attrib[@options][:escaped] ? process[value] : value
|
160
|
-
end
|
161
|
-
else
|
162
|
-
value = context.evaluate attribute[@value]
|
163
|
-
attribute[@options][:escaped] ? process[value] : value
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# Extend attributes using the extension directive where applicable.
|
168
|
-
# Concatenate arrays, merge hashes and replace otherwise
|
169
|
-
#
|
170
|
-
# @param attributes [Hash] Evaluated node attributes
|
171
|
-
# @param extension [Hash] Node extension input
|
172
|
-
#
|
173
|
-
def extend_attributes(attributes, extension)
|
174
|
-
extension.each do |key, value|
|
175
|
-
case attributes[key]
|
176
|
-
when Array
|
177
|
-
if key == :class
|
178
|
-
attributes[key] << value
|
179
|
-
attributes[key].flatten!
|
180
|
-
else
|
181
|
-
attributes[key] = value
|
182
|
-
end
|
183
|
-
when Hash
|
184
|
-
if value.is_a? Hash
|
185
|
-
attributes[key].merge! value
|
186
|
-
else
|
187
|
-
attributes[key] = value
|
188
|
-
end
|
189
|
-
else
|
190
|
-
attributes[key] = value
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# Generate attribute code for the current key value pair. For string
|
196
|
-
# values, generate a key value pair. For false values, remove the
|
197
|
-
# attribute. For true values, generate a standalone attribute key
|
198
|
-
#
|
199
|
-
# @param key [Symbol] Name of the attribute being generated
|
200
|
-
# @param value [Object] Value of the attribute
|
201
|
-
#
|
202
|
-
def attribute_code(key, value)
|
203
|
-
attribute_code = ""
|
204
|
-
|
205
|
-
case value
|
206
|
-
when Array
|
207
|
-
if key == :class
|
208
|
-
attribute_value = value.join ' '
|
209
|
-
else
|
210
|
-
attribute_value = value.join '_'
|
211
|
-
end
|
212
|
-
|
213
|
-
unless attribute_value.empty?
|
214
|
-
attribute_code += " #{key}"
|
215
|
-
attribute_code += "=\"#{attribute_value.strip}\""
|
216
|
-
end
|
217
|
-
when Hash
|
218
|
-
value.each do |k,v|
|
219
|
-
if v
|
220
|
-
attribute_code += " #{key}-#{k}"
|
221
|
-
attribute_code += "=\"#{v.to_s.strip}\"" unless v == true
|
222
|
-
end
|
223
|
-
end
|
224
|
-
else
|
225
|
-
if value
|
226
|
-
attribute_code += " #{key}"
|
227
|
-
attribute_code += "=\"#{value.to_s.strip}\"" unless value == true
|
228
|
-
end
|
44
|
+
# Set tag closing code
|
45
|
+
buffer_freeze "</#{node[@value]}>"
|
46
|
+
buffer_freeze " " if node[@options][:trailing_whitespace]
|
229
47
|
end
|
230
|
-
|
231
|
-
return attribute_code
|
232
48
|
end
|
233
49
|
end
|
234
50
|
end
|