sass 3.3.0.alpha.378 → 3.3.0.alpha.380

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 CHANGED
@@ -1 +1 @@
1
- af904635d4da0719e029b715cd2acb9fa6446b0a
1
+ 898bec6bfb7fa4ce8a1ca8e2ff210387c7f98f0e
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0.alpha.378
1
+ 3.3.0.alpha.380
@@ -1 +1 @@
1
- 11 October 2013 21:25:34 GMT
1
+ 11 October 2013 22:11:57 GMT
@@ -437,6 +437,7 @@ RUBY
437
437
 
438
438
  return [args, keywords] unless e
439
439
 
440
+ splat = nil
440
441
  loop do
441
442
  if @lexer.peek && @lexer.peek.type == :colon
442
443
  name = e
@@ -450,21 +451,19 @@ RUBY
450
451
 
451
452
  keywords[name.name] = value
452
453
  else
453
- unless keywords.empty?
454
+ if try_tok(:splat)
455
+ return args, keywords, splat, e if splat
456
+ splat, e = e, nil
457
+ elsif splat
458
+ raise SyntaxError.new("Only keyword arguments may follow variable arguments (...).")
459
+ elsif !keywords.empty?
454
460
  raise SyntaxError.new("Positional arguments must come before keyword arguments.")
455
461
  end
456
462
 
457
- if try_tok(:splat)
458
- splat = e
459
- return args, keywords, splat unless try_tok(:comma)
460
- kwarg_splat = assert_expr(subexpr, description)
461
- assert_tok(:splat)
462
- return args, keywords, splat, kwarg_splat
463
- end
464
- args << e
463
+ args << e if e
465
464
  end
466
465
 
467
- return args, keywords unless try_tok(:comma)
466
+ return args, keywords, splat unless try_tok(:comma)
468
467
  e = assert_expr(subexpr, description)
469
468
  end
470
469
  end
@@ -76,17 +76,18 @@ module Sass::Script::Tree
76
76
  sass
77
77
  end
78
78
 
79
- args = @args.map(&arg_to_sass).join(', ')
79
+ args = @args.map(&arg_to_sass)
80
80
  keywords = Sass::Util.hash_to_a(@keywords.as_stored).
81
- map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}.join(', ')
81
+ map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
82
+
82
83
  # rubocop:disable RedundantSelf
83
84
  if self.splat
84
- splat = args.empty? && keywords.empty? ? "" : ", "
85
- splat = "#{splat}#{arg_to_sass[self.splat]}..."
86
- splat = "#{splat}, #{arg_to_sass[kwarg_splat]}..." if kwarg_splat
85
+ splat = "#{arg_to_sass[self.splat]}..."
86
+ kwarg_splat = "#{arg_to_sass[self.kwarg_splat]}..." if self.kwarg_splat
87
87
  end
88
88
  # rubocop:enable RedundantSelf
89
- arglist = "#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat}"
89
+
90
+ arglist = [args, splat, keywords, kwarg_splat].flatten.compact.join(', ')
90
91
  "#{dasherize(name, opts)}(#{arglist})"
91
92
  end
92
93
 
@@ -121,16 +122,16 @@ module Sass::Script::Tree
121
122
  def _perform(environment)
122
123
  args = Sass::Util.enum_with_index(@args).
123
124
  map {|a, i| perform_arg(a, environment, signature && signature.args[i])}
124
- splat = Sass::Tree::Visitors::Perform.perform_splat(@splat, @kwarg_splat, environment)
125
125
  keywords = Sass::Util.map_hash(@keywords) do |k, v|
126
126
  [k, perform_arg(v, environment, k.tr('-', '_'))]
127
127
  end
128
+ splat = Sass::Tree::Visitors::Perform.perform_splat(
129
+ @splat, keywords, @kwarg_splat, environment)
128
130
  if (fn = environment.function(@name))
129
- return perform_sass_fn(fn, args, keywords, splat, environment)
131
+ return perform_sass_fn(fn, args, splat, environment)
130
132
  end
131
133
 
132
- ruby_name = @name.tr('-', '_')
133
- args = construct_ruby_args(ruby_name, args, keywords, splat, environment)
134
+ args = construct_ruby_args(ruby_name, args, splat, environment)
134
135
 
