sass 3.2.0.alpha.104 → 3.2.0.alpha.236
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/REVISION +1 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/sass/engine.rb +8 -1
- data/lib/sass/exec.rb +2 -2
- data/lib/sass/plugin/compiler.rb +51 -43
- data/lib/sass/script/color.rb +4 -9
- data/lib/sass/script/funcall.rb +11 -2
- data/lib/sass/script/functions.rb +16 -30
- data/lib/sass/script/lexer.rb +7 -1
- data/lib/sass/script/list.rb +2 -2
- data/lib/sass/script/literal.rb +8 -0
- data/lib/sass/script/null.rb +34 -0
- data/lib/sass/script/operation.rb +4 -0
- data/lib/sass/script/parser.rb +4 -2
- data/lib/sass/scss/parser.rb +1 -5
- data/lib/sass/scss/rx.rb +1 -1
- data/lib/sass/tree/directive_node.rb +5 -0
- data/lib/sass/tree/media_node.rb +3 -0
- data/lib/sass/tree/prop_node.rb +7 -3
- data/lib/sass/tree/visitors/base.rb +1 -1
- data/lib/sass/tree/visitors/check_nesting.rb +21 -18
- data/lib/sass/tree/visitors/convert.rb +1 -0
- data/lib/sass/tree/visitors/perform.rb +3 -2
- data/lib/sass/tree/visitors/to_css.rb +1 -0
- data/lib/sass/util.rb +28 -0
- data/test/sass/conversion_test.rb +33 -0
- data/test/sass/engine_test.rb +118 -3
- data/test/sass/functions_test.rb +56 -24
- data/test/sass/script_test.rb +60 -4
- data/test/sass/scss/scss_test.rb +10 -0
- data/vendor/listen/CHANGELOG.md +19 -1
- data/vendor/listen/README.md +27 -12
- data/vendor/listen/lib/listen/adapter.rb +9 -1
- data/vendor/listen/lib/listen/adapters/linux.rb +18 -7
- data/vendor/listen/lib/listen/adapters/windows.rb +7 -8
- data/vendor/listen/lib/listen/directory_record.rb +108 -48
- data/vendor/listen/lib/listen/listener.rb +28 -11
- data/vendor/listen/lib/listen/multi_listener.rb +6 -6
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +11 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +268 -41
- data/vendor/listen/spec/listen/listener_spec.rb +8 -4
- data/vendor/listen/spec/listen/multi_listener_spec.rb +9 -4
- data/vendor/listen/spec/support/adapter_helper.rb +178 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +24 -4
- data/vendor/listen/spec/support/listeners_helper.rb +11 -0
- metadata +11 -11
- data/lib/sass/plugin/listener.rb +0 -61
data/lib/sass/script/parser.rb
CHANGED
@@ -381,7 +381,9 @@ RUBY
|
|
381
381
|
|
382
382
|
other_args, other_keywords = assert_expr(type)
|
383
383
|
if keywords
|
384
|
-
if
|
384
|
+
if !other_args.empty?
|
385
|
+
raise SyntaxError.new("Positional arguments must come before keyword arguments")
|
386
|
+
elsif other_keywords[name.underscored_name]
|
385
387
|
raise SyntaxError.new("Keyword argument \"#{name.to_sass}\" passed more than once")
|
386
388
|
end
|
387
389
|
return other_args, keywords.merge(other_keywords)
|
@@ -453,7 +455,7 @@ RUBY
|
|
453
455
|
end
|
454
456
|
|
455
457
|
def literal
|
456
|
-
(t = try_tok(:color, :bool)) && (return t.value)
|
458
|
+
(t = try_tok(:color, :bool, :null)) && (return t.value)
|
457
459
|
end
|
458
460
|
|
459
461
|
# It would be possible to have unified #assert and #try methods,
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -721,11 +721,7 @@ module Sass
|
|
721
721
|
tok(SUBSTRINGMATCH)
|
722
722
|
@expected = "identifier or string"
|
723
723
|
ss
|
724
|
-
|
725
|
-
val = [val]
|
726
|
-
else
|
727
|
-
val = expr!(:interp_string)
|
728
|
-
end
|
724
|
+
val = interp_ident || expr!(:interp_string)
|
729
725
|
ss
|
730
726
|
end
|
731
727
|
tok(/\]/)
|
data/lib/sass/scss/rx.rb
CHANGED
@@ -130,7 +130,7 @@ module Sass
|
|
130
130
|
# about 50 characters. This mitigates the problem of exponential parsing
|
131
131
|
# time when a value has a long string of valid, parsable content followed
|
132
132
|
# by something invalid.
|
133
|
-
STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|[ \t](?!%)|#[a-f0-9]|[,%]|#{NUM}|\!important){
|
133
|
+
STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|[ \t](?!%)|#[a-f0-9]|[,%]|#{NUM}|\!important){1,50}([;}])/i
|
134
134
|
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){0,50}([{])/i
|
135
135
|
end
|
136
136
|
end
|
data/lib/sass/tree/media_node.rb
CHANGED
@@ -27,6 +27,9 @@ module Sass::Tree
|
|
27
27
|
# @see DirectiveNode#value
|
28
28
|
def value; raise NotImplementedError; end
|
29
29
|
|
30
|
+
# @see DirectiveNode#name
|
31
|
+
def name; '@media'; end
|
32
|
+
|
30
33
|
# @see DirectiveNode#resolved_value
|
31
34
|
def resolved_value
|
32
35
|
@resolved_value ||= "@media #{query.to_css}"
|
data/lib/sass/tree/prop_node.rb
CHANGED
@@ -92,15 +92,19 @@ module Sass::Tree
|
|
92
92
|
"#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
|
93
93
|
end
|
94
94
|
|
95
|
+
# A property node is invisible if its value is empty.
|
96
|
+
#
|
97
|
+
# @return [Boolean]
|
98
|
+
def invisible?
|
99
|
+
resolved_value.empty?
|
100
|
+
end
|
101
|
+
|
95
102
|
private
|
96
103
|
|
97
104
|
def check!
|
98
105
|
if @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
|
99
106
|
raise Sass::SyntaxError.new(
|
100
107
|
"Illegal property syntax: can't use #{@prop_syntax} syntax when :property_syntax => #{@options[:property_syntax].inspect} is set.")
|
101
|
-
elsif resolved_value.empty?
|
102
|
-
raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no value)." +
|
103
|
-
pseudo_class_selector_message)
|
104
108
|
end
|
105
109
|
end
|
106
110
|
|
@@ -33,7 +33,7 @@ module Sass::Tree::Visitors
|
|
33
33
|
# @return [Object] The return value of the `visit_*` method for this node.
|
34
34
|
def visit(node)
|
35
35
|
method = "visit_#{node_name node}"
|
36
|
-
if self.respond_to?(method)
|
36
|
+
if self.respond_to?(method, true)
|
37
37
|
self.send(method, node) {visit_children(node)}
|
38
38
|
else
|
39
39
|
visit_children(node)
|
@@ -2,13 +2,14 @@
|
|
2
2
|
class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
|
3
3
|
protected
|
4
4
|
|
5
|
+
def initialize
|
6
|
+
@parents = []
|
7
|
+
end
|
8
|
+
|
5
9
|
def visit(node)
|
6
|
-
if error =
|
7
|
-
|
8
|
-
|
9
|
-
(@real_parent && (
|
10
|
-
try_send("invalid_#{node_name @real_parent}_real_child?", @real_parent, node) ||
|
11
|
-
try_send("invalid_#{node_name node}_real_parent?", @real_parent, node)))
|
10
|
+
if error = @parent && (
|
11
|
+
try_send("invalid_#{node_name @parent}_child?", @parent, node) ||
|
12
|
+
try_send("invalid_#{node_name node}_parent?", @parent, node))
|
12
13
|
raise Sass::SyntaxError.new(error)
|
13
14
|
end
|
14
15
|
super
|
@@ -23,11 +24,11 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
|
|
23
24
|
def visit_children(parent)
|
24
25
|
old_parent = @parent
|
25
26
|
@parent = parent unless is_any_of?(parent, SCRIPT_NODES)
|
26
|
-
|
27
|
+
@parents.push parent
|
27
28
|
super
|
28
29
|
ensure
|
29
30
|
@parent = old_parent
|
30
|
-
@
|
31
|
+
@parents.pop
|
31
32
|
end
|
32
33
|
|
33
34
|
def visit_root(node)
|
@@ -68,7 +69,15 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
|
|
68
69
|
VALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
|
69
70
|
def invalid_extend_parent?(parent, child)
|
70
71
|
unless is_any_of?(parent, VALID_EXTEND_PARENTS)
|
71
|
-
"Extend directives may only be used within rules."
|
72
|
+
return "Extend directives may only be used within rules."
|
73
|
+
end
|
74
|
+
|
75
|
+
if directive = @parents.find {|p| p.is_a?(Sass::Tree::DirectiveNode)}
|
76
|
+
return <<ERR.rstrip
|
77
|
+
@extend may not be used within directives (e.g. #{directive.name}).
|
78
|
+
|
79
|
+
This will only work once @extend is supported natively in the browser.
|
80
|
+
ERR
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
@@ -86,12 +95,10 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
|
|
86
95
|
end
|
87
96
|
end
|
88
97
|
|
89
|
-
|
90
|
-
Sass::Tree::
|
91
|
-
Sass::Tree::EachNode, Sass::Tree::MixinDefNode, Sass::Tree::MixinNode
|
92
|
-
]
|
98
|
+
INVALID_IMPORT_PARENTS = CONTROL_NODES +
|
99
|
+
[Sass::Tree::MixinDefNode, Sass::Tree::MixinNode]
|
93
100
|
def invalid_import_parent?(parent, child)
|
94
|
-
|
101
|
+
unless (@parents.map {|p| p.class} & INVALID_IMPORT_PARENTS).empty?
|
95
102
|
return "Import directives may not be used within control directives or mixins."
|
96
103
|
end
|
97
104
|
return if parent.is_a?(Sass::Tree::RootNode)
|
@@ -106,10 +113,6 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
|
|
106
113
|
raise e
|
107
114
|
end
|
108
115
|
|
109
|
-
def invalid_import_real_parent?(parent, child)
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
116
|
def invalid_mixindef_parent?(parent, child)
|
114
117
|
"Mixins may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
|
115
118
|
end
|
@@ -198,7 +198,7 @@ END
|
|
198
198
|
elsif default
|
199
199
|
default.perform(env)
|
200
200
|
end)
|
201
|
-
raise Sass::SyntaxError.new("Mixin #{node.name} is missing
|
201
|
+
raise Sass::SyntaxError.new("Mixin #{node.name} is missing argument #{var.inspect}.") unless env.var(var.name)
|
202
202
|
env
|
203
203
|
end
|
204
204
|
environment.caller = Sass::Environment.new(@environment)
|
@@ -261,7 +261,8 @@ END
|
|
261
261
|
|
262
262
|
# Loads the new variable value into the environment.
|
263
263
|
def visit_variable(node)
|
264
|
-
|
264
|
+
var = @environment.var(node.name)
|
265
|
+
return [] if node.guarded && var && !var.null?
|
265
266
|
val = node.expr.perform(@environment)
|
266
267
|
@environment.set_var(node.name, val)
|
267
268
|
[]
|
@@ -122,6 +122,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
122
122
|
end
|
123
123
|
|
124
124
|
def visit_prop(node)
|
125
|
+
return if node.resolved_value.empty?
|
125
126
|
tab_str = ' ' * (@tabs + node.tabs)
|
126
127
|
if node.style == :compressed
|
127
128
|
"#{tab_str}#{node.resolved_name}:#{node.resolved_value}"
|
data/lib/sass/util.rb
CHANGED
@@ -256,6 +256,26 @@ module Sass
|
|
256
256
|
arr
|
257
257
|
end
|
258
258
|
|
259
|
+
# Asserts that `value` falls within `range` (inclusive), leaving
|
260
|
+
# room for slight floating-point errors.
|
261
|
+
#
|
262
|
+
# @param name [String] The name of the value. Used in the error message.
|
263
|
+
# @param range [Range] The allowed range of values.
|
264
|
+
# @param value [Numeric, Sass::Script::Number] The value to check.
|
265
|
+
# @param unit [String] The unit of the value. Used in error reporting.
|
266
|
+
# @return [Numeric] `value` adjusted to fall within range, if it
|
267
|
+
# was outside by a floating-point margin.
|
268
|
+
def check_range(name, range, value, unit='')
|
269
|
+
grace = (-0.00001..0.00001)
|
270
|
+
str = value.to_s
|
271
|
+
value = value.value if value.is_a?(Sass::Script::Number)
|
272
|
+
return value if range.include?(value)
|
273
|
+
return range.first if grace.include?(value - range.first)
|
274
|
+
return range.last if grace.include?(value - range.last)
|
275
|
+
raise ArgumentError.new(
|
276
|
+
"#{name} #{str} must be between #{range.first}#{unit} and #{range.last}#{unit}")
|
277
|
+
end
|
278
|
+
|
259
279
|
# Returns information about the caller of the previous method.
|
260
280
|
#
|
261
281
|
# @param entry [String] An entry in the `#caller` list, or a similarly formatted string
|
@@ -422,6 +442,14 @@ module Sass
|
|
422
442
|
RUBY_ENGINE == "ironruby"
|
423
443
|
end
|
424
444
|
|
445
|
+
# Like `Dir.glob`, but works with backslash-separated paths on Windows.
|
446
|
+
#
|
447
|
+
# @param path [String]
|
448
|
+
def glob(path)
|
449
|
+
path = path.gsub('\\', '/') if windows?
|
450
|
+
Dir.glob(path)
|
451
|
+
end
|
452
|
+
|
425
453
|
## Cross-Ruby-Version Compatibility
|
426
454
|
|
427
455
|
# Whether or not this is running under Ruby 1.8 or lower.
|
@@ -1525,6 +1525,39 @@ $foo: ();
|
|
1525
1525
|
SCSS
|
1526
1526
|
end
|
1527
1527
|
|
1528
|
+
def test_nested_if_statements
|
1529
|
+
assert_renders(<<SASS, <<SCSS)
|
1530
|
+
@if $foo
|
1531
|
+
one
|
1532
|
+
a: b
|
1533
|
+
@else
|
1534
|
+
@if $bar
|
1535
|
+
two
|
1536
|
+
a: b
|
1537
|
+
@else
|
1538
|
+
three
|
1539
|
+
a: b
|
1540
|
+
SASS
|
1541
|
+
@if $foo {
|
1542
|
+
one {
|
1543
|
+
a: b;
|
1544
|
+
}
|
1545
|
+
}
|
1546
|
+
@else {
|
1547
|
+
@if $bar {
|
1548
|
+
two {
|
1549
|
+
a: b;
|
1550
|
+
}
|
1551
|
+
}
|
1552
|
+
@else {
|
1553
|
+
three {
|
1554
|
+
a: b;
|
1555
|
+
}
|
1556
|
+
}
|
1557
|
+
}
|
1558
|
+
SCSS
|
1559
|
+
end
|
1560
|
+
|
1528
1561
|
private
|
1529
1562
|
|
1530
1563
|
def assert_sass_to_sass(sass, options = {})
|
data/test/sass/engine_test.rb
CHANGED
@@ -64,7 +64,9 @@ MSG
|
|
64
64
|
"@import templates/basic\n foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
|
65
65
|
"foo\n @import foo.css" => "CSS import directives may only be used at the root of a document.",
|
66
66
|
"@if true\n @import foo" => "Import directives may not be used within control directives or mixins.",
|
67
|
+
"@if true\n .foo\n @import foo" => "Import directives may not be used within control directives or mixins.",
|
67
68
|
"@mixin foo\n @import foo" => "Import directives may not be used within control directives or mixins.",
|
69
|
+
"@mixin foo\n .foo\n @import foo" => "Import directives may not be used within control directives or mixins.",
|
68
70
|
"@import foo;" => "Invalid @import: expected end of line, was \";\".",
|
69
71
|
'$foo: "bar" "baz" !' => %Q{Invalid CSS after ""bar" "baz" ": expected expression (e.g. 1px, bold), was "!"},
|
70
72
|
'$foo: "bar" "baz" $' => %Q{Invalid CSS after ""bar" "baz" ": expected expression (e.g. 1px, bold), was "$"}, #'
|
@@ -92,7 +94,7 @@ MSG
|
|
92
94
|
"=a($b: 1, $c)" => "Required argument $c must come before any optional arguments.",
|
93
95
|
"=a($b: 1)\n a: $b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
|
94
96
|
"=a($b: 1)\n a: $b\ndiv\n +a(1,$c: 3)" => "Mixin a doesn't have an argument named $c",
|
95
|
-
"=a($b)\n a: $b\ndiv\n +a" => "Mixin a is missing
|
97
|
+
"=a($b)\n a: $b\ndiv\n +a" => "Mixin a is missing argument $b.",
|
96
98
|
"@function foo()\n 1 + 2" => "Functions can only contain variable declarations and control directives.",
|
97
99
|
"@function foo()\n foo: bar" => "Functions can only contain variable declarations and control directives.",
|
98
100
|
"@function foo()\n foo: bar\n @return 3" => ["Functions can only contain variable declarations and control directives.", 2],
|
@@ -104,7 +106,7 @@ MSG
|
|
104
106
|
"@function foo()\n @return" => 'Invalid @return: expected expression.',
|
105
107
|
"@function foo()\n @return 1\n $var: val" => 'Illegal nesting: Nothing may be nested beneath return directives.',
|
106
108
|
"foo\n @function bar()\n @return 1" => ['Functions may only be defined at the root of a document.', 2],
|
107
|
-
"@function foo($a)\n @return 1\na\n b: foo()" => 'Function foo is missing
|
109
|
+
"@function foo($a)\n @return 1\na\n b: foo()" => 'Function foo is missing argument $a',
|
108
110
|
"@function foo()\n @return 1\na\n b: foo(2)" => 'Wrong number of arguments (1 for 0) for `foo\'',
|
109
111
|
"@function foo()\n @return 1\na\n b: foo($a: 1)" => "Function foo doesn't have an argument named $a",
|
110
112
|
"@function foo()\n @return 1\na\n b: foo($a: 1, $b: 2)" => "Function foo doesn't have the following arguments: $a, $b",
|
@@ -144,6 +146,8 @@ MSG
|
|
144
146
|
"$var: true\n@while $var\n @extend .bar\n $var: false" => ["Extend directives may only be used within rules.", 3],
|
145
147
|
"@for $i from 0 to 1\n @extend .bar" => ["Extend directives may only be used within rules.", 2],
|
146
148
|
"@mixin foo\n @extend .bar\n@include foo" => ["Extend directives may only be used within rules.", 2],
|
149
|
+
"@media screen\n .bar\n @extend .foo" => "@extend may not be used within directives (e.g. @media).\n\nThis will only work once @extend is supported natively in the browser.",
|
150
|
+
"@flooblehoof\n .bar\n @extend .foo" => "@extend may not be used within directives (e.g. @flooblehoof).\n\nThis will only work once @extend is supported natively in the browser.",
|
147
151
|
"foo\n &a\n b: c" => ["Invalid CSS after \"&\": expected \"{\", was \"a\"\n\n\"a\" may only be used at the beginning of a selector.", 2],
|
148
152
|
"foo\n &1\n b: c" => ["Invalid CSS after \"&\": expected \"{\", was \"1\"\n\n\"1\" may only be used at the beginning of a selector.", 2],
|
149
153
|
"foo %\n a: b" => ['Invalid CSS after "foo %": expected placeholder name, was ""', 1],
|
@@ -1011,7 +1015,7 @@ SASS
|
|
1011
1015
|
|
1012
1016
|
def test_debug_info_without_filename
|
1013
1017
|
assert_equal(<<CSS, Sass::Engine.new(<<SASS, :debug_info => true).render)
|
1014
|
-
@media -sass-debug-info{filename{
|
1018
|
+
@media -sass-debug-info{filename{}line{font-family:\\000031}}
|
1015
1019
|
foo {
|
1016
1020
|
a: b; }
|
1017
1021
|
CSS
|
@@ -1100,6 +1104,7 @@ SASS
|
|
1100
1104
|
def test_guarded_assign
|
1101
1105
|
assert_equal("foo {\n a: b; }\n", render(%Q{$foo: b\n$foo: c !default\nfoo\n a: $foo}))
|
1102
1106
|
assert_equal("foo {\n a: b; }\n", render(%Q{$foo: b !default\nfoo\n a: $foo}))
|
1107
|
+
assert_equal("foo {\n a: b; }\n", render(%Q{$foo: null\n$foo: b !default\nfoo\n a: $foo}))
|
1103
1108
|
end
|
1104
1109
|
|
1105
1110
|
def test_mixins
|
@@ -1185,6 +1190,35 @@ two
|
|
1185
1190
|
+foo(#fff, 2px)
|
1186
1191
|
three
|
1187
1192
|
+foo(#fff, 2px, 3px)
|
1193
|
+
SASS
|
1194
|
+
assert_equal(<<CSS, render(<<SASS))
|
1195
|
+
one {
|
1196
|
+
color: white;
|
1197
|
+
padding: 1px;
|
1198
|
+
margin: 4px; }
|
1199
|
+
|
1200
|
+
two {
|
1201
|
+
color: white;
|
1202
|
+
padding: 2px;
|
1203
|
+
margin: 5px; }
|
1204
|
+
|
1205
|
+
three {
|
1206
|
+
color: white;
|
1207
|
+
padding: 2px;
|
1208
|
+
margin: 3px; }
|
1209
|
+
CSS
|
1210
|
+
$a: 5px
|
1211
|
+
=foo($a, $b: 1px, $c: null)
|
1212
|
+
$c: 3px + $b !default
|
1213
|
+
color: $a
|
1214
|
+
padding: $b
|
1215
|
+
margin: $c
|
1216
|
+
one
|
1217
|
+
+foo(#fff)
|
1218
|
+
two
|
1219
|
+
+foo(#fff, 2px)
|
1220
|
+
three
|
1221
|
+
+foo(#fff, 2px, 3px)
|
1188
1222
|
SASS
|
1189
1223
|
end
|
1190
1224
|
|
@@ -1271,6 +1305,58 @@ bar
|
|
1271
1305
|
SASS
|
1272
1306
|
end
|
1273
1307
|
|
1308
|
+
def test_function_with_missing_argument
|
1309
|
+
render(<<SASS)
|
1310
|
+
@function plus($var1, $var2)
|
1311
|
+
@return $var1 + $var2
|
1312
|
+
|
1313
|
+
bar
|
1314
|
+
a: plus($var2: bar)
|
1315
|
+
SASS
|
1316
|
+
flunk("Expected exception")
|
1317
|
+
rescue Sass::SyntaxError => e
|
1318
|
+
assert_equal("Function plus is missing argument $var1", e.message)
|
1319
|
+
end
|
1320
|
+
|
1321
|
+
def test_function_with_extra_argument
|
1322
|
+
render(<<SASS)
|
1323
|
+
@function plus($var1, $var2)
|
1324
|
+
@return $var1 + $var2
|
1325
|
+
|
1326
|
+
bar
|
1327
|
+
a: plus($var1: foo, $var2: bar, $var3: baz)
|
1328
|
+
SASS
|
1329
|
+
flunk("Expected exception")
|
1330
|
+
rescue Sass::SyntaxError => e
|
1331
|
+
assert_equal("Function plus doesn't have an argument named $var3", e.message)
|
1332
|
+
end
|
1333
|
+
|
1334
|
+
def test_function_with_positional_and_keyword_argument
|
1335
|
+
render(<<SASS)
|
1336
|
+
@function plus($var1, $var2)
|
1337
|
+
@return $var1 + $var2
|
1338
|
+
|
1339
|
+
bar
|
1340
|
+
a: plus(foo, bar, $var2: baz)
|
1341
|
+
SASS
|
1342
|
+
flunk("Expected exception")
|
1343
|
+
rescue Sass::SyntaxError => e
|
1344
|
+
assert_equal("Function plus was passed argument $var2 both by position and by name", e.message)
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
def test_function_with_keyword_before_positional_argument
|
1348
|
+
render(<<SASS)
|
1349
|
+
@function plus($var1, $var2)
|
1350
|
+
@return $var1 + $var2
|
1351
|
+
|
1352
|
+
bar
|
1353
|
+
a: plus($var2: foo, bar)
|
1354
|
+
SASS
|
1355
|
+
flunk("Expected exception")
|
1356
|
+
rescue Sass::SyntaxError => e
|
1357
|
+
assert_equal("Positional arguments must come before keyword arguments", e.message)
|
1358
|
+
end
|
1359
|
+
|
1274
1360
|
def test_function_with_if
|
1275
1361
|
assert_equal(<<CSS, render(<<SASS))
|
1276
1362
|
bar {
|
@@ -1341,6 +1427,15 @@ SASS
|
|
1341
1427
|
def test_if_directive
|
1342
1428
|
assert_equal("a {\n b: 1; }\n", render(<<SASS))
|
1343
1429
|
$var: true
|
1430
|
+
a
|
1431
|
+
@if $var
|
1432
|
+
b: 1
|
1433
|
+
@if not $var
|
1434
|
+
b: 2
|
1435
|
+
SASS
|
1436
|
+
|
1437
|
+
assert_equal("a {\n b: 2; }\n", render(<<SASS))
|
1438
|
+
$var: null
|
1344
1439
|
a
|
1345
1440
|
@if $var
|
1346
1441
|
b: 1
|
@@ -1743,6 +1838,26 @@ This selector doesn't have any properties and will not be rendered.
|
|
1743
1838
|
END
|
1744
1839
|
end
|
1745
1840
|
|
1841
|
+
def test_nonprinting_empty_property
|
1842
|
+
assert_equal(<<CSS, render(<<SASS))
|
1843
|
+
a {
|
1844
|
+
c: "";
|
1845
|
+
e: f; }
|
1846
|
+
CSS
|
1847
|
+
$null-value: null
|
1848
|
+
$empty-string: ''
|
1849
|
+
$empty-list: (null)
|
1850
|
+
a
|
1851
|
+
b: $null-value
|
1852
|
+
c: $empty-string
|
1853
|
+
d: $empty-list
|
1854
|
+
e: f
|
1855
|
+
|
1856
|
+
g
|
1857
|
+
h: null
|
1858
|
+
SASS
|
1859
|
+
end
|
1860
|
+
|
1746
1861
|
def test_root_level_pseudo_class_with_new_properties
|
1747
1862
|
assert_equal(<<CSS, render(<<SASS, :property_syntax => :new))
|
1748
1863
|
:focus {
|