haml 1.8.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/FAQ +138 -0
- data/MIT-LICENSE +1 -1
- data/{README → README.rdoc} +66 -3
- data/Rakefile +111 -147
- data/VERSION +1 -1
- data/bin/css2sass +0 -0
- data/bin/haml +0 -0
- data/bin/html2haml +0 -0
- data/bin/sass +0 -0
- data/init.rb +6 -1
- data/lib/haml.rb +464 -201
- data/lib/haml/buffer.rb +117 -63
- data/lib/haml/engine.rb +63 -44
- data/lib/haml/error.rb +16 -6
- data/lib/haml/exec.rb +37 -7
- data/lib/haml/filters.rb +213 -68
- data/lib/haml/helpers.rb +95 -60
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +54 -6
- data/lib/haml/html.rb +6 -6
- data/lib/haml/precompiler.rb +254 -133
- data/lib/haml/template.rb +3 -6
- data/lib/haml/template/patch.rb +9 -2
- data/lib/haml/template/plugin.rb +52 -23
- data/lib/sass.rb +157 -12
- data/lib/sass/constant.rb +22 -22
- data/lib/sass/constant/color.rb +13 -13
- data/lib/sass/constant/literal.rb +7 -7
- data/lib/sass/constant/number.rb +9 -9
- data/lib/sass/constant/operation.rb +4 -4
- data/lib/sass/constant/string.rb +3 -3
- data/lib/sass/css.rb +104 -31
- data/lib/sass/engine.rb +120 -39
- data/lib/sass/error.rb +1 -1
- data/lib/sass/plugin.rb +14 -3
- data/lib/sass/plugin/merb.rb +6 -2
- data/lib/sass/tree/attr_node.rb +5 -5
- data/lib/sass/tree/directive_node.rb +2 -7
- data/lib/sass/tree/node.rb +1 -12
- data/lib/sass/tree/rule_node.rb +39 -31
- data/lib/sass/tree/value_node.rb +1 -1
- data/test/benchmark.rb +67 -80
- data/test/haml/engine_test.rb +284 -84
- data/test/haml/helper_test.rb +51 -15
- data/test/haml/results/content_for_layout.xhtml +1 -2
- data/test/haml/results/eval_suppressed.xhtml +2 -4
- data/test/haml/results/filters.xhtml +44 -15
- data/test/haml/results/helpers.xhtml +2 -3
- data/test/haml/results/just_stuff.xhtml +2 -6
- data/test/haml/results/nuke_inner_whitespace.xhtml +34 -0
- data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
- data/test/haml/results/original_engine.xhtml +3 -7
- data/test/haml/results/partials.xhtml +1 -0
- data/test/haml/results/tag_parsing.xhtml +1 -6
- data/test/haml/results/very_basic.xhtml +2 -4
- data/test/haml/results/whitespace_handling.xhtml +13 -21
- data/test/haml/template_test.rb +8 -15
- data/test/haml/templates/_partial.haml +1 -0
- data/test/haml/templates/filters.haml +48 -7
- data/test/haml/templates/just_stuff.haml +1 -2
- data/test/haml/templates/nuke_inner_whitespace.haml +26 -0
- data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
- data/test/haml/templates/tag_parsing.haml +0 -3
- data/test/haml/test_helper.rb +15 -0
- data/test/sass/engine_test.rb +80 -34
- data/test/sass/plugin_test.rb +1 -1
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/mixins.css +95 -0
- data/test/sass/results/multiline.css +24 -0
- data/test/sass/templates/import.sass +4 -1
- data/test/sass/templates/importee.sass +4 -0
- data/test/sass/templates/mixins.sass +76 -0
- data/test/sass/templates/multiline.sass +20 -0
- metadata +65 -51
- data/lib/haml/util.rb +0 -18
- data/test/haml/runner.rb +0 -16
- data/test/profile.rb +0 -65
data/lib/sass/constant/color.rb
CHANGED
@@ -21,9 +21,9 @@ module Sass::Constant # :nodoc:
|
|
21
21
|
'teal' => 0x008080,
|
22
22
|
'aqua' => 0x00ffff
|
23
23
|
}
|
24
|
-
|
24
|
+
|
25
25
|
REGEXP = /\##{"([0-9a-fA-F]{1,2})" * 3}/
|
26
|
-
|
26
|
+
|
27
27
|
def parse(value)
|
28
28
|
if (value =~ REGEXP)
|
29
29
|
@value = value.scan(REGEXP)[0].map { |num| num.ljust(2, num).to_i(16) }
|
@@ -32,7 +32,7 @@ module Sass::Constant # :nodoc:
|
|
32
32
|
@value = (0..2).map{ |n| color >> (n << 3) & 0xff }.reverse
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def plus(other)
|
37
37
|
if other.is_a? Sass::Constant::String
|
38
38
|
Sass::Constant::String.from_value(self.to_s + other.to_s)
|
@@ -40,7 +40,7 @@ module Sass::Constant # :nodoc:
|
|
40
40
|
piecewise(other, :+)
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def minus(other)
|
45
45
|
if other.is_a? Sass::Constant::String
|
46
46
|
raise NoMethodError.new(nil, :minus)
|
@@ -48,7 +48,7 @@ module Sass::Constant # :nodoc:
|
|
48
48
|
piecewise(other, :-)
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
def times(other)
|
53
53
|
if other.is_a? Sass::Constant::String
|
54
54
|
raise NoMethodError.new(nil, :times)
|
@@ -56,7 +56,7 @@ module Sass::Constant # :nodoc:
|
|
56
56
|
piecewise(other, :*)
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def div(other)
|
61
61
|
if other.is_a? Sass::Constant::String
|
62
62
|
raise NoMethodError.new(nil, :div)
|
@@ -64,7 +64,7 @@ module Sass::Constant # :nodoc:
|
|
64
64
|
piecewise(other, :/)
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def mod(other)
|
69
69
|
if other.is_a? Sass::Constant::String
|
70
70
|
raise NoMethodError.new(nil, :mod)
|
@@ -72,24 +72,24 @@ module Sass::Constant # :nodoc:
|
|
72
72
|
piecewise(other, :%)
|
73
73
|
end
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
def to_s
|
77
77
|
red, green, blue = @value.map { |num| num.to_s(16).rjust(2, '0') }
|
78
78
|
"##{red}#{green}#{blue}"
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
protected
|
82
|
-
|
82
|
+
|
83
83
|
def self.filter_value(value)
|
84
84
|
value.map { |num| num.to_i }
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
private
|
88
|
-
|
88
|
+
|
89
89
|
def piecewise(other, operation)
|
90
90
|
other_num = other.is_a? Number
|
91
91
|
other_val = other.value
|
92
|
-
|
92
|
+
|
93
93
|
rgb = []
|
94
94
|
for i in (0...3)
|
95
95
|
res = @value[i].send(operation, other_num ? other_val : other_val[i])
|
@@ -13,7 +13,7 @@ class Sass::Constant::Literal # :nodoc:
|
|
13
13
|
|
14
14
|
# The regular expression matching colors.
|
15
15
|
COLOR = /^\# (?: [\da-f]{3} | [\da-f]{6} ) | #{html_color_matcher}/ix
|
16
|
-
|
16
|
+
|
17
17
|
def self.parse(value)
|
18
18
|
case value
|
19
19
|
when NUMBER
|
@@ -24,11 +24,11 @@ class Sass::Constant::Literal # :nodoc:
|
|
24
24
|
Sass::Constant::String.new(value)
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def initialize(value = nil)
|
29
29
|
self.parse(value) if value
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def perform
|
33
33
|
self
|
34
34
|
end
|
@@ -36,15 +36,15 @@ class Sass::Constant::Literal # :nodoc:
|
|
36
36
|
def concat(other)
|
37
37
|
Sass::Constant::String.from_value("#{self.to_s} #{other.to_s}")
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
attr_reader :value
|
41
|
-
|
41
|
+
|
42
42
|
protected
|
43
|
-
|
43
|
+
|
44
44
|
def self.filter_value(value)
|
45
45
|
value
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def self.from_value(value)
|
49
49
|
instance = self.new
|
50
50
|
instance.instance_variable_set('@value', self.filter_value(value))
|
data/lib/sass/constant/number.rb
CHANGED
@@ -10,7 +10,7 @@ module Sass::Constant # :nodoc:
|
|
10
10
|
@value = first.empty? ? second.to_i : "#{first}#{second}".to_f
|
11
11
|
@unit = unit unless unit.empty?
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def plus(other)
|
15
15
|
if other.is_a? Number
|
16
16
|
operate(other, :+)
|
@@ -20,7 +20,7 @@ module Sass::Constant # :nodoc:
|
|
20
20
|
Sass::Constant::String.from_value(self.to_s + other.to_s)
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def minus(other)
|
25
25
|
if other.is_a? Number
|
26
26
|
operate(other, :-)
|
@@ -28,7 +28,7 @@ module Sass::Constant # :nodoc:
|
|
28
28
|
raise NoMethodError.new(nil, :minus)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def times(other)
|
33
33
|
if other.is_a? Number
|
34
34
|
operate(other, :*)
|
@@ -38,7 +38,7 @@ module Sass::Constant # :nodoc:
|
|
38
38
|
raise NoMethodError.new(nil, :times)
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
def div(other)
|
43
43
|
if other.is_a? Number
|
44
44
|
operate(other, :/)
|
@@ -46,7 +46,7 @@ module Sass::Constant # :nodoc:
|
|
46
46
|
raise NoMethodError.new(nil, :div)
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def mod(other)
|
51
51
|
if other.is_a? Number
|
52
52
|
operate(other, :%)
|
@@ -54,13 +54,13 @@ module Sass::Constant # :nodoc:
|
|
54
54
|
raise NoMethodError.new(nil, :mod)
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
def to_s
|
59
59
|
value = @value
|
60
60
|
value = value.to_i if value % 1 == 0.0
|
61
61
|
"#{value}#{@unit}"
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
protected
|
65
65
|
|
66
66
|
def self.from_value(value, unit=nil)
|
@@ -68,7 +68,7 @@ module Sass::Constant # :nodoc:
|
|
68
68
|
instance.instance_variable_set('@unit', unit)
|
69
69
|
instance
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def operate(other, operation)
|
73
73
|
unit = nil
|
74
74
|
if other.unit.nil?
|
@@ -78,7 +78,7 @@ module Sass::Constant # :nodoc:
|
|
78
78
|
elsif other.unit == self.unit
|
79
79
|
unit = self.unit
|
80
80
|
else
|
81
|
-
raise Sass::SyntaxError.new("Incompatible units: #{self.unit} and #{other.unit}")
|
81
|
+
raise Sass::SyntaxError.new("Incompatible units: #{self.unit} and #{other.unit}.")
|
82
82
|
end
|
83
83
|
|
84
84
|
Number.from_value(self.value.send(operation, other.value), unit)
|
@@ -9,13 +9,13 @@ module Sass::Constant # :nodoc:
|
|
9
9
|
@operand2 = operand2
|
10
10
|
@operator = operator
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def to_s
|
14
14
|
self.perform.to_s
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
protected
|
18
|
-
|
18
|
+
|
19
19
|
def perform
|
20
20
|
literal1 = @operand1.perform
|
21
21
|
literal2 = @operand2.perform
|
@@ -23,7 +23,7 @@ module Sass::Constant # :nodoc:
|
|
23
23
|
literal1.send(@operator, literal2)
|
24
24
|
rescue NoMethodError => e
|
25
25
|
raise e unless e.name.to_s == @operator.to_s
|
26
|
-
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\"")
|
26
|
+
raise Sass::SyntaxError.new("Undefined operation: \"#{literal1} #{@operator} #{literal2}\".")
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/lib/sass/constant/string.rb
CHANGED
@@ -2,11 +2,11 @@ require 'sass/constant/literal'
|
|
2
2
|
|
3
3
|
module Sass::Constant # :nodoc:
|
4
4
|
class String < Literal # :nodoc:
|
5
|
-
|
5
|
+
|
6
6
|
def parse(value)
|
7
7
|
@value = value
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def plus(other)
|
11
11
|
Sass::Constant::String.from_value(self.to_s + other.to_s)
|
12
12
|
end
|
@@ -14,7 +14,7 @@ module Sass::Constant # :nodoc:
|
|
14
14
|
def funcall(other)
|
15
15
|
Sass::Constant::String.from_value("#{self.to_s}(#{other.to_s})")
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def to_s
|
19
19
|
@value
|
20
20
|
end
|
data/lib/sass/css.rb
CHANGED
@@ -6,11 +6,11 @@ module Sass
|
|
6
6
|
# :stopdoc:
|
7
7
|
module Tree
|
8
8
|
class Node
|
9
|
-
def to_sass
|
9
|
+
def to_sass(opts = {})
|
10
10
|
result = ''
|
11
11
|
|
12
12
|
children.each do |child|
|
13
|
-
result << "#{child.to_sass(0)}\n"
|
13
|
+
result << "#{child.to_sass(0, opts)}\n"
|
14
14
|
end
|
15
15
|
|
16
16
|
result
|
@@ -24,11 +24,11 @@ module Sass
|
|
24
24
|
end
|
25
25
|
|
26
26
|
class RuleNode
|
27
|
-
def to_sass(tabs)
|
28
|
-
str = "#{' ' * tabs}#{rule}\n"
|
27
|
+
def to_sass(tabs, opts = {})
|
28
|
+
str = "\n#{' ' * tabs}#{rule}#{children.any? { |c| c.is_a? AttrNode } ? "\n" : ''}"
|
29
29
|
|
30
30
|
children.each do |child|
|
31
|
-
str << "#{child.to_sass(tabs + 1)}"
|
31
|
+
str << "#{child.to_sass(tabs + 1, opts)}"
|
32
32
|
end
|
33
33
|
|
34
34
|
str
|
@@ -36,8 +36,8 @@ module Sass
|
|
36
36
|
end
|
37
37
|
|
38
38
|
class AttrNode
|
39
|
-
def to_sass(tabs)
|
40
|
-
"#{' ' * tabs}
|
39
|
+
def to_sass(tabs, opts = {})
|
40
|
+
"#{' ' * tabs}#{opts[:alternate] ? '' : ':'}#{name}#{opts[:alternate] ? ':' : ''} #{value}\n"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -46,25 +46,40 @@ module Sass
|
|
46
46
|
# It keeps the semantics and most of the efficiency of normal hashes
|
47
47
|
# while also keeping track of the order in which elements were set.
|
48
48
|
class OrderedHash
|
49
|
-
Node = Struct.new(
|
49
|
+
Node = Struct.new(:key, :value, :next, :prev)
|
50
50
|
include Enumerable
|
51
51
|
|
52
52
|
def initialize
|
53
53
|
@hash = {}
|
54
54
|
end
|
55
55
|
|
56
|
+
def initialize_copy(other)
|
57
|
+
@hash = other.instance_variable_get('@hash').clone
|
58
|
+
end
|
59
|
+
|
56
60
|
def [](key)
|
57
61
|
@hash[key] && @hash[key].value
|
58
62
|
end
|
59
63
|
|
60
64
|
def []=(key, value)
|
61
|
-
node = Node.new(key, value
|
65
|
+
node = Node.new(key, value)
|
66
|
+
|
67
|
+
if old = @hash[key]
|
68
|
+
if old.prev
|
69
|
+
old.prev.next = old.next
|
70
|
+
else # old is @first and @last
|
71
|
+
@first = @last = nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
62
75
|
if @first.nil?
|
63
76
|
@first = @last = node
|
64
77
|
else
|
78
|
+
node.prev = @last
|
65
79
|
@last.next = node
|
66
80
|
@last = node
|
67
81
|
end
|
82
|
+
|
68
83
|
@hash[key] = node
|
69
84
|
value
|
70
85
|
end
|
@@ -90,11 +105,12 @@ module Sass
|
|
90
105
|
|
91
106
|
# Creates a new instance of Sass::CSS that will compile the given document
|
92
107
|
# to a Sass string when +render+ is called.
|
93
|
-
def initialize(template)
|
108
|
+
def initialize(template, options = {})
|
94
109
|
if template.is_a? IO
|
95
110
|
template = template.read
|
96
111
|
end
|
97
112
|
|
113
|
+
@options = options
|
98
114
|
@template = StringScanner.new(template)
|
99
115
|
end
|
100
116
|
|
@@ -102,10 +118,10 @@ module Sass
|
|
102
118
|
# containing the CSS template.
|
103
119
|
def render
|
104
120
|
begin
|
105
|
-
build_tree.to_sass
|
121
|
+
build_tree.to_sass(@options).lstrip
|
106
122
|
rescue Exception => err
|
107
123
|
line = @template.string[0...@template.pos].split("\n").size
|
108
|
-
|
124
|
+
|
109
125
|
err.backtrace.unshift "(css):#{line}"
|
110
126
|
raise err
|
111
127
|
end
|
@@ -116,12 +132,13 @@ module Sass
|
|
116
132
|
def build_tree
|
117
133
|
root = Tree::Node.new(nil)
|
118
134
|
whitespace
|
119
|
-
directives
|
120
|
-
rules
|
121
|
-
expand_commas
|
122
|
-
|
123
|
-
|
124
|
-
|
135
|
+
directives root
|
136
|
+
rules root
|
137
|
+
expand_commas root
|
138
|
+
parent_ref_rules root
|
139
|
+
remove_parent_refs root
|
140
|
+
flatten_rules root
|
141
|
+
fold_commas root
|
125
142
|
root
|
126
143
|
end
|
127
144
|
|
@@ -164,12 +181,12 @@ module Sass
|
|
164
181
|
whitespace
|
165
182
|
|
166
183
|
assert_match /:/
|
167
|
-
|
184
|
+
|
168
185
|
value = ''
|
169
186
|
while @template.scan(/[^;\s\}]+/)
|
170
187
|
value << @template[0] << whitespace
|
171
188
|
end
|
172
|
-
|
189
|
+
|
173
190
|
assert_match /(;|(?=\}))/
|
174
191
|
rule << Tree::AttrNode.new(name, value, nil)
|
175
192
|
end
|
@@ -191,7 +208,10 @@ module Sass
|
|
191
208
|
|
192
209
|
def assert_match(re)
|
193
210
|
if !@template.scan(re)
|
194
|
-
|
211
|
+
line = @template.string[0..@template.pos].count "\n"
|
212
|
+
# Display basic regexps as plain old strings
|
213
|
+
expected = re.source == Regexp.escape(re.source) ? "\"#{re.source}\"" : re.inspect
|
214
|
+
raise Exception.new("Invalid CSS on line #{line}: expected #{expected}")
|
195
215
|
end
|
196
216
|
whitespace
|
197
217
|
end
|
@@ -224,7 +244,22 @@ module Sass
|
|
224
244
|
root.children.flatten!
|
225
245
|
end
|
226
246
|
|
227
|
-
#
|
247
|
+
# Make rules use parent refs so that
|
248
|
+
#
|
249
|
+
# foo
|
250
|
+
# color: green
|
251
|
+
# foo.bar
|
252
|
+
# color: blue
|
253
|
+
#
|
254
|
+
# becomes
|
255
|
+
#
|
256
|
+
# foo
|
257
|
+
# color: green
|
258
|
+
# &.bar
|
259
|
+
# color: blue
|
260
|
+
#
|
261
|
+
# This has the side effect of nesting rules,
|
262
|
+
# so that
|
228
263
|
#
|
229
264
|
# foo
|
230
265
|
# color: green
|
@@ -237,29 +272,50 @@ module Sass
|
|
237
272
|
#
|
238
273
|
# foo
|
239
274
|
# color: green
|
240
|
-
# bar
|
275
|
+
# & bar
|
241
276
|
# color: red
|
242
|
-
# baz
|
277
|
+
# & baz
|
243
278
|
# color: blue
|
244
|
-
#
|
245
|
-
def
|
279
|
+
#
|
280
|
+
def parent_ref_rules(root)
|
246
281
|
rules = OrderedHash.new
|
247
282
|
root.children.select { |c| Tree::RuleNode === c }.each do |child|
|
248
283
|
root.children.delete child
|
249
|
-
first, rest = child.rule.
|
284
|
+
first, rest = child.rule.scan(/^(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?$/).first
|
250
285
|
rules[first] ||= Tree::RuleNode.new(first, nil)
|
251
286
|
if rest
|
252
|
-
child.rule = rest
|
287
|
+
child.rule = "&" + rest
|
253
288
|
rules[first] << child
|
254
289
|
else
|
255
290
|
rules[first].children += child.children
|
256
291
|
end
|
257
292
|
end
|
258
293
|
|
259
|
-
rules.values.each { |v|
|
294
|
+
rules.values.each { |v| parent_ref_rules(v) }
|
260
295
|
root.children += rules.values
|
261
296
|
end
|
262
297
|
|
298
|
+
# Remove useless parent refs so that
|
299
|
+
#
|
300
|
+
# foo
|
301
|
+
# & bar
|
302
|
+
# color: blue
|
303
|
+
#
|
304
|
+
# becomes
|
305
|
+
#
|
306
|
+
# foo
|
307
|
+
# bar
|
308
|
+
# color: blue
|
309
|
+
#
|
310
|
+
def remove_parent_refs(root)
|
311
|
+
root.children.each do |child|
|
312
|
+
if child.is_a?(Tree::RuleNode)
|
313
|
+
child.rule.gsub! /^& /, ''
|
314
|
+
remove_parent_refs child
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
263
319
|
# Flatten rules so that
|
264
320
|
#
|
265
321
|
# foo
|
@@ -271,7 +327,18 @@ module Sass
|
|
271
327
|
#
|
272
328
|
# foo bar baz
|
273
329
|
# color: red
|
274
|
-
#
|
330
|
+
#
|
331
|
+
# and
|
332
|
+
#
|
333
|
+
# foo
|
334
|
+
# &.bar
|
335
|
+
# color: blue
|
336
|
+
#
|
337
|
+
# becomes
|
338
|
+
#
|
339
|
+
# foo.bar
|
340
|
+
# color: blue
|
341
|
+
#
|
275
342
|
def flatten_rules(root)
|
276
343
|
root.children.each { |child| flatten_rule(child) if child.is_a?(Tree::RuleNode) }
|
277
344
|
end
|
@@ -279,7 +346,13 @@ module Sass
|
|
279
346
|
def flatten_rule(rule)
|
280
347
|
while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
|
281
348
|
child = rule.children.first
|
282
|
-
|
349
|
+
|
350
|
+
if child.rule[0] == ?&
|
351
|
+
rule.rule = child.rule.gsub /^&/, rule.rule
|
352
|
+
else
|
353
|
+
rule.rule = "#{rule.rule} #{child.rule}"
|
354
|
+
end
|
355
|
+
|
283
356
|
rule.children = child.children
|
284
357
|
end
|
285
358
|
|