135
136
  if Sass::Script::Functions.callable?(ruby_name)
136
137
  local_environment = Sass::Environment.new(environment.global_env, environment.options)
@@ -141,54 +142,7 @@ module Sass::Script::Tree
141
142
  opts(to_literal(args))
142
143
  end
143
144
  rescue ArgumentError => e
144
- message = e.message
145
-
146
- # If this is a legitimate Ruby-raised argument error, re-raise it.
147
- # Otherwise, it's an error in the user's stylesheet, so wrap it.
148
- if Sass::Util.rbx?
149
- # Rubinius has a different error report string than vanilla Ruby. It
150
- # also doesn't put the actual method for which the argument error was
151
- # thrown in the backtrace, nor does it include `send`, so we look for
152
- # `_perform`.
153
- if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
154
- error_name, given, expected = $1, $2, $3
155
- raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
156
- message = "wrong number of arguments (#{given} for #{expected})"
157
- end
158
- elsif Sass::Util.jruby?
159
- if Sass::Util.jruby1_6?
160
- should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
161
- # The one case where JRuby does include the Ruby name of the function
162
- # is manually-thrown ArgumentErrors, which are indistinguishable from
163
- # legitimate ArgumentErrors. We treat both of these as
164
- # Sass::SyntaxErrors even though it can hide Ruby errors.
165
- e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
166
- else
167
- should_maybe_raise =
168
- e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
169
- given, expected = $1, $2
170
- end
171
-
172
- if should_maybe_raise
173
- # JRuby 1.7 includes __send__ before send and _perform.
174
- trace = e.backtrace.dup
175
- raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
176
-
177
- # JRuby (as of 1.7.2) doesn't put the actual method
178
- # for which the argument error was thrown in the backtrace, so we
179
- # detect whether our send threw an argument error.
180
- if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
181
- raise e
182
- elsif !Sass::Util.jruby1_6?
183
- # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
184
- message = "wrong number of arguments (#{given} for #{expected})"
185
- end
186
- end
187
- elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
188
- e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
189
- raise e
190
- end
191
- raise Sass::SyntaxError.new("#{message} for `#{name}'")
145
+ reformat_argument_error(e)
192
146
  end
193
147
 
194
148
  # Compass historically overrode this before it changed name to {Funcall#to_value}.
@@ -206,6 +160,10 @@ module Sass::Script::Tree
206
160
 
207
161
  private
208
162
 
163
+ def ruby_name
164
+ @ruby_name ||= @name.tr('-', '_')
165
+ end
166
+
209
167
  def perform_arg(argument, environment, name)
210
168
  return argument if signature && signature.delayed_args.include?(name)
211
169
  argument.perform(environment)
@@ -215,15 +173,14 @@ module Sass::Script::Tree
215
173
  @signature ||= Sass::Script::Functions.signature(name.to_sym, @args.size, @keywords.size)
216
174
  end
217
175
 
218
- def construct_ruby_args(name, args, keywords, splat, environment)
176
+ def construct_ruby_args(name, args, splat, environment)
219
177
  args += splat.to_a if splat
220
178
 
221
- # If variable arguments were passed, there won't be any explicit keywords.
222
- if splat && !splat.keywords.empty?
223
- old_keywords_accessed = splat.keywords_accessed
224
- keywords = splat.keywords
225
- splat.keywords_accessed = old_keywords_accessed
226
- end
179
+ # All keywords are contained in splat.keywords for consistency,
180
+ # even if there were no splats passed in.
181
+ old_keywords_accessed = splat.keywords_accessed
182
+ keywords = splat.keywords
183
+ splat.keywords_accessed = old_keywords_accessed
227
184
 
228
185
  unless (signature = Sass::Script::Functions.signature(name.to_sym, args.size, keywords.size))
229
186
  return args if keywords.empty?
@@ -267,8 +224,8 @@ module Sass::Script::Tree
267
224
  args
268
225
  end
269
226
 
270
- def perform_sass_fn(function, args, keywords, splat, environment)
271
- Sass::Tree::Visitors::Perform.perform_arguments(function, args, keywords, splat) do |env|
227
+ def perform_sass_fn(function, args, splat, environment)
228
+ Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat) do |env|
272
229
  env.caller = Sass::Environment.new(environment)
