opulent 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/benchmark/benchmark.rb +18 -7
  3. data/benchmark/cases/node/node.haml +6 -16
  4. data/benchmark/cases/node/node.op +6 -13
  5. data/benchmark/cases/node/node.slim +6 -18
  6. data/docs/comments.md +5 -0
  7. data/docs/filters.md +31 -0
  8. data/docs/includes.md +0 -0
  9. data/docs/nodes.md +88 -0
  10. data/docs/reference.md +7 -6
  11. data/lib/opulent.rb +2 -1
  12. data/lib/opulent/compiler.rb +19 -18
  13. data/lib/opulent/compiler/buffer.rb +260 -0
  14. data/lib/opulent/compiler/comment.rb +4 -9
  15. data/lib/opulent/compiler/control.rb +65 -67
  16. data/lib/opulent/compiler/define.rb +91 -63
  17. data/lib/opulent/compiler/doctype.rb +1 -5
  18. data/lib/opulent/compiler/eval.rb +1 -1
  19. data/lib/opulent/compiler/node.rb +10 -194
  20. data/lib/opulent/compiler/root.rb +1 -1
  21. data/lib/opulent/compiler/text.rb +3 -40
  22. data/lib/opulent/compiler/yield.rb +15 -0
  23. data/lib/opulent/context.rb +2 -2
  24. data/lib/opulent/engine.rb +56 -57
  25. data/lib/opulent/parser.rb +10 -10
  26. data/lib/opulent/parser/control.rb +2 -3
  27. data/lib/opulent/parser/expression.rb +1 -1
  28. data/lib/opulent/parser/{require.rb → include.rb} +17 -15
  29. data/lib/opulent/parser/node.rb +22 -17
  30. data/lib/opulent/parser/root.rb +3 -4
  31. data/lib/opulent/parser/text.rb +3 -7
  32. data/lib/opulent/parser/yield.rb +23 -0
  33. data/lib/opulent/settings.rb +5 -4
  34. data/lib/opulent/template.rb +12 -30
  35. data/lib/opulent/tokens.rb +5 -9
  36. data/lib/opulent/utils.rb +41 -0
  37. data/lib/opulent/version.rb +1 -1
  38. metadata +9 -5
  39. data/lib/opulent/compiler/block.rb +0 -31
  40. 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
- indentation = " " * indent
13
-
14
- # Escaping double quotes is required in order to avoid any conflicts with the eval quotes.
15
- value = indent_lines context.evaluate('"' + node[@value].gsub('"', '\\"') + '"'), " " * indent
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
- index = node[@value].index do |value|
14
- value.empty? || context.evaluate(value)
15
- end
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
- # If we have a branch that meets the condition, generate code for the
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
- index = node[@value].index do |value|
35
- value.empty? || !context.evaluate(value)
36
- end
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
- # If we have a branch that meets the condition, generate code for the
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
- switch_case = context.evaluate node[@options][:condition]
66
+ buffer_eval "case #{node[@options][:condition]}"
56
67
 
57
68
  # Check if we have any condition met, or an else branch
58
- index = node[@value].index do |value|
59
- value.empty? || switch_case == context.evaluate(value)
60
- end
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
- # If we have a branch that meets the condition, generate code for the
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 context.evaluate node[@value]
81
- node[@children].each do |child|
82
- root child, indent, context
83
- end
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 context.evaluate node[@value]
97
- node[@children].each do |child|
98
- root child, indent, context
99
- end
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][0].clone
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
- # Evaluate in current context and add to results
133
- evaluate_children = Proc.new do |key, value, context|
134
- # Update the local variables in the each context with the values from the
135
- # current loop iteration
136
- locals = {
137
- variables[0] => key,
138
- variables[1] => value
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
- # Create a new context based on the parent context and progressively update
149
- # variables in the new context
150
- block = context.block.clone if context.block
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
- # Create a new definition context
13
- #
14
- # @update: Added &context.block to make sure yield can be called from
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 node
16
+ # Set call variable
23
17
  call_node = node[@options][:call]
24
18
 
25
- # Get call node attributes
26
- attributes = call_node[@options][:attributes]
19
+ # Create the definition
20
+ buffer_eval "instance_eval do"
21
+ buffer_eval "def #{key}(attributes = {}, &block)"
27
22
 
28
- # Evaluate node extension in the current context
29
- if call_node[@options][:extension]
30
- extension = context.evaluate call_node[@options][:extension][@value]
31
- else
32
- extension = {}
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 and generate node attributes, then process each one to
36
- # by generating the required attribute code
37
- attributes = {}
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
- # Go through each extension attribute and use the value where applicable
45
- extend_attributes attributes, extension
35
+ # End
36
+ buffer_eval "end"
37
+ buffer_eval "end"
46
38
 
47
- # Definition call arguments
48
- arguments = {}
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
- # Extract values which appear as definition parameters. If we have the
51
- # key passed as argument, get its value. Otherwise, set the default
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
- # Set the remaining attributes as a value in the arguments
66
- arguments[:attributes] = attributes
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
- # Add call children to the block stack, depending on whether they're
69
- # block elements or child elements
70
- @block_stack << { @default_yield => [] }
59
+ buffer_eval "#{key}(#{call_attributes}) do"
60
+ end
71
61
 
72
- # If we have a direct child, add it to the default yield (children)
73
- # block and allow same block multiple times by appending nodes
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
- if child[@type] == :block
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
- # Set variable to determine available blocks
84
- arguments[:blocks] = Hash[@block_stack[-1].keys.map{|key| [key, true]}]
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
- # Evaluate the model using the new context
90
- node[@children].each do |child|
91
- root child, indent, definition_context
92
- end
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
- @code += doctype_tag
35
+ buffer_freeze "<#{value}>"
40
36
  end
41
37
  end
42
38
  end
@@ -9,7 +9,7 @@ module Opulent
9
9
  # @param context [Context] Processing environment data
10
10
  #
11
11
  def evaluate(node, indent, context)
12
- context.evaluate node[@value]
12
+ buffer_eval node[@value]
13
13
  end
14
14
  end
15
15
  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
- tag_open = "<#{node[@value]}"
45
- @code += " " if node[@options][:leading_whitespace]
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 = context.evaluate node[@options][:extension][@value]
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].each do |key, attribute|
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
- tag_close = ">"
79
- tag_close += "\n"
80
-
81
- @code += tag_close
34
+ buffer_freeze ">"
82
35
  else
83
36
  # Set tag ending code
84
- tag_end = ">"
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
- # Remove the current node children count from the sibling stack
107
- @sibling_stack.pop
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