haml 3.0.0.rc.1 → 3.0.0.rc.2
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/REMEMBER +2 -3
- data/VERSION +1 -1
- data/lib/haml/exec.rb +7 -5
- data/lib/haml/util.rb +41 -1
- data/lib/haml/util/subset_map.rb +1 -1
- data/lib/sass/engine.rb +4 -0
- data/lib/sass/files.rb +1 -0
- data/lib/sass/script/lexer.rb +2 -2
- data/lib/sass/script/number.rb +8 -0
- data/lib/sass/scss/parser.rb +3 -0
- data/lib/sass/scss/static_parser.rb +2 -2
- data/lib/sass/selector/sequence.rb +15 -6
- data/lib/sass/selector/simple.rb +9 -4
- data/lib/sass/selector/simple_sequence.rb +13 -11
- data/lib/sass/tree/directive_node.rb +1 -1
- data/lib/sass/tree/extend_node.rb +7 -2
- data/lib/sass/tree/mixin_def_node.rb +12 -0
- data/lib/sass/tree/node.rb +40 -1
- data/lib/sass/tree/prop_node.rb +2 -2
- data/lib/sass/tree/rule_node.rb +5 -13
- data/test/haml/util_test.rb +44 -0
- data/test/sass/conversion_test.rb +83 -0
- data/test/sass/engine_test.rb +6 -0
- data/test/sass/extend_test.rb +104 -30
- data/test/sass/scss/css_test.rb +2 -0
- data/test/sass/scss/scss_test.rb +20 -3
- metadata +3 -3
data/REMEMBER
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
Be smart about default namespaces (http://www.w3.org/TR/css3-namespace/#declaration)
|
2
|
-
Pseudo-selectors should go to the end w/@extend
|
3
2
|
Extending nested selectors?
|
4
3
|
|
5
|
-
|
6
|
-
|
4
|
+
Less
|
5
|
+
including mixins across imports
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0.0.rc.
|
1
|
+
3.0.0.rc.2
|
data/lib/haml/exec.rb
CHANGED
@@ -58,8 +58,8 @@ module Haml
|
|
58
58
|
# SyntaxErrors have weird line reporting
|
59
59
|
# when there's trailing whitespace,
|
60
60
|
# which there is for Haml documents.
|
61
|
-
return exception.message.scan(/:(\d+)/).first.first if exception.is_a?(::SyntaxError)
|
62
|
-
exception.backtrace[0].scan(/:(\d+)/).first.first
|
61
|
+
return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError)
|
62
|
+
(exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
|
63
63
|
end
|
64
64
|
|
65
65
|
# Tells optparse how to parse the arguments
|
@@ -371,8 +371,9 @@ MSG
|
|
371
371
|
end
|
372
372
|
|
373
373
|
dirs, files = @args.map {|name| name.split(':', 2)}.
|
374
|
-
map {|from, to| [from, to || from.gsub(/\..*?$/, '.css')]}.
|
375
374
|
partition {|i, _| File.directory? i}
|
375
|
+
files.map! {|from, to| [from, to || from.gsub(/\..*?$/, '.css')]}
|
376
|
+
dirs.map! {|from, to| [from, to || from]}
|
376
377
|
::Sass::Plugin.options[:template_location] = dirs
|
377
378
|
|
378
379
|
::Sass::Plugin.on_updating_stylesheet do |_, css|
|
@@ -648,7 +649,7 @@ END
|
|
648
649
|
|
649
650
|
super
|
650
651
|
input = @options[:input]
|
651
|
-
raise "Error: '#{input}' is a directory (did you mean to use --recursive?)" if File.directory?(input)
|
652
|
+
raise "Error: '#{input.path}' is a directory (did you mean to use --recursive?)" if File.directory?(input)
|
652
653
|
output = @options[:output]
|
653
654
|
output = input if @options[:in_place]
|
654
655
|
process_file(input, output)
|
@@ -750,7 +751,8 @@ END
|
|
750
751
|
output.write(out)
|
751
752
|
rescue ::Sass::SyntaxError => e
|
752
753
|
raise e if @options[:trace]
|
753
|
-
|
754
|
+
file = " of #{e.sass_filename}" if e.sass_filename
|
755
|
+
raise "Error on line #{e.sass_line}#{file}: #{e.message}\n Use --trace for backtrace"
|
754
756
|
end
|
755
757
|
end
|
756
758
|
end
|
data/lib/haml/util.rb
CHANGED
@@ -189,7 +189,7 @@ module Haml
|
|
189
189
|
# # [2, 4, 5]]
|
190
190
|
def paths(arrs)
|
191
191
|
arrs.inject([[]]) do |paths, arr|
|
192
|
-
arr.map {|e| paths.map {|path| path + [e]}}
|
192
|
+
flatten(arr.map {|e| paths.map {|path| path + [e]}}, 1)
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
@@ -370,6 +370,14 @@ module Haml
|
|
370
370
|
Haml::Util::RUBY_VERSION[0] == 1 && Haml::Util::RUBY_VERSION[1] < 9
|
371
371
|
end
|
372
372
|
|
373
|
+
# Whether or not this is running under Ruby 1.8.6 or lower.
|
374
|
+
# Note that lower versions are not officially supported.
|
375
|
+
#
|
376
|
+
# @return [Boolean]
|
377
|
+
def ruby1_8_6?
|
378
|
+
ruby1_8? && Haml::Util::RUBY_VERSION[2] < 7
|
379
|
+
end
|
380
|
+
|
373
381
|
# Checks that the encoding of a string is valid in Ruby 1.9
|
374
382
|
# and cleans up potential encoding gotchas like the UTF-8 BOM.
|
375
383
|
# If it's not, yields an error string describing the invalid character
|
@@ -458,6 +466,38 @@ MSG
|
|
458
466
|
ruby1_8? ? c[0] : c.ord
|
459
467
|
end
|
460
468
|
|
469
|
+
# Flattens the first `n` nested arrays in a cross-version manner.
|
470
|
+
#
|
471
|
+
# @param arr [Array] The array to flatten
|
472
|
+
# @param n [Fixnum] The number of levels to flatten
|
473
|
+
# @return [Array] The flattened array
|
474
|
+
def flatten(arr, n)
|
475
|
+
return arr.flatten(n) unless ruby1_8_6?
|
476
|
+
return arr if n == 0
|
477
|
+
arr.inject([]) {|res, e| e.is_a?(Array) ? res.concat(flatten(e, n - 1)) : res << e}
|
478
|
+
end
|
479
|
+
|
480
|
+
# Returns the hash code for a set in a cross-version manner.
|
481
|
+
# Aggravatingly, this is order-dependent in Ruby 1.8.6.
|
482
|
+
#
|
483
|
+
# @param set [Set]
|
484
|
+
# @return [Fixnum] The order-independent hashcode of `set`
|
485
|
+
def set_hash(set)
|
486
|
+
return set.hash unless ruby1_8_6?
|
487
|
+
set.map {|e| e.hash}.uniq.sort.hash
|
488
|
+
end
|
489
|
+
|
490
|
+
# Tests the hash-equality of two sets in a cross-version manner.
|
491
|
+
# Aggravatingly, this is order-dependent in Ruby 1.8.6.
|
492
|
+
#
|
493
|
+
# @param set1 [Set]
|
494
|
+
# @param set2 [Set]
|
495
|
+
# @return [Boolean] Whether or not the sets are hashcode equal
|
496
|
+
def set_eql?(set1, set2)
|
497
|
+
return set1.eql?(set2) unless ruby1_8_6?
|
498
|
+
set1.to_a.uniq.sort_by {|e| e.hash}.eql?(set2.to_a.uniq.sort_by {|e| e.hash})
|
499
|
+
end
|
500
|
+
|
461
501
|
## Static Method Stuff
|
462
502
|
|
463
503
|
# The context in which the ERB for \{#def\_static\_method} will be run.
|
data/lib/haml/util/subset_map.rb
CHANGED
data/lib/sass/engine.rb
CHANGED
@@ -408,11 +408,15 @@ WARNING
|
|
408
408
|
return Tree::RuleNode.new(parse_interp(line.text))
|
409
409
|
end
|
410
410
|
res.unshift(hack_char) if hack_char
|
411
|
+
if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
|
412
|
+
res << comment
|
413
|
+
end
|
411
414
|
|
412
415
|
name = line.text[0...scanner.pos]
|
413
416
|
if scanner.scan(/\s*([:=])(?:\s|$)/)
|
414
417
|
parse_property(name, res, scanner[1], scanner.rest, :new, line)
|
415
418
|
else
|
419
|
+
res.pop if comment
|
416
420
|
Tree::RuleNode.new(res + parse_interp(scanner.rest))
|
417
421
|
end
|
418
422
|
end
|
data/lib/sass/files.rb
CHANGED
@@ -77,6 +77,7 @@ module Sass
|
|
77
77
|
end
|
78
78
|
|
79
79
|
new_filename = nil
|
80
|
+
load_paths = load_paths.uniq
|
80
81
|
load_paths.each do |load_path|
|
81
82
|
new_filename ||= find_full_path("#{filename}.sass", load_path) unless was_scss
|
82
83
|
new_filename ||= find_full_path("#{filename}.scss", load_path) unless was_sass
|
data/lib/sass/script/lexer.rb
CHANGED
@@ -149,10 +149,10 @@ module Sass
|
|
149
149
|
# @return [Boolean]
|
150
150
|
def whitespace?(tok = @tok)
|
151
151
|
if tok
|
152
|
-
@scanner.string[0...tok.pos] =~ /\s
|
152
|
+
@scanner.string[0...tok.pos] =~ /\s\Z/
|
153
153
|
else
|
154
154
|
@scanner.string[@scanner.pos, 1] =~ /^\s/ ||
|
155
|
-
@scanner.string[@scanner.pos - 1, 1] =~ /\s
|
155
|
+
@scanner.string[@scanner.pos - 1, 1] =~ /\s\Z/
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
data/lib/sass/script/number.rb
CHANGED
@@ -25,6 +25,14 @@ module Sass::Script
|
|
25
25
|
# @return [Array<String>]
|
26
26
|
attr_reader :denominator_units
|
27
27
|
|
28
|
+
# The original representation of this number.
|
29
|
+
# For example, although the result of `1px/2px` is `0.5`,
|
30
|
+
# the value of `#original` is `"1px/2px"`.
|
31
|
+
#
|
32
|
+
# This is only non-nil when the original value should be used as the CSS value,
|
33
|
+
# as in `font: 1px/2px`.
|
34
|
+
#
|
35
|
+
# @return [Boolean, nil]
|
28
36
|
attr_accessor :original
|
29
37
|
|
30
38
|
# The precision with which numbers will be printed to CSS files.
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -15,7 +15,7 @@ module Sass
|
|
15
15
|
# Used for error reporting
|
16
16
|
# @return [Selector::CommaSequence] The parsed selector
|
17
17
|
# @raise [Sass::SyntaxError] if there's a syntax error in the selector
|
18
|
-
def parse_selector(
|
18
|
+
def parse_selector(filename)
|
19
19
|
init_scanner!
|
20
20
|
selectors = [expr!(:_selector)]
|
21
21
|
while tok(/,/)
|
@@ -25,7 +25,7 @@ module Sass
|
|
25
25
|
end
|
26
26
|
expected("selector") unless @scanner.eos?
|
27
27
|
seq = Selector::CommaSequence.new(selectors)
|
28
|
-
seq.line = line
|
28
|
+
seq.line = @line
|
29
29
|
seq.filename = filename
|
30
30
|
seq
|
31
31
|
end
|
@@ -77,10 +77,19 @@ module Sass
|
|
77
77
|
# These correspond to a {CommaSequence}'s {CommaSequence#members members array}.
|
78
78
|
# @see CommaSequence#do_extend
|
79
79
|
def do_extend(extends, supers = [])
|
80
|
-
Haml::Util.paths(members.map do |sseq_or_op|
|
80
|
+
paths = Haml::Util.paths(members.map do |sseq_or_op|
|
81
81
|
next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
|
82
|
-
|
83
|
-
|
82
|
+
extended = sseq_or_op.do_extend(extends, supers)
|
83
|
+
choices = extended.map {|seq| seq.members}
|
84
|
+
choices.unshift([sseq_or_op]) unless extended.any? {|seq| seq.superselector?(sseq_or_op)}
|
85
|
+
choices
|
86
|
+
end)
|
87
|
+
Haml::Util.flatten(paths.map {|path| weave(path)}, 1).map {|p| Sequence.new(p)}
|
88
|
+
end
|
89
|
+
|
90
|
+
def superselector?(sseq)
|
91
|
+
return false unless members.size == 1
|
92
|
+
members.last.superselector?(sseq)
|
84
93
|
end
|
85
94
|
|
86
95
|
# @see Simple#to_a
|
@@ -134,9 +143,9 @@ module Sass
|
|
134
143
|
while !current.empty? && last_current.first.is_a?(String) || current.last.is_a?(String)
|
135
144
|
last_current.unshift(current.pop)
|
136
145
|
end
|
137
|
-
befores = befores.map do |before|
|
138
|
-
|
139
|
-
|
146
|
+
befores = Haml::Util.flatten(befores.map do |before|
|
147
|
+
subweave(before, current).map {|seqs| seqs + last_current}
|
148
|
+
end, 1)
|
140
149
|
return befores if afters.empty?
|
141
150
|
end
|
142
151
|
end
|
data/lib/sass/selector/simple.rb
CHANGED
@@ -75,10 +75,15 @@ module Sass
|
|
75
75
|
# this exception will only ever be raised as a result of programmer error
|
76
76
|
def unify(sels)
|
77
77
|
return sels if sels.any? {|sel2| eql?(sel2)}
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
sels_with_ix = Haml::Util.enum_with_index(sels)
|
79
|
+
_, i =
|
80
|
+
if self.is_a?(Pseudo) || self.is_a?(Negation)
|
81
|
+
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) && sels.last.type == :element}
|
82
|
+
else
|
83
|
+
sels_with_ix.find {|sel, _| sel.is_a?(Pseudo) || sel.is_a?(Negation)}
|
84
|
+
end
|
85
|
+
return sels + [self] unless i
|
86
|
+
return sels[0...i] + [self] + sels[i..-1]
|
82
87
|
end
|
83
88
|
|
84
89
|
protected
|
@@ -62,21 +62,18 @@ module Sass
|
|
62
62
|
# by extending this selector with `extends`.
|
63
63
|
# @see CommaSequence#do_extend
|
64
64
|
def do_extend(extends, supers = [])
|
65
|
-
|
65
|
+
extends.get(members.to_set).map do |seq, sels|
|
66
66
|
# If A {@extend B} and C {...},
|
67
67
|
# seq is A, sels is B, and self is C
|
68
68
|
|
69
69
|
self_without_sel = self.members - sels
|
70
70
|
next unless unified = seq.members.last.unify(self_without_sel)
|
71
71
|
[sels, seq.members[0...-1] + [unified]]
|
72
|
-
end.compact.map {|sels, seq| [sels, Sequence.new(seq)]}
|
73
|
-
|
74
|
-
|
75
|
-
seqs
|
76
|
-
|
77
|
-
supers.shift
|
78
|
-
new_seqs
|
79
|
-
end.flatten.uniq)
|
72
|
+
end.compact.map {|sels, seq| [sels, Sequence.new(seq)]}.map do |sels, seq|
|
73
|
+
seqs = seq.do_extend(extends, supers.unshift(sels))
|
74
|
+
supers.shift
|
75
|
+
seqs
|
76
|
+
end.flatten.uniq
|
80
77
|
rescue SystemStackError
|
81
78
|
handle_extend_loop(supers)
|
82
79
|
end
|
@@ -102,6 +99,10 @@ module Sass
|
|
102
99
|
SimpleSequence.new(sseq)
|
103
100
|
end
|
104
101
|
|
102
|
+
def superselector?(sseq)
|
103
|
+
(base.nil? || base.eql?(sseq.base)) && rest.subset?(sseq.rest)
|
104
|
+
end
|
105
|
+
|
105
106
|
# @see Simple#to_a
|
106
107
|
def to_a
|
107
108
|
@members.map {|sel| sel.to_a}.flatten
|
@@ -119,7 +120,7 @@ module Sass
|
|
119
120
|
#
|
120
121
|
# @return [Fixnum]
|
121
122
|
def hash
|
122
|
-
[base, rest].hash
|
123
|
+
[base, Haml::Util.set_hash(rest)].hash
|
123
124
|
end
|
124
125
|
|
125
126
|
# Checks equality between this and another object.
|
@@ -127,7 +128,8 @@ module Sass
|
|
127
128
|
# @param other [Object] The object to test equality against
|
128
129
|
# @return [Boolean] Whether or not this is equal to `other`
|
129
130
|
def eql?(other)
|
130
|
-
other.class == self.class && other.base.eql?(self.base) &&
|
131
|
+
other.class == self.class && other.base.eql?(self.base) &&
|
132
|
+
Haml::Util.set_eql?(other.rest, self.rest)
|
131
133
|
end
|
132
134
|
|
133
135
|
private
|
@@ -25,7 +25,7 @@ module Sass::Tree
|
|
25
25
|
# @see Node#to_src
|
26
26
|
def to_src(tabs, opts, fmt)
|
27
27
|
res = "#{' ' * tabs}#{value}"
|
28
|
-
return res + "#{semi fmt}\n"
|
28
|
+
return res + "#{semi fmt}\n" unless has_children
|
29
29
|
res + children_to_src(tabs, opts, fmt) + "\n"
|
30
30
|
end
|
31
31
|
|
@@ -46,14 +46,19 @@ module Sass::Tree
|
|
46
46
|
|
47
47
|
protected
|
48
48
|
|
49
|
+
# @see Node#to_src
|
50
|
+
def to_src(tabs, opts, fmt)
|
51
|
+
"#{' ' * tabs}@extend #{selector_to_src(@selector, tabs, opts, fmt).lstrip}#{semi fmt}\n"
|
52
|
+
end
|
53
|
+
|
49
54
|
# Runs SassScript interpolation in the selector,
|
50
55
|
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
51
56
|
#
|
52
57
|
# @param environment [Sass::Environment] The lexical environment containing
|
53
58
|
# variable and mixin values
|
54
59
|
def perform!(environment)
|
55
|
-
@resolved_selector = Sass::SCSS::CssParser.new(run_interp(@selector, environment)).
|
56
|
-
parse_selector(self.
|
60
|
+
@resolved_selector = Sass::SCSS::CssParser.new(run_interp(@selector, environment), self.line).
|
61
|
+
parse_selector(self.filename)
|
57
62
|
super
|
58
63
|
end
|
59
64
|
end
|
@@ -43,6 +43,18 @@ module Sass
|
|
43
43
|
environment.set_mixin(@name, Sass::Mixin.new(@name, @args, environment, children))
|
44
44
|
[]
|
45
45
|
end
|
46
|
+
|
47
|
+
# Returns an error message if the given child node is invalid,
|
48
|
+
# and false otherwise.
|
49
|
+
#
|
50
|
+
# {ExtendNode}s are valid within {MixinDefNode}s.
|
51
|
+
#
|
52
|
+
# @param child [Tree::Node] A potential child node.
|
53
|
+
# @return [Boolean, String] Whether or not the child node is valid,
|
54
|
+
# as well as the error message to display if it is invalid
|
55
|
+
def invalid_child?(child)
|
56
|
+
super unless child.is_a?(ExtendNode)
|
57
|
+
end
|
46
58
|
end
|
47
59
|
end
|
48
60
|
end
|
data/lib/sass/tree/node.rb
CHANGED
@@ -400,13 +400,52 @@ module Sass
|
|
400
400
|
# @param tabs [Fixnum] The amount of tabulation to use for the Sass code
|
401
401
|
# @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
|
402
402
|
# @param fmt [Symbol] `:sass` or `:scss`
|
403
|
-
# @return [String] The Sass or
|
403
|
+
# @return [String] The Sass or SCSS code corresponding to the children
|
404
404
|
def children_to_src(tabs, opts, fmt)
|
405
|
+
return fmt == :sass ? "\n" : " {}\n" if children.empty?
|
406
|
+
|
405
407
|
(fmt == :sass ? "\n" : " {\n") +
|
406
408
|
children.map {|c| c.send("to_#{fmt}", tabs + 1, opts)}.join.rstrip +
|
407
409
|
(fmt == :sass ? "\n" : " }\n")
|
408
410
|
end
|
409
411
|
|
412
|
+
# Converts a selector to a Sass or SCSS string.
|
413
|
+
#
|
414
|
+
# @param sel [Array<String, Sass::Script::Node>] The selector to convert
|
415
|
+
# @param tabs [Fixnum] The indentation of the selector
|
416
|
+
# @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
|
417
|
+
# @param fmt [Symbol] `:sass` or `:scss`
|
418
|
+
# @return [String] The Sass or SCSS code corresponding to the selector
|
419
|
+
def selector_to_src(sel, tabs, opts, fmt)
|
420
|
+
fmt == :sass ? selector_to_sass(sel, opts) : selector_to_scss(sel, tabs, opts)
|
421
|
+
end
|
422
|
+
|
423
|
+
# Converts a selector to a Sass string.
|
424
|
+
#
|
425
|
+
# @param sel [Array<String, Sass::Script::Node>] The selector to convert
|
426
|
+
# @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
|
427
|
+
# @return [String] The Sass code corresponding to the selector
|
428
|
+
def selector_to_sass(sel, opts)
|
429
|
+
sel.map do |r|
|
430
|
+
if r.is_a?(String)
|
431
|
+
r.gsub(/(,[ \t]*)?\n\s*/) {$1 ? $1 + "\n" : " "}
|
432
|
+
else
|
433
|
+
"\#{#{r.to_sass(opts)}}"
|
434
|
+
end
|
435
|
+
end.join
|
436
|
+
end
|
437
|
+
|
438
|
+
# Converts a selector to a SCSS string.
|
439
|
+
#
|
440
|
+
# @param sel [Array<String, Sass::Script::Node>] The selector to convert
|
441
|
+
# @param tabs [Fixnum] The indentation of the selector
|
442
|
+
# @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
|
443
|
+
# @return [String] The SCSS code corresponding to the selector
|
444
|
+
def selector_to_scss(sel, tabs, opts)
|
445
|
+
sel.map {|r| r.is_a?(String) ? r : "\#{#{r.to_sass(opts)}}"}.
|
446
|
+
join.gsub(/^[ \t]*/, ' ' * tabs)
|
447
|
+
end
|
448
|
+
|
410
449
|
# Convert any underscores in a string into hyphens,
|
411
450
|
# but only if the `:dasherize` option is set.
|
412
451
|
#
|
data/lib/sass/tree/prop_node.rb
CHANGED
@@ -179,7 +179,6 @@ module Sass::Tree
|
|
179
179
|
class << self
|
180
180
|
# @private
|
181
181
|
def val_to_sass(value, opts)
|
182
|
-
return value.to_sass(opts) unless value.context == :equals
|
183
182
|
val_to_sass_comma(value, opts).to_sass(opts)
|
184
183
|
end
|
185
184
|
|
@@ -208,7 +207,8 @@ module Sass::Tree
|
|
208
207
|
def val_to_sass_div(node, opts)
|
209
208
|
unless node.is_a?(Sass::Script::Operation) && node.operator == :div &&
|
210
209
|
node.operand1.is_a?(Sass::Script::Number) &&
|
211
|
-
node.operand2.is_a?(Sass::Script::Number)
|
210
|
+
node.operand2.is_a?(Sass::Script::Number) &&
|
211
|
+
(node.context == :equals || !node.operand1.original || !node.operand2.original)
|
212
212
|
return node
|
213
213
|
end
|
214
214
|
|
data/lib/sass/tree/rule_node.rb
CHANGED
@@ -84,22 +84,14 @@ module Sass::Tree
|
|
84
84
|
|
85
85
|
# @see Node#to_sass
|
86
86
|
def to_sass(tabs, opts = {})
|
87
|
-
name = rule
|
88
|
-
if r.is_a?(String)
|
89
|
-
r.gsub(/(,[ \t]*)?\n\s*/) {$1 ? $1 + "\n" : " "}
|
90
|
-
else
|
91
|
-
"\#{#{r.to_sass(opts)}}"
|
92
|
-
end
|
93
|
-
end.join
|
87
|
+
name = selector_to_sass(rule, opts)
|
94
88
|
name = "\\" + name if name[0] == ?:
|
95
89
|
name.gsub(/^/, ' ' * tabs) + children_to_src(tabs, opts, :sass)
|
96
90
|
end
|
97
91
|
|
98
92
|
# @see Node#to_scss
|
99
93
|
def to_scss(tabs, opts = {})
|
100
|
-
name = rule
|
101
|
-
join.gsub(/^[ \t]*/, ' ' * tabs)
|
102
|
-
|
94
|
+
name = selector_to_scss(rule, tabs, opts)
|
103
95
|
res = name + children_to_src(tabs, opts, :scss)
|
104
96
|
|
105
97
|
if children.last.is_a?(CommentNode) && children.last.silent
|
@@ -191,8 +183,8 @@ module Sass::Tree
|
|
191
183
|
# @param environment [Sass::Environment] The lexical environment containing
|
192
184
|
# variable and mixin values
|
193
185
|
def perform!(environment)
|
194
|
-
@parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment)).
|
195
|
-
parse_selector(self.
|
186
|
+
@parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment), self.line).
|
187
|
+
parse_selector(self.filename)
|
196
188
|
super
|
197
189
|
end
|
198
190
|
|
@@ -236,7 +228,7 @@ module Sass::Tree
|
|
236
228
|
#
|
237
229
|
# {ExtendNode}s are valid within {RuleNode}s.
|
238
230
|
#
|
239
|
-
# @param child [Tree::Node] A potential child
|
231
|
+
# @param child [Tree::Node] A potential child node.
|
240
232
|
# @return [Boolean, String] Whether or not the child node is valid,
|
241
233
|
# as well as the error message to display if it is invalid
|
242
234
|
def invalid_child?(child)
|
data/test/haml/util_test.rb
CHANGED
@@ -144,6 +144,50 @@ class UtilTest < Test::Unit::TestCase
|
|
144
144
|
assert_equal(98, ord("bar"))
|
145
145
|
end
|
146
146
|
|
147
|
+
def test_flatten
|
148
|
+
assert_equal([1, 2, 3], flatten([1, 2, 3], 0))
|
149
|
+
assert_equal([1, 2, 3], flatten([1, 2, 3], 1))
|
150
|
+
assert_equal([1, 2, 3], flatten([1, 2, 3], 2))
|
151
|
+
|
152
|
+
assert_equal([[1, 2], 3], flatten([[1, 2], 3], 0))
|
153
|
+
assert_equal([1, 2, 3], flatten([[1, 2], 3], 1))
|
154
|
+
assert_equal([1, 2, 3], flatten([[1, 2], 3], 2))
|
155
|
+
|
156
|
+
assert_equal([[[1], 2], [3], 4], flatten([[[1], 2], [3], 4], 0))
|
157
|
+
assert_equal([[1], 2, 3, 4], flatten([[[1], 2], [3], 4], 1))
|
158
|
+
assert_equal([1, 2, 3, 4], flatten([[[1], 2], [3], 4], 2))
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_set_hash
|
162
|
+
assert(set_hash(Set[1, 2, 3]) == set_hash(Set[3, 2, 1]))
|
163
|
+
assert(set_hash(Set[1, 2, 3]) == set_hash(Set[1, 2, 3]))
|
164
|
+
|
165
|
+
s1 = Set[]
|
166
|
+
s1 << 1
|
167
|
+
s1 << 2
|
168
|
+
s1 << 3
|
169
|
+
s2 = Set[]
|
170
|
+
s2 << 3
|
171
|
+
s2 << 2
|
172
|
+
s2 << 1
|
173
|
+
assert(set_hash(s1) == set_hash(s2))
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_set_eql
|
177
|
+
assert(set_eql?(Set[1, 2, 3], Set[3, 2, 1]))
|
178
|
+
assert(set_eql?(Set[1, 2, 3], Set[1, 2, 3]))
|
179
|
+
|
180
|
+
s1 = Set[]
|
181
|
+
s1 << 1
|
182
|
+
s1 << 2
|
183
|
+
s1 << 3
|
184
|
+
s2 = Set[]
|
185
|
+
s2 << 3
|
186
|
+
s2 << 2
|
187
|
+
s2 << 1
|
188
|
+
assert(set_eql?(s1, s2))
|
189
|
+
end
|
190
|
+
|
147
191
|
def test_caller_info
|
148
192
|
assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'"))
|
149
193
|
assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12"))
|
@@ -23,6 +23,19 @@ foo bar {
|
|
23
23
|
SCSS
|
24
24
|
end
|
25
25
|
|
26
|
+
def test_empty_selector
|
27
|
+
assert_renders "foo bar", "foo bar {}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_empty_directive
|
31
|
+
assert_scss_to_sass "@media screen", "@media screen {}"
|
32
|
+
assert_scss_to_scss "@media screen {}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_empty_control_directive
|
36
|
+
assert_renders "@if false", "@if false {}"
|
37
|
+
end
|
38
|
+
|
26
39
|
def test_nesting
|
27
40
|
assert_renders <<SASS, <<SCSS
|
28
41
|
foo bar
|
@@ -727,6 +740,18 @@ SASS
|
|
727
740
|
SCSS
|
728
741
|
end
|
729
742
|
|
743
|
+
def test_extend
|
744
|
+
assert_renders <<SASS, <<SCSS
|
745
|
+
.foo
|
746
|
+
@extend .bar
|
747
|
+
@extend .baz:bang
|
748
|
+
SASS
|
749
|
+
.foo {
|
750
|
+
@extend .bar;
|
751
|
+
@extend .baz:bang; }
|
752
|
+
SCSS
|
753
|
+
end
|
754
|
+
|
730
755
|
def test_argless_mixin_definition
|
731
756
|
assert_renders <<SASS, <<SCSS
|
732
757
|
=foo-bar
|
@@ -863,6 +888,60 @@ SCSS
|
|
863
888
|
assert_sass_to_scss '$var: 12px $bar baz !default;', '$var ||= 12px $bar "baz"'
|
864
889
|
end
|
865
890
|
|
891
|
+
def test_division_asserted_with_parens
|
892
|
+
assert_renders <<SASS, <<SCSS
|
893
|
+
foo
|
894
|
+
a: (1px / 2px)
|
895
|
+
SASS
|
896
|
+
foo {
|
897
|
+
a: (1px / 2px); }
|
898
|
+
SCSS
|
899
|
+
end
|
900
|
+
|
901
|
+
def test_division_not_asserted_when_unnecessary
|
902
|
+
assert_renders <<SASS, <<SCSS
|
903
|
+
$var: 1px / 2px
|
904
|
+
|
905
|
+
foo
|
906
|
+
a: $var
|
907
|
+
SASS
|
908
|
+
$var: 1px / 2px;
|
909
|
+
|
910
|
+
foo {
|
911
|
+
a: $var; }
|
912
|
+
SCSS
|
913
|
+
|
914
|
+
assert_renders <<SASS, <<SCSS
|
915
|
+
$var: 1px
|
916
|
+
|
917
|
+
foo
|
918
|
+
a: $var / 2px
|
919
|
+
SASS
|
920
|
+
$var: 1px;
|
921
|
+
|
922
|
+
foo {
|
923
|
+
a: $var / 2px; }
|
924
|
+
SCSS
|
925
|
+
|
926
|
+
assert_renders <<SASS, <<SCSS
|
927
|
+
foo
|
928
|
+
a: 1 + 1px / 2px
|
929
|
+
SASS
|
930
|
+
foo {
|
931
|
+
a: 1 + 1px / 2px; }
|
932
|
+
SCSS
|
933
|
+
end
|
934
|
+
|
935
|
+
def test_literal_slash
|
936
|
+
assert_renders <<SASS, <<SCSS
|
937
|
+
foo
|
938
|
+
a: 1px / 2px
|
939
|
+
SASS
|
940
|
+
foo {
|
941
|
+
a: 1px / 2px; }
|
942
|
+
SCSS
|
943
|
+
end
|
944
|
+
|
866
945
|
# Hacks
|
867
946
|
|
868
947
|
def test_declaration_hacks
|
@@ -872,6 +951,8 @@ foo
|
|
872
951
|
*name: val
|
873
952
|
#name: val
|
874
953
|
.name: val
|
954
|
+
name/**/: val
|
955
|
+
name/*\\**/: val
|
875
956
|
name: val
|
876
957
|
SASS
|
877
958
|
foo {
|
@@ -879,6 +960,8 @@ foo {
|
|
879
960
|
*name: val;
|
880
961
|
#name: val;
|
881
962
|
.name: val;
|
963
|
+
name/**/: val;
|
964
|
+
name/*\\**/: val;
|
882
965
|
name: val; }
|
883
966
|
SCSS
|
884
967
|
end
|
data/test/sass/engine_test.rb
CHANGED
@@ -32,6 +32,8 @@ MSG
|
|
32
32
|
"a\n :b:c d" => 'Invalid property: ":b:c d".',
|
33
33
|
"a\n :b c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
|
34
34
|
"a\n b: c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
|
35
|
+
".foo ^bar\n a: b" => ['Invalid CSS after ".foo ": expected selector, was "^bar"', 1],
|
36
|
+
"a\n @extend .foo ^bar" => 'Invalid CSS after ".foo ": expected selector, was "^bar"',
|
35
37
|
"a: b" => 'Properties aren\'t allowed at the root of a document.',
|
36
38
|
":a b" => 'Properties aren\'t allowed at the root of a document.',
|
37
39
|
"!" => 'Invalid variable: "!".',
|
@@ -599,6 +601,8 @@ foo {
|
|
599
601
|
*name: val;
|
600
602
|
#name: val;
|
601
603
|
.name: val;
|
604
|
+
name/**/: val;
|
605
|
+
name/*\\**/: val;
|
602
606
|
name: val; }
|
603
607
|
CSS
|
604
608
|
foo
|
@@ -606,6 +610,8 @@ foo
|
|
606
610
|
*name: val
|
607
611
|
#name: val
|
608
612
|
.name: val
|
613
|
+
name/**/: val
|
614
|
+
name/*\\**/: val
|
609
615
|
name: val
|
610
616
|
SASS
|
611
617
|
end
|
data/test/sass/extend_test.rb
CHANGED
@@ -102,7 +102,7 @@ CSS
|
|
102
102
|
SCSS
|
103
103
|
|
104
104
|
assert_equal <<CSS, render(<<SCSS)
|
105
|
-
.foo.bar, .
|
105
|
+
.foo.bar, .baz {
|
106
106
|
a: b; }
|
107
107
|
CSS
|
108
108
|
.foo.bar {a: b}
|
@@ -121,7 +121,7 @@ CSS
|
|
121
121
|
SCSS
|
122
122
|
|
123
123
|
assert_equal <<CSS, render(<<SCSS)
|
124
|
-
.foo.bar, .bar.baz, .
|
124
|
+
.foo.bar, .bar.baz, .baz.bang, .foo.bang {
|
125
125
|
a: b; }
|
126
126
|
CSS
|
127
127
|
.foo.bar {a: b}
|
@@ -190,7 +190,7 @@ CSS
|
|
190
190
|
SCSS
|
191
191
|
|
192
192
|
assert_equal <<CSS, render(<<SCSS)
|
193
|
-
.
|
193
|
+
.baz {
|
194
194
|
a: b; }
|
195
195
|
CSS
|
196
196
|
.foo.baz {a: b}
|
@@ -208,7 +208,7 @@ CSS
|
|
208
208
|
SCSS
|
209
209
|
|
210
210
|
assert_equal <<CSS, render(<<SCSS)
|
211
|
-
|
211
|
+
#baz {
|
212
212
|
a: b; }
|
213
213
|
CSS
|
214
214
|
.foo#baz {a: b}
|
@@ -242,7 +242,7 @@ CSS
|
|
242
242
|
SCSS
|
243
243
|
|
244
244
|
assert_equal <<CSS, render(<<SCSS)
|
245
|
-
.
|
245
|
+
.bar {
|
246
246
|
a: b; }
|
247
247
|
CSS
|
248
248
|
.foo.bar {a: b}
|
@@ -250,7 +250,7 @@ CSS
|
|
250
250
|
SCSS
|
251
251
|
|
252
252
|
assert_equal <<CSS, render(<<SCSS)
|
253
|
-
.
|
253
|
+
.bar {
|
254
254
|
a: b; }
|
255
255
|
CSS
|
256
256
|
.foo.bar {a: b}
|
@@ -268,7 +268,7 @@ SCSS
|
|
268
268
|
|
269
269
|
def test_universal_unification_with_namespaceless_universal_target
|
270
270
|
assert_equal <<CSS, render(<<SCSS)
|
271
|
-
|
271
|
+
* {
|
272
272
|
a: b; }
|
273
273
|
CSS
|
274
274
|
*.foo {a: b}
|
@@ -276,7 +276,7 @@ CSS
|
|
276
276
|
SCSS
|
277
277
|
|
278
278
|
assert_equal <<CSS, render(<<SCSS)
|
279
|
-
|
279
|
+
* {
|
280
280
|
a: b; }
|
281
281
|
CSS
|
282
282
|
*.foo {a: b}
|
@@ -292,7 +292,7 @@ CSS
|
|
292
292
|
SCSS
|
293
293
|
|
294
294
|
assert_equal <<CSS, render(<<SCSS)
|
295
|
-
|
295
|
+
*|* {
|
296
296
|
a: b; }
|
297
297
|
CSS
|
298
298
|
*|*.foo {a: b}
|
@@ -318,7 +318,7 @@ SCSS
|
|
318
318
|
|
319
319
|
def test_universal_unification_with_namespaced_universal_target
|
320
320
|
assert_equal <<CSS, render(<<SCSS)
|
321
|
-
ns
|
321
|
+
ns|* {
|
322
322
|
a: b; }
|
323
323
|
CSS
|
324
324
|
ns|*.foo {a: b}
|
@@ -326,7 +326,7 @@ ns|*.foo {a: b}
|
|
326
326
|
SCSS
|
327
327
|
|
328
328
|
assert_equal <<CSS, render(<<SCSS)
|
329
|
-
ns
|
329
|
+
ns|* {
|
330
330
|
a: b; }
|
331
331
|
CSS
|
332
332
|
ns|*.foo {a: b}
|
@@ -342,7 +342,7 @@ ns2|* {@extend .foo}
|
|
342
342
|
SCSS
|
343
343
|
|
344
344
|
assert_equal <<CSS, render(<<SCSS)
|
345
|
-
ns
|
345
|
+
ns|* {
|
346
346
|
a: b; }
|
347
347
|
CSS
|
348
348
|
ns|*.foo {a: b}
|
@@ -352,7 +352,7 @@ SCSS
|
|
352
352
|
|
353
353
|
def test_universal_unification_with_namespaceless_element_target
|
354
354
|
assert_equal <<CSS, render(<<SCSS)
|
355
|
-
a
|
355
|
+
a {
|
356
356
|
a: b; }
|
357
357
|
CSS
|
358
358
|
a.foo {a: b}
|
@@ -360,7 +360,7 @@ a.foo {a: b}
|
|
360
360
|
SCSS
|
361
361
|
|
362
362
|
assert_equal <<CSS, render(<<SCSS)
|
363
|
-
a
|
363
|
+
a {
|
364
364
|
a: b; }
|
365
365
|
CSS
|
366
366
|
a.foo {a: b}
|
@@ -376,7 +376,7 @@ CSS
|
|
376
376
|
SCSS
|
377
377
|
|
378
378
|
assert_equal <<CSS, render(<<SCSS)
|
379
|
-
*|a
|
379
|
+
*|a {
|
380
380
|
a: b; }
|
381
381
|
CSS
|
382
382
|
*|a.foo {a: b}
|
@@ -402,7 +402,7 @@ SCSS
|
|
402
402
|
|
403
403
|
def test_universal_unification_with_namespaced_element_target
|
404
404
|
assert_equal <<CSS, render(<<SCSS)
|
405
|
-
ns|a
|
405
|
+
ns|a {
|
406
406
|
a: b; }
|
407
407
|
CSS
|
408
408
|
ns|a.foo {a: b}
|
@@ -410,7 +410,7 @@ ns|a.foo {a: b}
|
|
410
410
|
SCSS
|
411
411
|
|
412
412
|
assert_equal <<CSS, render(<<SCSS)
|
413
|
-
ns|a
|
413
|
+
ns|a {
|
414
414
|
a: b; }
|
415
415
|
CSS
|
416
416
|
ns|a.foo {a: b}
|
@@ -426,7 +426,7 @@ ns2|* {@extend .foo}
|
|
426
426
|
SCSS
|
427
427
|
|
428
428
|
assert_equal <<CSS, render(<<SCSS)
|
429
|
-
ns|a
|
429
|
+
ns|a {
|
430
430
|
a: b; }
|
431
431
|
CSS
|
432
432
|
ns|a.foo {a: b}
|
@@ -554,7 +554,7 @@ SCSS
|
|
554
554
|
|
555
555
|
def test_element_unification_with_namespaceless_element_target
|
556
556
|
assert_equal <<CSS, render(<<SCSS)
|
557
|
-
a
|
557
|
+
a {
|
558
558
|
a: b; }
|
559
559
|
CSS
|
560
560
|
a.foo {a: b}
|
@@ -562,7 +562,7 @@ a {@extend .foo}
|
|
562
562
|
SCSS
|
563
563
|
|
564
564
|
assert_equal <<CSS, render(<<SCSS)
|
565
|
-
a
|
565
|
+
a {
|
566
566
|
a: b; }
|
567
567
|
CSS
|
568
568
|
a.foo {a: b}
|
@@ -578,7 +578,7 @@ a {@extend .foo}
|
|
578
578
|
SCSS
|
579
579
|
|
580
580
|
assert_equal <<CSS, render(<<SCSS)
|
581
|
-
*|a
|
581
|
+
*|a {
|
582
582
|
a: b; }
|
583
583
|
CSS
|
584
584
|
*|a.foo {a: b}
|
@@ -612,7 +612,7 @@ SCSS
|
|
612
612
|
|
613
613
|
def test_element_unification_with_namespaced_element_target
|
614
614
|
assert_equal <<CSS, render(<<SCSS)
|
615
|
-
ns|a
|
615
|
+
ns|a {
|
616
616
|
a: b; }
|
617
617
|
CSS
|
618
618
|
ns|a.foo {a: b}
|
@@ -620,7 +620,7 @@ a {@extend .foo}
|
|
620
620
|
SCSS
|
621
621
|
|
622
622
|
assert_equal <<CSS, render(<<SCSS)
|
623
|
-
ns|a
|
623
|
+
ns|a {
|
624
624
|
a: b; }
|
625
625
|
CSS
|
626
626
|
ns|a.foo {a: b}
|
@@ -636,7 +636,7 @@ ns2|a {@extend .foo}
|
|
636
636
|
SCSS
|
637
637
|
|
638
638
|
assert_equal <<CSS, render(<<SCSS)
|
639
|
-
ns|a
|
639
|
+
ns|a {
|
640
640
|
a: b; }
|
641
641
|
CSS
|
642
642
|
ns|a.foo {a: b}
|
@@ -678,7 +678,7 @@ CSS
|
|
678
678
|
SCSS
|
679
679
|
|
680
680
|
assert_equal <<CSS, render(<<SCSS)
|
681
|
-
[foo=bar]
|
681
|
+
[foo=bar] {
|
682
682
|
a: b; }
|
683
683
|
CSS
|
684
684
|
[foo=bar].baz {a: b}
|
@@ -720,7 +720,7 @@ CSS
|
|
720
720
|
SCSS
|
721
721
|
|
722
722
|
assert_equal <<CSS, render(<<SCSS)
|
723
|
-
::foo
|
723
|
+
::foo {
|
724
724
|
a: b; }
|
725
725
|
CSS
|
726
726
|
::foo.baz {a: b}
|
@@ -728,7 +728,7 @@ CSS
|
|
728
728
|
SCSS
|
729
729
|
|
730
730
|
assert_equal <<CSS, render(<<SCSS)
|
731
|
-
::foo(2n+1)
|
731
|
+
::foo(2n+1) {
|
732
732
|
a: b; }
|
733
733
|
CSS
|
734
734
|
::foo(2n+1).baz {a: b}
|
@@ -744,7 +744,7 @@ CSS
|
|
744
744
|
SCSS
|
745
745
|
|
746
746
|
assert_equal <<CSS, render(<<SCSS)
|
747
|
-
:foo
|
747
|
+
:foo {
|
748
748
|
a: b; }
|
749
749
|
CSS
|
750
750
|
:foo.baz {a: b}
|
@@ -770,6 +770,70 @@ a.foo::bar {a: b}
|
|
770
770
|
SCSS
|
771
771
|
end
|
772
772
|
|
773
|
+
def test_pseudoclass_remains_at_end_of_selector
|
774
|
+
assert_equal <<CSS, render(<<SCSS)
|
775
|
+
.foo:bar, .baz:bar {
|
776
|
+
a: b; }
|
777
|
+
CSS
|
778
|
+
.foo:bar {a: b}
|
779
|
+
.baz {@extend .foo}
|
780
|
+
SCSS
|
781
|
+
|
782
|
+
assert_equal <<CSS, render(<<SCSS)
|
783
|
+
a.foo:bar, a.baz:bar {
|
784
|
+
a: b; }
|
785
|
+
CSS
|
786
|
+
a.foo:bar {a: b}
|
787
|
+
.baz {@extend .foo}
|
788
|
+
SCSS
|
789
|
+
end
|
790
|
+
|
791
|
+
def test_not_remains_at_end_of_selector
|
792
|
+
assert_equal <<CSS, render(<<SCSS)
|
793
|
+
.foo:not(.bar), .baz:not(.bar) {
|
794
|
+
a: b; }
|
795
|
+
CSS
|
796
|
+
.foo:not(.bar) {a: b}
|
797
|
+
.baz {@extend .foo}
|
798
|
+
SCSS
|
799
|
+
end
|
800
|
+
|
801
|
+
def test_pseudoelement_goes_lefter_than_pseudoclass
|
802
|
+
assert_equal <<CSS, render(<<SCSS)
|
803
|
+
.foo::bar, .baz:bang::bar {
|
804
|
+
a: b; }
|
805
|
+
CSS
|
806
|
+
.foo::bar {a: b}
|
807
|
+
.baz:bang {@extend .foo}
|
808
|
+
SCSS
|
809
|
+
|
810
|
+
assert_equal <<CSS, render(<<SCSS)
|
811
|
+
.foo:bar, .baz:bar::bang {
|
812
|
+
a: b; }
|
813
|
+
CSS
|
814
|
+
.foo:bar {a: b}
|
815
|
+
.baz::bang {@extend .foo}
|
816
|
+
SCSS
|
817
|
+
end
|
818
|
+
|
819
|
+
def test_pseudoelement_goes_lefter_than_not
|
820
|
+
assert_equal <<CSS, render(<<SCSS)
|
821
|
+
.foo::bar, .baz:not(.bang)::bar {
|
822
|
+
a: b; }
|
823
|
+
CSS
|
824
|
+
.foo::bar {a: b}
|
825
|
+
.baz:not(.bang) {@extend .foo}
|
826
|
+
SCSS
|
827
|
+
|
828
|
+
assert_equal <<CSS, render(<<SCSS)
|
829
|
+
.foo:not(.bang), .baz:not(.bang)::bar {
|
830
|
+
a: b; }
|
831
|
+
CSS
|
832
|
+
.foo:not(.bang) {a: b}
|
833
|
+
.baz::bar {@extend .foo}
|
834
|
+
SCSS
|
835
|
+
end
|
836
|
+
|
773
837
|
def test_negation_unification
|
774
838
|
assert_equal <<CSS, render(<<SCSS)
|
775
839
|
:not(.foo).baz, :not(.foo):not(.bar) {
|
@@ -780,7 +844,7 @@ CSS
|
|
780
844
|
SCSS
|
781
845
|
|
782
846
|
assert_equal <<CSS, render(<<SCSS)
|
783
|
-
:not(.foo)
|
847
|
+
:not(.foo) {
|
784
848
|
a: b; }
|
785
849
|
CSS
|
786
850
|
:not(.foo).baz {a: b}
|
@@ -788,7 +852,7 @@ CSS
|
|
788
852
|
SCSS
|
789
853
|
|
790
854
|
assert_equal <<CSS, render(<<SCSS)
|
791
|
-
:not([a=b])
|
855
|
+
:not([a=b]) {
|
792
856
|
a: b; }
|
793
857
|
CSS
|
794
858
|
:not([a=b]).baz {a: b}
|
@@ -1036,6 +1100,16 @@ CSS
|
|
1036
1100
|
SCSS
|
1037
1101
|
end
|
1038
1102
|
|
1103
|
+
def test_multiple_extender_merges_with_superset_selector
|
1104
|
+
assert_equal <<CSS, render(<<SCSS)
|
1105
|
+
a.bar.baz, a.foo {
|
1106
|
+
a: b; }
|
1107
|
+
CSS
|
1108
|
+
.foo {@extend .bar; @extend .baz}
|
1109
|
+
a.bar.baz {a: b}
|
1110
|
+
SCSS
|
1111
|
+
end
|
1112
|
+
|
1039
1113
|
private
|
1040
1114
|
|
1041
1115
|
def render(sass, options = {})
|
data/test/sass/scss/css_test.rb
CHANGED
data/test/sass/scss/scss_test.rb
CHANGED
@@ -942,9 +942,11 @@ SCSS
|
|
942
942
|
end
|
943
943
|
|
944
944
|
def test_post_resolution_selector_error
|
945
|
-
|
946
|
-
|
947
|
-
|
945
|
+
render "\n\nfoo \#{\") bar\"} {a: b}"
|
946
|
+
assert(false, "Expected syntax error")
|
947
|
+
rescue Sass::SyntaxError => e
|
948
|
+
assert_equal 'Invalid CSS after "foo ": expected selector, was ") bar"', e.message
|
949
|
+
assert_equal 3, e.sass_line
|
948
950
|
end
|
949
951
|
|
950
952
|
def test_parent_in_mid_selector_error
|
@@ -968,6 +970,21 @@ SCSS
|
|
968
970
|
flim {
|
969
971
|
&& {a: b}
|
970
972
|
}
|
973
|
+
SCSS
|
974
|
+
end
|
975
|
+
|
976
|
+
# Regression
|
977
|
+
|
978
|
+
def test_weird_added_space
|
979
|
+
assert_equal <<CSS, render(<<SCSS)
|
980
|
+
foo {
|
981
|
+
bar: -moz-bip; }
|
982
|
+
CSS
|
983
|
+
$value : bip;
|
984
|
+
|
985
|
+
foo {
|
986
|
+
bar: -moz-\#{$value};
|
987
|
+
}
|
971
988
|
SCSS
|
972
989
|
end
|
973
990
|
end
|
metadata
CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
|
|
7
7
|
- 0
|
8
8
|
- 0
|
9
9
|
- rc
|
10
|
-
-
|
11
|
-
version: 3.0.0.rc.
|
10
|
+
- 2
|
11
|
+
version: 3.0.0.rc.2
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Nathan Weizenbaum
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2010-04-
|
20
|
+
date: 2010-04-27 00:00:00 -07:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|