273
230
 
274
231
  val = catch :_sass_return do
@@ -278,5 +235,56 @@ module Sass::Script::Tree
278
235
  val
279
236
  end
280
237
  end
238
+
239
+ def reformat_argument_error(e)
240
+ message = e.message
241
+
242
+ # If this is a legitimate Ruby-raised argument error, re-raise it.
243
+ # Otherwise, it's an error in the user's stylesheet, so wrap it.
244
+ if Sass::Util.rbx?
245
+ # Rubinius has a different error report string than vanilla Ruby. It
246
+ # also doesn't put the actual method for which the argument error was
247
+ # thrown in the backtrace, nor does it include `send`, so we look for
248
+ # `_perform`.
249
+ if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
250
+ error_name, given, expected = $1, $2, $3
251
+ raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
252
+ message = "wrong number of arguments (#{given} for #{expected})"
253
+ end
254
+ elsif Sass::Util.jruby?
255
+ if Sass::Util.jruby1_6?
256
+ should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
257
+ # The one case where JRuby does include the Ruby name of the function
258
+ # is manually-thrown ArgumentErrors, which are indistinguishable from
259
+ # legitimate ArgumentErrors. We treat both of these as
260
+ # Sass::SyntaxErrors even though it can hide Ruby errors.
261
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
262
+ else
263
+ should_maybe_raise =
264
+ e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
265
+ given, expected = $1, $2
266
+ end
267
+
268
+ if should_maybe_raise
269
+ # JRuby 1.7 includes __send__ before send and _perform.
270
+ trace = e.backtrace.dup
271
+ raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
272
+
273
+ # JRuby (as of 1.7.2) doesn't put the actual method
274
+ # for which the argument error was thrown in the backtrace, so we
275
+ # detect whether our send threw an argument error.
276
+ if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
277
+ raise e
278
+ elsif !Sass::Util.jruby1_6?
279
+ # JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
280
+ message = "wrong number of arguments (#{given} for #{expected})"
281
+ end
282
+ end
283
+ elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
284
+ e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
285
+ raise e
286
+ end
287
+ raise Sass::SyntaxError.new("#{message} for `#{name}'")
288
+ end
281
289
  end
282
290
  end
@@ -206,15 +206,16 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
206
206
  end
207
207
 
208
208
  unless node.args.empty? && node.keywords.empty? && node.splat.nil?
209
- args = node.args.map(&arg_to_sass).join(", ")
209
+ args = node.args.map(&arg_to_sass)
210
210
  keywords = Sass::Util.hash_to_a(node.keywords).
211
- map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}.join(', ')
211
+ map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}
212
+
212
213
  if node.splat
213
- splat = args.empty? && keywords.empty? ? "" : ", "
214
- splat = "#{splat}#{arg_to_sass[node.splat]}..."
215
- splat = "#{splat}, #{node.kwarg_splat.inspect}..." if node.kwarg_splat
214
+ splat = "#{arg_to_sass[node.splat]}..."
215
+ kwarg_splat = "#{arg_to_sass[node.kwarg_splat]}..." if node.kwarg_splat
216
216
  end
217
- arglist = "(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
217
+
218
+ arglist = "(#{[args, splat, keywords, kwarg_splat].flatten.compact.join(', ')})"
218
219
  end
219
220
  "#{tab_str}#{@format == :sass ? '+' : '@include '}" +
220
221
  "#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
@@ -11,16 +11,15 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
11
11
  # @api private
12
12
  # @comment
13
13
  # rubocop:disable MethodLength
14
- def perform_arguments(callable, args, keywords, splat)
14
+ def perform_arguments(callable, args, splat)
15
15
  desc = "#{callable.type.capitalize} #{callable.name}"
16
16
  downcase_desc = "#{callable.type} #{callable.name}"
17
17
 
18
- # If variable arguments were passed, there won't be any explicit keywords.
19
- if splat && !splat.keywords.empty?
20
- old_keywords_accessed = splat.keywords_accessed
21
- keywords = splat.keywords
22
- splat.keywords_accessed = old_keywords_accessed
23
- end
18
+ # All keywords are contained in splat.keywords for consistency,
19
+ # even if there were no splats passed in.
20
+ old_keywords_accessed = splat.keywords_accessed
21
+ keywords = splat.keywords
22
+ splat.keywords_accessed = old_keywords_accessed
24
23
 
