sass 3.2.0.alpha.104 → 3.2.0.alpha.236
Sign up to get free protection for your applications and to get access to all the features.
- 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 {
|