sass 3.3.0.alpha.231 → 3.3.0.alpha.243
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.
- data/README.md +1 -1
- data/REVISION +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/engine.rb +11 -7
- data/lib/sass/environment.rb +8 -0
- data/lib/sass/script/functions.rb +140 -17
- data/lib/sass/script/parser.rb +28 -5
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/value.rb +1 -0
- data/lib/sass/script/value/base.rb +29 -1
- data/lib/sass/script/value/color.rb +4 -0
- data/lib/sass/script/value/list.rb +27 -1
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/number.rb +12 -0
- data/lib/sass/scss/parser.rb +8 -2
- data/lib/sass/stack.rb +9 -0
- data/lib/sass/tree/each_node.rb +6 -6
- data/lib/sass/tree/rule_node.rb +1 -1
- data/lib/sass/tree/visitors/convert.rb +2 -1
- data/lib/sass/tree/visitors/perform.rb +19 -22
- data/lib/sass/tree/visitors/to_css.rb +1 -1
- data/test/sass/conversion_test.rb +10 -0
- data/test/sass/engine_test.rb +21 -0
- data/test/sass/functions_test.rb +126 -0
- data/test/sass/script_conversion_test.rb +16 -0
- data/test/sass/script_test.rb +41 -0
- data/test/sass/scss/scss_test.rb +25 -0
- metadata +11 -9
data/lib/sass/script/value.rb
CHANGED
@@ -158,6 +158,18 @@ MSG
|
|
158
158
|
Sass::Script::Value::String.new("/#{self.to_s}")
|
159
159
|
end
|
160
160
|
|
161
|
+
# Returns the hash code of this value. Two objects' hash codes should be
|
162
|
+
# equal if the objects are equal.
|
163
|
+
#
|
164
|
+
# @return [Fixnum] The hash code.
|
165
|
+
def hash
|
166
|
+
value.hash
|
167
|
+
end
|
168
|
+
|
169
|
+
def eql?(other)
|
170
|
+
self == other
|
171
|
+
end
|
172
|
+
|
161
173
|
# @return [String] A readable representation of the value
|
162
174
|
def inspect
|
163
175
|
value.inspect
|
@@ -185,14 +197,30 @@ MSG
|
|
185
197
|
# @raise [Sass::SyntaxError] if this value isn't an integer
|
186
198
|
def assert_int!; to_i; end
|
187
199
|
|
200
|
+
# Returns the separator for this value. For non-list-like values or the
|
201
|
+
# empty list, this will be `nil`. For lists or maps, it will be `:space` or
|
202
|
+
# `:comma`.
|
203
|
+
#
|
204
|
+
# @return [Symbol]
|
205
|
+
def separator; nil; end
|
206
|
+
|
188
207
|
# Returns the value of this value as a list.
|
189
208
|
# Single values are considered the same as single-element lists.
|
190
209
|
#
|
191
|
-
# @return [Array<Value>]
|
210
|
+
# @return [Array<Value>] This value as a list
|
192
211
|
def to_a
|
193
212
|
[self]
|
194
213
|
end
|
195
214
|
|
215
|
+
# Returns the value of this value as a hash. Most values don't have hash
|
216
|
+
# representations, but [Map]s and empty [List]s do.
|
217
|
+
#
|
218
|
+
# @return [Hash<Value, Value>] This value as a hash
|
219
|
+
# @raise [Sass::SyntaxError] if this value doesn't have a hash representation
|
220
|
+
def to_h
|
221
|
+
raise Sass::SyntaxError.new("#{self.inspect} is not a map.")
|
222
|
+
end
|
223
|
+
|
196
224
|
# Returns the string representation of this value
|
197
225
|
# as it would be output to the CSS document.
|
198
226
|
#
|
@@ -356,6 +356,10 @@ module Sass::Script::Value
|
|
356
356
|
other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha)
|
357
357
|
end
|
358
358
|
|
359
|
+
def hash
|
360
|
+
[rgb, alpha].hash
|
361
|
+
end
|
362
|
+
|
359
363
|
# Returns a copy of this color with one or more channels changed.
|
360
364
|
# RGB or HSL colors may be changed, but not both at once.
|
361
365
|
#
|
@@ -36,6 +36,10 @@ module Sass::Script::Value
|
|
36
36
|
self.separator == other.separator)
|
37
37
|
end
|
38
38
|
|
39
|
+
def hash
|
40
|
+
@hash ||= [value, separator].hash
|
41
|
+
end
|
42
|
+
|
39
43
|
# @see Value#to_s
|
40
44
|
def to_s(opts = {})
|
41
45
|
raise Sass::SyntaxError.new("() isn't a valid CSS value.") if value.empty?
|
@@ -48,7 +52,8 @@ module Sass::Script::Value
|
|
48
52
|
precedence = Sass::Script::Parser.precedence_of(separator)
|
49
53
|
value.reject {|e| e.is_a?(Null)}.map do |v|
|
50
54
|
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
|
51
|
-
separator == :space && v.is_a?(UnaryOperation) &&
|
55
|
+
separator == :space && v.is_a?(Sass::Script::Tree::UnaryOperation) &&
|
56
|
+
(v.operator == :minus || v.operator == :plus)
|
52
57
|
"(#{v.to_sass(opts)})"
|
53
58
|
else
|
54
59
|
v.to_sass(opts)
|
@@ -56,6 +61,27 @@ module Sass::Script::Value
|
|
56
61
|
end.join(sep_str(nil))
|
57
62
|
end
|
58
63
|
|
64
|
+
# @see Value#to_h
|
65
|
+
def to_h
|
66
|
+
return Sass::Util.ordered_hash if value.empty?
|
67
|
+
return @map ||= Sass::Util.to_hash(value.map {|e| e.to_a}) if is_pseudo_map?
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns whether a warning still needs to be printed for this list being used as a map.
|
72
|
+
#
|
73
|
+
# @return [Boolean]
|
74
|
+
def needs_map_warning?
|
75
|
+
!@value.empty? && !@map
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns whether this is a list of pairs that can be used as a map.
|
79
|
+
#
|
80
|
+
# @return [Boolean]
|
81
|
+
def is_pseudo_map?
|
82
|
+
@is_pseudo_map ||= value.all? {|e| e.is_a?(Sass::Script::Value::List) && e.to_a.length == 2}
|
83
|
+
end
|
84
|
+
|
59
85
|
# @see Value#inspect
|
60
86
|
def inspect
|
61
87
|
"(#{value.map {|e| e.inspect}.join(sep_str(nil))})"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Sass::Script::Value
|
2
|
+
# A SassScript object representing a map from keys to values. Both keys and
|
3
|
+
# values can be any SassScript object.
|
4
|
+
class Map < Base
|
5
|
+
# The Ruby hash containing the contents of this map.
|
6
|
+
#
|
7
|
+
# @return [Hash<Node, Node>]
|
8
|
+
attr_reader :value
|
9
|
+
alias_method :to_h, :value
|
10
|
+
|
11
|
+
# Creates a new map.
|
12
|
+
#
|
13
|
+
# @param hash [Hash<Node, Node>]
|
14
|
+
def initialize(hash)
|
15
|
+
super(Sass::Util.ordered_hash(hash))
|
16
|
+
end
|
17
|
+
|
18
|
+
# @see Value#options=
|
19
|
+
def options=(options)
|
20
|
+
super
|
21
|
+
value.each do |k, v|
|
22
|
+
k.options = options
|
23
|
+
v.options = options
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @see Value#separator
|
28
|
+
def separator
|
29
|
+
:comma unless value.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
# @see Value#to_a
|
33
|
+
def to_a
|
34
|
+
value.map do |k, v|
|
35
|
+
list = List.new([k, v], :space)
|
36
|
+
list.options = options
|
37
|
+
list
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @see Value#eq
|
42
|
+
def eq(other)
|
43
|
+
Bool.new(other.is_a?(Map) && self.value == other.value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hash
|
47
|
+
@hash ||= value.hash
|
48
|
+
end
|
49
|
+
|
50
|
+
# @see Value#to_s
|
51
|
+
def to_s(opts = {})
|
52
|
+
raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_sass(opts = {})
|
56
|
+
return "()" if value.empty?
|
57
|
+
|
58
|
+
to_sass = lambda do |value|
|
59
|
+
if value.is_a?(Map) || (value.is_a?(List) && value.separator == :comma)
|
60
|
+
"(#{value.to_sass(opts)})"
|
61
|
+
else
|
62
|
+
value.to_sass(opts)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
"(#{value.map {|(k, v)| "#{to_sass[k]}: #{to_sass[v]}"}.join(', ')})"
|
67
|
+
end
|
68
|
+
alias_method :inspect, :to_sass
|
69
|
+
end
|
70
|
+
end
|
@@ -206,6 +206,18 @@ module Sass::Script::Value
|
|
206
206
|
Bool.new(this.value == other.value)
|
207
207
|
end
|
208
208
|
|
209
|
+
def hash
|
210
|
+
[value, numerator_units, denominator_units].hash
|
211
|
+
end
|
212
|
+
|
213
|
+
# Hash-equality works differently than `==` equality for numbers.
|
214
|
+
# Hash-equality must be transitive, so it just compares the exact value,
|
215
|
+
# numerator units, and denominator units.
|
216
|
+
def eql?(other)
|
217
|
+
self.value == other.value && self.numerator_units == other.numerator_units &&
|
218
|
+
self.denominator_units == other.denominator_units
|
219
|
+
end
|
220
|
+
|
209
221
|
# The SassScript `>` operation.
|
210
222
|
#
|
211
223
|
# @param other [Number] The right-hand side of the operator
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -263,14 +263,20 @@ module Sass
|
|
263
263
|
|
264
264
|
def each_directive(start_pos)
|
265
265
|
tok!(/\$/)
|
266
|
-
|
266
|
+
vars = [tok!(IDENT)]
|
267
267
|
ss
|
268
|
+
while tok(/,/)
|
269
|
+
ss
|
270
|
+
tok!(/\$/)
|
271
|
+
vars << tok!(IDENT)
|
272
|
+
ss
|
273
|
+
end
|
268
274
|
|
269
275
|
tok!(/in/)
|
270
276
|
list = sass_script(:parse)
|
271
277
|
ss
|
272
278
|
|
273
|
-
block(node(Sass::Tree::EachNode.new(
|
279
|
+
block(node(Sass::Tree::EachNode.new(vars, list), start_pos), :directive)
|
274
280
|
end
|
275
281
|
|
276
282
|
def while_directive(start_pos)
|
data/lib/sass/stack.rb
CHANGED
@@ -98,6 +98,15 @@ module Sass
|
|
98
98
|
with_frame(filename, line, :mixin, name) {yield}
|
99
99
|
end
|
100
100
|
|
101
|
+
def to_s
|
102
|
+
Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
|
103
|
+
map do |(frame, caller), i|
|
104
|
+
"#{i == 0 ? "on" : "from"} line #{frame.line}" +
|
105
|
+
" of #{frame.filename || "an unknown file"}" +
|
106
|
+
(caller && caller.name ? ", in `#{caller.name}'" : "")
|
107
|
+
end.join("\n")
|
108
|
+
end
|
109
|
+
|
101
110
|
private
|
102
111
|
|
103
112
|
def with_frame(filename, line, type, name = nil)
|
data/lib/sass/tree/each_node.rb
CHANGED
@@ -5,18 +5,18 @@ module Sass::Tree
|
|
5
5
|
#
|
6
6
|
# @see Sass::Tree
|
7
7
|
class EachNode < Node
|
8
|
-
# The
|
9
|
-
# @return [String]
|
10
|
-
attr_reader :
|
8
|
+
# The names of the loop variables.
|
9
|
+
# @return [Array<String>]
|
10
|
+
attr_reader :vars
|
11
11
|
|
12
12
|
# The parse tree for the list.
|
13
13
|
# @return [Script::Tree::Node]
|
14
14
|
attr_accessor :list
|
15
15
|
|
16
|
-
# @param
|
16
|
+
# @param vars [Array<String>] The names of the loop variables
|
17
17
|
# @param list [Script::Tree::Node] The parse tree for the list
|
18
|
-
def initialize(
|
19
|
-
@
|
18
|
+
def initialize(vars, list)
|
19
|
+
@vars = vars
|
20
20
|
@list = list
|
21
21
|
super()
|
22
22
|
end
|
data/lib/sass/tree/rule_node.rb
CHANGED
@@ -58,7 +58,7 @@ module Sass::Tree
|
|
58
58
|
# This is only readable in a CSS tree as it is written during the perform step
|
59
59
|
# and only when the :trace_selectors option is set.
|
60
60
|
#
|
61
|
-
# @return [
|
61
|
+
# @return [String]
|
62
62
|
attr_accessor :stack_trace
|
63
63
|
|
64
64
|
# @param rule [Array<String, Sass::Script::Tree::Node>]
|
@@ -104,7 +104,8 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def visit_each(node)
|
107
|
-
|
107
|
+
vars = node.vars.map {|var| "$#{dasherize(var)}"}.join(", ")
|
108
|
+
"#{tab_str}@each #{vars} in #{node.list.to_sass(@options)}#{yield}"
|
108
109
|
end
|
109
110
|
|
110
111
|
def visit_extend(node)
|
@@ -91,12 +91,12 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
91
91
|
|
92
92
|
def initialize(env)
|
93
93
|
@environment = env
|
94
|
-
@stack = Sass::Stack.new
|
95
94
|
end
|
96
95
|
|
97
96
|
# If an exception is raised, this adds proper metadata to the backtrace.
|
98
97
|
def visit(node)
|
99
|
-
|
98
|
+
return super(node.dup) unless @environment
|
99
|
+
@environment.stack.with_base(node.filename, node.line) {super(node.dup)}
|
100
100
|
rescue Sass::SyntaxError => e
|
101
101
|
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
102
102
|
raise e
|
@@ -155,8 +155,14 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
155
155
|
list = node.list.perform(@environment)
|
156
156
|
|
157
157
|
with_environment Sass::Environment.new(@environment) do
|
158
|
-
list.to_a.map do |
|
159
|
-
|
158
|
+
list.to_a.map do |value|
|
159
|
+
if node.vars.length == 1
|
160
|
+
@environment.set_local_var(node.vars.first, value)
|
161
|
+
else
|
162
|
+
node.vars.zip(value.to_a) do |(var, sub_value)|
|
163
|
+
@environment.set_local_var(var, sub_value || Sass::Script::Value::Null.new)
|
164
|
+
end
|
165
|
+
end
|
160
166
|
node.children.map {|c| visit(c)}
|
161
167
|
end.flatten
|
162
168
|
end
|
@@ -220,12 +226,12 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
220
226
|
return resolved_node
|
221
227
|
end
|
222
228
|
file = node.imported_file
|
223
|
-
if @stack.frames.any? {|f| f.is_import? && f.filename == file.options[:filename]}
|
229
|
+
if @environment.stack.frames.any? {|f| f.is_import? && f.filename == file.options[:filename]}
|
224
230
|
handle_import_loop!(node)
|
225
231
|
end
|
226
232
|
|
227
233
|
begin
|
228
|
-
@stack.with_import(node.filename, node.line) do
|
234
|
+
@environment.stack.with_import(node.filename, node.line) do
|
229
235
|
root = file.to_tree
|
230
236
|
Sass::Tree::Visitors::CheckNesting.visit(root)
|
231
237
|
node.children = root.children.map {|c| visit(c)}.flatten
|
@@ -249,10 +255,10 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
249
255
|
# Runs a mixin.
|
250
256
|
def visit_mixin(node)
|
251
257
|
include_loop = true
|
252
|
-
handle_include_loop!(node) if @stack.frames.any? {|f| f.is_mixin? && f.name == node.name}
|
258
|
+
handle_include_loop!(node) if @environment.stack.frames.any? {|f| f.is_mixin? && f.name == node.name}
|
253
259
|
include_loop = false
|
254
260
|
|
255
|
-
@stack.with_mixin(node.filename, node.line, node.name) do
|
261
|
+
@environment.stack.with_mixin(node.filename, node.line, node.name) do
|
256
262
|
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin = @environment.mixin(node.name)
|
257
263
|
|
258
264
|
if node.children.any? && !mixin.has_content
|
@@ -282,7 +288,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
282
288
|
|
283
289
|
def visit_content(node)
|
284
290
|
return [] unless content = @environment.content
|
285
|
-
@stack.with_mixin(node.filename, node.line, '@content') do
|
291
|
+
@environment.stack.with_mixin(node.filename, node.line, '@content') do
|
286
292
|
trace_node = Sass::Tree::TraceNode.from_node('@content', node)
|
287
293
|
with_environment(@environment.caller) {trace_node.children = content.map {|c| visit(c.dup)}.flatten}
|
288
294
|
trace_node
|
@@ -315,7 +321,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
315
321
|
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
|
316
322
|
node.filename, node.options[:importer], node.line)
|
317
323
|
node.parsed_rules ||= parser.parse_selector
|
318
|
-
node.stack_trace =
|
324
|
+
node.stack_trace = @environment.stack.to_s if node.options[:trace_selectors]
|
319
325
|
yield
|
320
326
|
end
|
321
327
|
|
@@ -338,7 +344,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
338
344
|
res = node.expr.perform(@environment)
|
339
345
|
res = res.value if res.is_a?(Sass::Script::Value::String)
|
340
346
|
msg = "WARNING: #{res}\n "
|
341
|
-
msg <<
|
347
|
+
msg << @environment.stack.to_s.gsub("\n", "\n ") << "\n"
|
342
348
|
Sass::Util.sass_warn msg
|
343
349
|
[]
|
344
350
|
end
|
@@ -382,15 +388,6 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
382
388
|
|
383
389
|
private
|
384
390
|
|
385
|
-
def stack_trace
|
386
|
-
Sass::Util.enum_with_index(Sass::Util.enum_cons(@stack.frames.reverse + [nil], 2)).
|
387
|
-
map do |(frame, caller), i|
|
388
|
-
"#{i == 0 ? "on" : "from"} line #{frame.line}" +
|
389
|
-
" of #{frame.filename || "an unknown file"}" +
|
390
|
-
(caller && caller.name ? ", in `#{caller.name}'" : "")
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
391
|
def run_interp_no_strip(text)
|
395
392
|
text.map do |r|
|
396
393
|
next r if r.is_a?(String)
|
@@ -408,7 +405,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
408
405
|
def handle_include_loop!(node)
|
409
406
|
msg = "An @include loop has been found:"
|
410
407
|
content_count = 0
|
411
|
-
mixins = @stack.frames.select {|f| f.is_mixin?}.reverse.map {|f| f.name}.select do |name|
|
408
|
+
mixins = @environment.stack.frames.select {|f| f.is_mixin?}.reverse.map {|f| f.name}.select do |name|
|
412
409
|
if name == '@content'
|
413
410
|
content_count += 1
|
414
411
|
false
|
@@ -431,7 +428,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
431
428
|
|
432
429
|
def handle_import_loop!(node)
|
433
430
|
msg = "An @import loop has been found:"
|
434
|
-
files = @stack.frames.select {|f| f.is_import?}.map {|f| f.filename}.compact
|
431
|
+
files = @environment.stack.frames.select {|f| f.is_import?}.map {|f| f.filename}.compact
|
435
432
|
if node.filename == node.imported_file.options[:filename]
|
436
433
|
raise Sass::SyntaxError.new("#{msg} #{node.filename} imports itself")
|
437
434
|
end
|
@@ -280,7 +280,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
280
280
|
output "\n"
|
281
281
|
elsif node.options[:trace_selectors]
|
282
282
|
output("#{old_spaces}/* ")
|
283
|
-
output(node.stack_trace.
|
283
|
+
output(node.stack_trace.gsub("\n", "\n #{old_spaces}"))
|
284
284
|
output(" */\n")
|
285
285
|
elsif node.options[:line_comments]
|
286
286
|
output("#{old_spaces}/* line #{node.line}")
|
@@ -747,6 +747,10 @@ a
|
|
747
747
|
c
|
748
748
|
@each $str in foo, bar, baz, bang
|
749
749
|
d: $str
|
750
|
+
|
751
|
+
c
|
752
|
+
@each $key, $value in (foo: 1, bar: 2, baz: 3)
|
753
|
+
\#{$key}: $value
|
750
754
|
SASS
|
751
755
|
a {
|
752
756
|
@each $number in 1px 2px 3px 4px {
|
@@ -759,6 +763,12 @@ c {
|
|
759
763
|
d: $str;
|
760
764
|
}
|
761
765
|
}
|
766
|
+
|
767
|
+
c {
|
768
|
+
@each $key, $value in (foo: 1, bar: 2, baz: 3) {
|
769
|
+
\#{$key}: $value;
|
770
|
+
}
|
771
|
+
}
|
762
772
|
SCSS
|
763
773
|
end
|
764
774
|
|
data/test/sass/engine_test.rb
CHANGED
@@ -1646,6 +1646,27 @@ a
|
|
1646
1646
|
SASS
|
1647
1647
|
end
|
1648
1648
|
|
1649
|
+
def test_destructuring_each
|
1650
|
+
assert_equal <<CSS, render(<<SCSS)
|
1651
|
+
a {
|
1652
|
+
foo: 1px;
|
1653
|
+
bar: 2px;
|
1654
|
+
baz: 3px; }
|
1655
|
+
|
1656
|
+
c {
|
1657
|
+
foo: "Value is bar";
|
1658
|
+
bar: "Value is baz";
|
1659
|
+
bang: "Value is "; }
|
1660
|
+
CSS
|
1661
|
+
a
|
1662
|
+
@each $name, $number in (foo: 1px, bar: 2px, baz: 3px)
|
1663
|
+
\#{$name}: $number
|
1664
|
+
c
|
1665
|
+
@each $key, $value in (foo bar) (bar, baz) bang
|
1666
|
+
\#{$key}: "Value is \#{$value}"
|
1667
|
+
SCSS
|
1668
|
+
end
|
1669
|
+
|
1649
1670
|
def test_variable_reassignment
|
1650
1671
|
assert_equal(<<CSS, render(<<SASS))
|
1651
1672
|
a {
|