25
24
  begin
26
25
  unless keywords.empty?
@@ -99,33 +98,34 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
99
98
 
100
99
  # @api private
101
100
  # @return [Sass::Script::Value::ArgList]
102
- def perform_splat(splat, kwarg_splat, environment)
103
- return unless splat
104
- splat = splat.perform(environment)
105
- unless kwarg_splat
106
- return splat if splat.is_a?(Sass::Script::Value::ArgList)
107
- if splat.is_a?(Sass::Script::Value::Map)
108
- args = []
101
+ def perform_splat(splat, performed_keywords, kwarg_splat, environment)
102
+ args, kwargs, separator = [], Sass::Util.ordered_hash, :comma
103
+
104
+ if splat
105
+ splat = splat.perform(environment)
106
+ separator = splat.separator || separator
107
+ if splat.is_a?(Sass::Script::Value::ArgList)
108
+ args = splat.to_a
109
+ kwargs = splat.keywords
110
+ elsif splat.is_a?(Sass::Script::Value::Map)
109
111
  kwargs = arg_hash(splat)
110
112
  else
111
113
  args = splat.to_a
112
- kwargs = {}
113
114
  end
114
- return Sass::Script::Value::ArgList.new(args, kwargs, splat.separator || :comma)
115
115
  end
116
116
 
117
- kwarg_splat = kwarg_splat.perform(environment)
118
- unless kwarg_splat.is_a?(Sass::Script::Value::Map)
119
- raise Sass::SyntaxError.new("Variable keyword arguments must be a map " +
120
- "(was #{kwarg_splat.inspect}).")
121
- end
117
+ kwargs = kwargs.merge(performed_keywords)
122
118
 
123
- if splat.is_a?(Sass::Script::Value::ArgList)
124
- return Sass::Script::Value::ArgList.new(
125
- splat.value, splat.keywords.merge(arg_hash(kwarg_splat)), splat.separator)
126
- else
127
- return Sass::Script::Value::ArgList.new(splat.to_a, arg_hash(kwarg_splat), splat.separator)
119
+ if kwarg_splat
120
+ kwarg_splat = kwarg_splat.perform(environment)
121
+ unless kwarg_splat.is_a?(Sass::Script::Value::Map)
122
+ raise Sass::SyntaxError.new("Variable keyword arguments must be a map " +
123
+ "(was #{kwarg_splat.inspect}).")
124
+ end
125
+ kwargs = kwargs.merge(arg_hash(kwarg_splat))
128
126
  end
127
+
128
+ Sass::Script::Value::ArgList.new(args, kwargs, separator)
129
129
  end
130
130
 
131
131
  private
@@ -326,9 +326,9 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
326
326
 
327
327
  args = node.args.map {|a| a.perform(@environment)}
328
328
  keywords = Sass::Util.map_hash(node.keywords) {|k, v| [k, v.perform(@environment)]}
329
- splat = self.class.perform_splat(node.splat, node.kwarg_splat, @environment)
329
+ splat = self.class.perform_splat(node.splat, keywords, node.kwarg_splat, @environment)
330
330
 
331
- self.class.perform_arguments(mixin, args, keywords, splat) do |env|
331
+ self.class.perform_arguments(mixin, args, splat) do |env|
332
332
  env.caller = Sass::Environment.new(@environment)
333
333
  env.content = [node.children, @environment] if node.has_children
334
334
 
@@ -1629,6 +1629,7 @@ SCSS
1629
1629
 
1630
1630
  .foo
1631
1631
  +foo($list..., $map...)
1632
+ +foo(pos, $list..., $kwd: val, $map...)
1632
1633
  SASS
