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