1633
1634
  @mixin foo($a: b, $c: d) {
1634
1635
  a: $a;
@@ -1637,6 +1638,7 @@ SASS
1637
1638
 
1638
1639
  .foo {
1639
1640
  @include foo($list..., $map...);
1641
+ @include foo(pos, $list..., $kwd: val, $map...);
1640
1642
  }
1641
1643
  SCSS
1642
1644
  end
@@ -1675,6 +1677,7 @@ SCSS
1675
1677
 
1676
1678
  .foo
1677
1679
  a: foo($list..., $map...)
1680
+ b: foo(pos, $list..., $kwd: val, $map...)
1678
1681
  SASS
1679
1682
  @function foo($a: b, $c: d) {
1680
1683
  @return foo;
@@ -1682,6 +1685,7 @@ SASS
1682
1685
 
1683
1686
  .foo {
1684
1687
  a: foo($list..., $map...);
1688
+ b: foo(pos, $list..., $kwd: val, $map...);
1685
1689
  }
1686
1690
  SCSS
1687
1691
  end
@@ -1074,6 +1074,108 @@ CSS
1074
1074
  SCSS
1075
1075
  end
1076
1076
 
1077
+ def test_mixin_splat_after_keyword_args
1078
+ assert_equal <<CSS, render(<<SCSS)
1079
+ .foo {
1080
+ a: 1;
1081
+ b: 2;
1082
+ c: 3; }
1083
+ CSS
1084
+ @mixin foo($a, $b, $c) {
1085
+ a: 1;
1086
+ b: 2;
1087
+ c: 3;
1088
+ }
1089
+
1090
+ .foo {
1091
+ @include foo(1, $c: 3, 2...);
1092
+ }
1093
+ SCSS
1094
+ end
1095
+
1096
+ def test_mixin_keyword_args_after_splat
1097
+ assert_equal <<CSS, render(<<SCSS)
1098
+ .foo {
1099
+ a: 1;
1100
+ b: 2;
1101
+ c: 3; }
1102
+ CSS
1103
+ @mixin foo($a, $b, $c) {
1104
+ a: 1;
1105
+ b: 2;
1106
+ c: 3;
1107
+ }
1108
+
1109
+ .foo {
1110
+ @include foo(1, 2..., $c: 3);
1111
+ }
1112
+ SCSS
1113
+ end
1114
+
1115
+ def test_mixin_keyword_splat_after_keyword_args
1116
+ assert_equal <<CSS, render(<<SCSS)
1117
+ .foo {
1118
+ a: 1;
1119
+ b: 2;
1120
+ c: 3; }
1121
+ CSS
1122
+ @mixin foo($a, $b, $c) {
1123
+ a: 1;
1124
+ b: 2;
1125
+ c: 3;
1126
+ }
1127
+
1128
+ .foo {
1129
+ @include foo(1, $b: 2, (c: 3)...);
1130
+ }
1131
+ SCSS
1132
+ end
1133
+
1134
+ def test_mixin_triple_keyword_splat_merge
1135
+ assert_equal <<CSS, render(<<SCSS)
1136
+ .foo {
1137
+ foo: 1;
1138
+ bar: 2;
1139
+ kwarg: 3;
1140
+ a: 3;
1141
+ b: 2;
1142
+ c: 3; }
1143
+ CSS
1144
+ @mixin foo($foo, $bar, $kwarg, $a, $b, $c) {
1145
+ foo: $foo;
1146
+ bar: $bar;
1147
+ kwarg: $kwarg;
1148
+ a: $a;
1149
+ b: $b;
1150
+ c: $c;
1151
+ }
1152
+
1153
+ @mixin bar($args...) {
1154
+ @include foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1155
+ }
1156
+
1157
+ .foo {
1158
+ @include bar($foo: 1, $a: 1, $b: 1, $c: 1);
1159
+ }
1160
+ SCSS
1161
+ end
1162
+
1163
+ def test_mixin_conflicting_splat_after_keyword_args
1164
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1165
+ Mixin foo was passed argument $b both by position and by name.
1166
+ MESSAGE
1167
+ @mixin foo($a, $b, $c) {
1168
+ a: 1;
1169
+ b: 2;
1170
+ c: 3;
1171
+ }
1172
+
1173
+ .foo {
1174
+ @include foo(1, $b: 2, 3...);
1175
+ }
1176
+ SCSS
1177
+ end
1178
+
1077
1179
  def test_mixin_keyword_splat_must_have_string_keys
1078
1180
  assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1079
1181
  Variable keyword argument map must have string keys.
@@ -1087,6 +1189,22 @@ MESSAGE
1087
1189
  SCSS
1088
1190
  end
1089
1191
 
1192
+ def test_mixin_positional_arg_after_splat
1193
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1194
+ Only keyword arguments may follow variable arguments (...).
1195
+ MESSAGE
1196
+ @mixin foo($a, $b, $c) {
1197
+ a: 1;
1198
+ b: 2;
1199
+ c: 3;
1200
+ }
1201
+
1202
+ .foo {
1203
+ @include foo(1, 2..., 3);
1204
+ }
1205
+ SCSS
1206
+ end
1207
+
1090
1208
  def test_mixin_var_args_with_keyword
1091
1209
  assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1092
1210
  @mixin foo($a, $b...) {
@@ -1397,6 +1515,98 @@ CSS
1397
1515
  SCSS
1398
1516
  end
1399
1517
 
1518
+ def test_function_splat_after_keyword_args
1519
+ assert_equal <<CSS, render(<<SCSS)
1520
+ .foo {
1521
+ val: "a: 1, b: 2, c: 3"; }
1522
+ CSS
1523
+ @function foo($a, $b, $c) {
1524
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1525
+ }
1526
+
1527
+ .foo {
1528
+ val: foo(1, $c: 3, 2...);
1529
+ }
1530
+ SCSS
1531
+ end
1532
+
1533
+ def test_function_keyword_args_after_splat
1534
+ assert_equal <<CSS, render(<<SCSS)
1535
+ .foo {
1536
+ val: "a: 1, b: 2, c: 3"; }
1537
+ CSS
1538
+ @function foo($a, $b, $c) {
1539
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1540
+ }
1541
+
1542
+ .foo {
1543
+ val: foo(1, 2..., $c: 3);
1544
+ }
1545
+ SCSS
1546
+ end
1547
+
1548
+ def test_function_keyword_splat_after_keyword_args
1549
+ assert_equal <<CSS, render(<<SCSS)
1550
+ .foo {
1551
+ val: "a: 1, b: 2, c: 3"; }
1552
+ CSS
1553
+ @function foo($a, $b, $c) {
1554
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1555
+ }
1556
+
1557
+ .foo {
1558
+ val: foo(1, $b: 2, (c: 3)...);
1559
+ }
1560
+ SCSS
1561
+ end
1562
+
1563
+ def test_function_triple_keyword_splat_merge
1564
+ assert_equal <<CSS, render(<<SCSS)
1565
+ .foo {
1566
+ val: "foo: 1, bar: 2, kwarg: 3, a: 3, b: 2, c: 3"; }
1567
+ CSS
1568
+ @function foo($foo, $bar, $kwarg, $a, $b, $c) {
1569
+ @return "foo: \#{$foo}, bar: \#{$bar}, kwarg: \#{$kwarg}, a: \#{$a}, b: \#{$b}, c: \#{$c}";
1570
+ }
1571
+
1572
+ @function bar($args...) {
1573
+ @return foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1574
+ }
1575
+
1576
+ .foo {
1577
+ val: bar($foo: 1, $a: 1, $b: 1, $c: 1);
1578
+ }
1579
+ SCSS
1580
+ end
1581
+
1582
+ def test_function_conflicting_splat_after_keyword_args
1583
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1584
+ Function foo was passed argument $b both by position and by name.
1585
+ MESSAGE
1586
+ @function foo($a, $b, $c) {
1587
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1588
+ }
1589
+
1590
+ .foo {
1591
+ val: foo(1, $b: 2, 3...);
1592
+ }
1593
+ SCSS
1594
+ end
1595
+
1596
+ def test_function_positional_arg_after_splat
1597
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1598
+ Only keyword arguments may follow variable arguments (...).
1599
+ MESSAGE
1600
+ @function foo($a, $b, $c) {
1601
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1602
+ }
1603
+
1604
+ .foo {
1605
+ val: foo(1, 2..., 3);
1606
+ }
1607
+ SCSS
1608
+ end
1609
+
1400
1610
  def test_function_var_args_with_keyword
1401
1611
  assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1402
1612
  @function foo($a, $b...) {
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592302585
4
+ hash: 592302581
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 3
9
9
  - 0
10
10
  - alpha
11
- - 378
12
- version: 3.3.0.alpha.378
11
+ - 380
12
+ version: 3.3.0.alpha.380
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum