haml 3.1.0.alpha.19 → 3.1.0.alpha.22

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.

Files changed (33) hide show
  1. data/EDGE_GEM_VERSION +1 -1
  2. data/VERSION +1 -1
  3. data/lib/haml/precompiler.rb +1 -0
  4. data/lib/haml/template/plugin.rb +16 -6
  5. data/vendor/sass/doc-src/SASS_CHANGELOG.md +41 -0
  6. data/vendor/sass/doc-src/SASS_REFERENCE.md +37 -6
  7. data/vendor/sass/lib/sass.rb +7 -3
  8. data/vendor/sass/lib/sass/engine.rb +4 -4
  9. data/vendor/sass/lib/sass/environment.rb +24 -15
  10. data/vendor/sass/lib/sass/less.rb +31 -12
  11. data/vendor/sass/lib/sass/plugin/staleness_checker.rb +1 -1
  12. data/vendor/sass/lib/sass/script/funcall.rb +51 -9
  13. data/vendor/sass/lib/sass/script/functions.rb +189 -57
  14. data/vendor/sass/lib/sass/script/node.rb +7 -1
  15. data/vendor/sass/lib/sass/script/number.rb +21 -15
  16. data/vendor/sass/lib/sass/script/operation.rb +10 -5
  17. data/vendor/sass/lib/sass/script/parser.rb +61 -17
  18. data/vendor/sass/lib/sass/script/string.rb +2 -3
  19. data/vendor/sass/lib/sass/script/variable.rb +6 -0
  20. data/vendor/sass/lib/sass/scss/parser.rb +8 -5
  21. data/vendor/sass/lib/sass/selector/sequence.rb +2 -2
  22. data/vendor/sass/lib/sass/tree/mixin_node.rb +25 -5
  23. data/vendor/sass/lib/sass/tree/node.rb +2 -2
  24. data/vendor/sass/lib/sass/tree/prop_node.rb +9 -6
  25. data/vendor/sass/lib/sass/tree/rule_node.rb +9 -8
  26. data/vendor/sass/lib/sass/util.rb +5 -3
  27. data/vendor/sass/test/sass/conversion_test.rb +14 -0
  28. data/vendor/sass/test/sass/engine_test.rb +85 -0
  29. data/vendor/sass/test/sass/functions_test.rb +89 -0
  30. data/vendor/sass/test/sass/less_conversion_test.rb +24 -3
  31. data/vendor/sass/test/sass/script_conversion_test.rb +65 -0
  32. data/vendor/sass/test/sass/scss/scss_test.rb +63 -0
  33. metadata +2 -2
@@ -88,8 +88,12 @@ module Sass::Tree
88
88
  # @param tabs [Fixnum] The level of indentation for the CSS
89
89
  # @return [String] The resulting CSS
90
90
  def _to_s(tabs)
91
- to_return = ' ' * (tabs - 1 + self.tabs) + resolved_name + ":" +
92
- (style == :compressed ? '' : ' ') + resolved_value + (style == :compressed ? "" : ";")
91
+ tab_str = ' ' * (tabs - 1 + self.tabs)
92
+ if style == :compressed
93
+ "#{tab_str}#{resolved_name}:#{resolved_value}"
94
+ else
95
+ "#{tab_str}#{resolved_name}: #{resolved_value};"
96
+ end
93
97
  end
94
98
 
95
99
  # Converts nested properties into flat properties.
@@ -154,10 +158,9 @@ module Sass::Tree
154
158
  private
155
159
 
156
160
  def check!
157
- if @options[:property_syntax] == :old && @prop_syntax == :new
158
- raise Sass::SyntaxError.new("Illegal property syntax: can't use new syntax when :property_syntax => :old is set.")
159
- elsif @options[:property_syntax] == :new && @prop_syntax == :old
160
- raise Sass::SyntaxError.new("Illegal property syntax: can't use old syntax when :property_syntax => :new is set.")
161
+ if @options[:property_syntax] && @options[:property_syntax] != @prop_syntax
162
+ raise Sass::SyntaxError.new(
163
+ "Illegal property syntax: can't use #{@prop_syntax} syntax when :property_syntax => #{@options[:property_syntax].inspect} is set.")
161
164
  elsif resolved_value.empty?
162
165
  raise Sass::SyntaxError.new("Invalid property: #{declaration.dump} (no value)." +
163
166
  pseudo_class_selector_message)
@@ -121,17 +121,18 @@ module Sass::Tree
121
121
  # @param tabs [Fixnum] The level of indentation for the CSS
122
122
  # @return [String] The resulting CSS
123
123
  def _to_s(tabs)
124
+ output_style = style
124
125
  tabs = tabs + self.tabs
125
126
 
126
- rule_separator = style == :compressed ? ',' : ', '
127
+ rule_separator = output_style == :compressed ? ',' : ', '
127
128
  line_separator =
128
- case style
129
+ case output_style
129
130
  when :nested, :expanded; "\n"
130
131
  when :compressed; ""
131
132
  else; " "
132
133
  end
133
134
  rule_indent = ' ' * (tabs - 1)
134
- per_rule_indent, total_indent = [:nested, :expanded].include?(style) ? [rule_indent, ''] : ['', rule_indent]
135
+ per_rule_indent, total_indent = [:nested, :expanded].include?(output_style) ? [rule_indent, ''] : ['', rule_indent]
135
136
 
136
137
  total_rule = total_indent + resolved_rules.members.
137
138
  map {|seq| seq.to_a.join.gsub(/([^,])\n/m, style == :compressed ? '\1 ' : "\\1\n")}.
@@ -142,7 +143,7 @@ module Sass::Tree
142
143
  to_return = ''
143
144
  old_spaces = ' ' * (tabs - 1)
144
145
  spaces = ' ' * tabs
145
- if style != :compressed
146
+ if output_style != :compressed
146
147
  if @options[:debug_info]
147
148
  to_return << debug_info_rule.to_s(tabs) << "\n"
148
149
  elsif @options[:line_comments]
@@ -165,15 +166,15 @@ module Sass::Tree
165
166
  end
166
167
  end
167
168
 
168
- if style == :compact
169
+ if output_style == :compact
169
170
  properties = children.map { |a| a.to_s(1) }.join(' ')
170
171
  to_return << "#{total_rule} { #{properties} }#{"\n" if group_end}"
171
- elsif style == :compressed
172
+ elsif output_style == :compressed
172
173
  properties = children.map { |a| a.to_s(1) }.join(';')
173
174
  to_return << "#{total_rule}{#{properties}}"
174
175
  else
175
176
  properties = children.map { |a| a.to_s(tabs + 1) }.join("\n")
176
- end_props = (style == :expanded ? "\n" + old_spaces : ' ')
177
+ end_props = (output_style == :expanded ? "\n" + old_spaces : ' ')
177
178
  to_return << "#{total_rule} {\n#{properties}#{end_props}}#{"\n" if group_end}"
178
179
  end
179
180
 
@@ -199,7 +200,7 @@ module Sass::Tree
199
200
  # or nil if the parent isn't a {RuleNode}
200
201
  def _cssize(extends, parent)
201
202
  node = super
202
- rules = node.children.select {|c| c.is_a?(RuleNode)}
203
+ rules = node.children.grep(RuleNode)
203
204
  props = node.children.reject {|c| c.is_a?(RuleNode) || c.invisible?}
204
205
 
205
206
  unless props.empty?
@@ -121,10 +121,12 @@ module Sass
121
121
  # @example
122
122
  # merge_adjacent_strings([1, "foo", "bar", 2, "baz"])
123
123
  # #=> [1, "foobar", 2, "baz"]
124
- # @param enum [Enumerable]
124
+ # @param arr [Array]
125
125
  # @return [Array] The enumerable with strings merged
126
- def merge_adjacent_strings(enum)
127
- enum.inject([]) do |a, e|
126
+ def merge_adjacent_strings(arr)
127
+ # Optimize for the common case of one element
128
+ return arr if arr.size < 2
129
+ arr.inject([]) do |a, e|
128
130
  if e.is_a?(String)
129
131
  if a.last.is_a?(String)
130
132
  a.last << e
@@ -859,6 +859,20 @@ foo {
859
859
  SCSS
860
860
  end
861
861
 
862
+ def test_mixin_include_with_keyword_args
863
+ assert_renders <<SASS, <<SCSS
864
+ foo
865
+ +foo-bar(12px, "blaz", $blip: blap, $bloop: blop)
866
+ +foo-bar($blip: blap, $bloop: blop)
867
+ a: blip
868
+ SASS
869
+ foo {
870
+ @include foo-bar(12px, "blaz", $blip: blap, $bloop: blop);
871
+ @include foo-bar($blip: blap, $bloop: blop);
872
+ a: blip; }
873
+ SCSS
874
+ end
875
+
862
876
  def test_variable_definition
863
877
  assert_renders <<SASS, <<SCSS
864
878
  $var1: 12px + 15px
@@ -5,6 +5,7 @@ require File.dirname(__FILE__) + '/test_helper'
5
5
  require 'sass/engine'
6
6
  require 'stringio'
7
7
  require 'mock_importer'
8
+ require 'pathname'
8
9
 
9
10
  module Sass::Script::Functions::UserFunctions
10
11
  def option(name)
@@ -94,6 +95,7 @@ MSG
94
95
  "a-\#{$b\n c: d" => ['Invalid CSS after "a-#{$b": expected "}", was ""', 1],
95
96
  "=a($b = 1, $c)" => "Required argument $c must come before any optional arguments.",
96
97
  "=a($b = 1)\n a: $b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
98
+ "=a($b: 1)\n a: $b\ndiv\n +a(1,$c: 3)" => "Mixin a doesn't have an argument named $c",
97
99
  "=a($b)\n a: $b\ndiv\n +a" => "Mixin a is missing parameter $b.",
98
100
  "@else\n a\n b: c" => ["@else must come after @if.", 1],
99
101
  "@if false\n@else foo" => "Invalid else directive '@else foo': expected 'if <expr>'.",
@@ -115,6 +117,16 @@ MSG
115
117
  '@warn' => "Invalid warn directive '@warn': expected expression.",
116
118
  %Q{@warn "a message"\n "nested message"} => "Illegal nesting: Nothing may be nested beneath warn directives.",
117
119
  "/* foo\n bar\n baz" => "Inconsistent indentation: previous line was indented by 4 spaces, but this line was indented by 2 spaces.",
120
+ '+foo(1 + 1: 2)' => 'Invalid CSS after "(1 + 1": expected comma, was ": 2)"',
121
+ '+foo($var: )' => 'Invalid CSS after "($var: ": expected mixin argument, was ")"',
122
+ '+foo($var: a, $var: b)' => 'Keyword argument "$var" passed more than once',
123
+ '+foo($var-var: a, $var_var: b)' => 'Keyword argument "$var-var" passed more than once',
124
+ '+foo($var_var: a, $var-var: b)' => 'Keyword argument "$var_var" passed more than once',
125
+ "a\n b: foo(1 + 1: 2)" => 'Invalid CSS after "foo(1 + 1": expected comma, was ": 2)"',
126
+ "a\n b: foo($var: )" => 'Invalid CSS after "foo($var: ": expected function argument, was ")"',
127
+ "a\n b: foo($var: a, $var: b)" => 'Keyword argument "$var" passed more than once',
128
+ "a\n b: foo($var-var: a, $var_var: b)" => 'Keyword argument "$var-var" passed more than once',
129
+ "a\n b: foo($var_var: a, $var-var: b)" => 'Keyword argument "$var_var" passed more than once',
118
130
 
119
131
  # Regression tests
120
132
  "a\n b:\n c\n d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
@@ -534,6 +546,15 @@ CSS
534
546
  assert File.exists?(sassc_file)
535
547
  end
536
548
 
549
+ def test_sass_pathname_import
550
+ sassc_file = sassc_path("importee")
551
+ assert !File.exists?(sassc_file)
552
+ renders_correctly("import",
553
+ :style => :compact,
554
+ :load_paths => [Pathname.new(File.dirname(__FILE__) + "/templates")])
555
+ assert File.exists?(sassc_file)
556
+ end
557
+
537
558
  def test_nonexistent_extensionless_import
538
559
  assert_raise_message(Sass::SyntaxError, <<ERR.rstrip) do
539
560
  File to import not found or unreadable: nonexistent.
@@ -2101,6 +2122,70 @@ CSS
2101
2122
  SASS
2102
2123
  end
2103
2124
 
2125
+ def test_mixin_with_keyword_args
2126
+ assert_equal <<CSS, render(<<SASS)
2127
+ .mixed {
2128
+ required: foo;
2129
+ arg1: default-val1;
2130
+ arg2: non-default-val2; }
2131
+ CSS
2132
+ =a-mixin($required, $arg1: default-val1, $arg2: default-val2)
2133
+ required: $required
2134
+ arg1: $arg1
2135
+ arg2: $arg2
2136
+ .mixed
2137
+ +a-mixin(foo, $arg2: non-default-val2)
2138
+ SASS
2139
+ end
2140
+
2141
+ def test_mixin_keyword_args_handle_variable_underscore_dash_equivalence
2142
+ assert_equal <<CSS, render(<<SASS)
2143
+ .mixed {
2144
+ required: foo;
2145
+ arg1: non-default-val1;
2146
+ arg2: non-default-val2; }
2147
+ CSS
2148
+ =a-mixin($required, $arg-1: default-val1, $arg_2: default-val2)
2149
+ required: $required
2150
+ arg1: $arg_1
2151
+ arg2: $arg-2
2152
+ .mixed
2153
+ +a-mixin(foo, $arg-2: non-default-val2, $arg_1: non-default-val1)
2154
+ SASS
2155
+ end
2156
+
2157
+ def test_passing_required_args_as_a_keyword_arg
2158
+ assert_equal <<CSS, render(<<SASS)
2159
+ .mixed {
2160
+ required: foo;
2161
+ arg1: default-val1;
2162
+ arg2: default-val2; }
2163
+ CSS
2164
+ =a-mixin($required, $arg1: default-val1, $arg2: default-val2)
2165
+ required: $required
2166
+ arg1: $arg1
2167
+ arg2: $arg2
2168
+ .mixed
2169
+ +a-mixin($required: foo)
2170
+ SASS
2171
+ end
2172
+
2173
+ def test_passing_all_as_keyword_args_in_opposite_order
2174
+ assert_equal <<CSS, render(<<SASS)
2175
+ .mixed {
2176
+ required: foo;
2177
+ arg1: non-default-val1;
2178
+ arg2: non-default-val2; }
2179
+ CSS
2180
+ =a-mixin($required, $arg1: default-val1, $arg2: default-val2)
2181
+ required: $required
2182
+ arg1: $arg1
2183
+ arg2: $arg2
2184
+ .mixed
2185
+ +a-mixin($arg2: non-default-val2, $arg1: non-default-val1, $required: foo)
2186
+ SASS
2187
+ end
2188
+
2104
2189
  def test_function_output_with_comma
2105
2190
  assert_equal <<CSS, render(<<SASS)
2106
2191
  foo {
@@ -3,6 +3,22 @@ require 'test/unit'
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
4
  require 'sass/script'
5
5
 
6
+ module Sass::Script::Functions
7
+ def no_kw_args
8
+ Sass::Script::String.new("no-kw-args")
9
+ end
10
+
11
+ def only_var_args(*args)
12
+ Sass::Script::String.new("only-var-args("+args.map{|a| a.plus(Sass::Script::Number.new(1)).to_s }.join(", ")+")")
13
+ end
14
+ declare :only_var_args, [], :var_args => true
15
+
16
+ def only_kw_args(kwargs)
17
+ Sass::Script::String.new("only-kw-args(" + kwargs.keys.sort.join(", ") + ")")
18
+ end
19
+ declare :only_kw_args, [], :var_kwargs => true
20
+ end
21
+
6
22
  module Sass::Script::Functions::UserFunctions
7
23
  def call_options_on_new_literal
8
24
  str = Sass::Script::String.new("foo")
@@ -50,6 +66,10 @@ class SassFunctionTest < Test::Unit::TestCase
50
66
  end
51
67
  end
52
68
 
69
+ def test_hsl_kwargs
70
+ assert_equal "#33cccc", evaluate("hsl($hue: 180, $saturation: 60%, $lightness: 50%)")
71
+ end
72
+
53
73
  def test_hsl_checks_bounds
54
74
  assert_error_message("Saturation -114 must be between 0% and 100% for `hsl'", "hsl(10, -114, 12)");
55
75
  assert_error_message("Lightness 256 must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
@@ -65,6 +85,7 @@ class SassFunctionTest < Test::Unit::TestCase
65
85
  assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla(180, 60%, 50%, 0.4)")
66
86
  assert_equal "#33cccc", evaluate("hsla(180, 60%, 50%, 1)")
67
87
  assert_equal "rgba(51, 204, 204, 0)", evaluate("hsla(180, 60%, 50%, 0)")
88
+ assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla($hue: 180, $saturation: 60%, $lightness: 50%, $alpha: 0.4)")
68
89
  end
69
90
 
70
91
  def test_hsla_checks_bounds
@@ -85,6 +106,7 @@ class SassFunctionTest < Test::Unit::TestCase
85
106
  assert_equal("50%", evaluate("percentage(.5)"))
86
107
  assert_equal("100%", evaluate("percentage(1)"))
87
108
  assert_equal("25%", evaluate("percentage(25px / 100px)"))
109
+ assert_equal("50%", evaluate("percentage($value: 0.5)"))
88
110
  end
89
111
 
90
112
  def test_percentage_checks_types
@@ -97,6 +119,7 @@ class SassFunctionTest < Test::Unit::TestCase
97
119
  assert_equal("5", evaluate("round(4.8)"))
98
120
  assert_equal("5px", evaluate("round(4.8px)"))
99
121
  assert_equal("5px", evaluate("round(5.49px)"))
122
+ assert_equal("5px", evaluate("round($value: 5.49px)"))
100
123
 
101
124
  assert_error_message("#cccccc is not a number for `round'", "round(#ccc)")
102
125
  end
@@ -104,6 +127,7 @@ class SassFunctionTest < Test::Unit::TestCase
104
127
  def test_floor
105
128
  assert_equal("4", evaluate("floor(4.8)"))
106
129
  assert_equal("4px", evaluate("floor(4.8px)"))
130
+ assert_equal("4px", evaluate("floor($value: 4.8px)"))
107
131
 
108
132
  assert_error_message("\"foo\" is not a number for `floor'", "floor(\"foo\")")
109
133
  end
@@ -111,6 +135,7 @@ class SassFunctionTest < Test::Unit::TestCase
111
135
  def test_ceil
112
136
  assert_equal("5", evaluate("ceil(4.1)"))
113
137
  assert_equal("5px", evaluate("ceil(4.8px)"))
138
+ assert_equal("5px", evaluate("ceil($value: 4.8px)"))
114
139
 
115
140
  assert_error_message("\"a\" is not a number for `ceil'", "ceil(\"a\")")
116
141
  end
@@ -120,6 +145,7 @@ class SassFunctionTest < Test::Unit::TestCase
120
145
  assert_equal("5px", evaluate("abs(-5px)"))
121
146
  assert_equal("5", evaluate("abs(5)"))
122
147
  assert_equal("5px", evaluate("abs(5px)"))
148
+ assert_equal("5px", evaluate("abs($value: 5px)"))
123
149
 
124
150
  assert_error_message("#aaaaaa is not a number for `abs'", "abs(#aaa)")
125
151
  end
@@ -128,6 +154,7 @@ class SassFunctionTest < Test::Unit::TestCase
128
154
  assert_equal("#123456", evaluate("rgb(18, 52, 86)"))
129
155
  assert_equal("#beaded", evaluate("rgb(190, 173, 237)"))
130
156
  assert_equal("#00ff7f", evaluate("rgb(0, 255, 127)"))
157
+ assert_equal("#00ff7f", evaluate("rgb($red: 0, $green: 255, $blue: 127)"))
131
158
  end
132
159
 
133
160
  def test_rgb_percent
@@ -169,6 +196,7 @@ class SassFunctionTest < Test::Unit::TestCase
169
196
  assert_equal("rgba(18, 52, 86, 0.5)", evaluate("rgba(18, 52, 86, 0.5)"))
170
197
  assert_equal("#beaded", evaluate("rgba(190, 173, 237, 1)"))
171
198
  assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba(0, 255, 127, 0)"))
199
+ assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba($red: 0, $green: 255, $blue: 127, $alpha: 0)"))
172
200
  end
173
201
 
174
202
  def test_rgb_tests_bounds
@@ -198,6 +226,7 @@ class SassFunctionTest < Test::Unit::TestCase
198
226
  def test_rgba_with_color
199
227
  assert_equal "rgba(16, 32, 48, 0.5)", evaluate("rgba(#102030, 0.5)")
200
228
  assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba(blue, 0.5)")
229
+ assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba($color: blue, $alpha: 0.5)")
201
230
  end
202
231
 
203
232
  def test_rgba_with_color_tests_types
@@ -214,6 +243,7 @@ class SassFunctionTest < Test::Unit::TestCase
214
243
 
215
244
  def test_red
216
245
  assert_equal("18", evaluate("red(#123456)"))
246
+ assert_equal("18", evaluate("red($color: #123456)"))
217
247
  end
218
248
 
219
249
  def test_red_exception
@@ -222,6 +252,7 @@ class SassFunctionTest < Test::Unit::TestCase
222
252
 
223
253
  def test_green
224
254
  assert_equal("52", evaluate("green(#123456)"))
255
+ assert_equal("52", evaluate("green($color: #123456)"))
225
256
  end
226
257
 
227
258
  def test_green_exception
@@ -230,6 +261,7 @@ class SassFunctionTest < Test::Unit::TestCase
230
261
 
231
262
  def test_blue
232
263
  assert_equal("86", evaluate("blue(#123456)"))
264
+ assert_equal("86", evaluate("blue($color: #123456)"))
233
265
  end
234
266
 
235
267
  def test_blue_exception
@@ -238,6 +270,7 @@ class SassFunctionTest < Test::Unit::TestCase
238
270
 
239
271
  def test_hue
240
272
  assert_equal("18deg", evaluate("hue(hsl(18, 50%, 20%))"))
273
+ assert_equal("18deg", evaluate("hue($color: hsl(18, 50%, 20%))"))
241
274
  end
242
275
 
243
276
  def test_hue_exception
@@ -247,6 +280,7 @@ class SassFunctionTest < Test::Unit::TestCase
247
280
  def test_saturation
248
281
  assert_equal("52%", evaluate("saturation(hsl(20, 52%, 20%))"))
249
282
  assert_equal("52%", evaluate("saturation(hsl(20, 52, 20%))"))
283
+ assert_equal("52%", evaluate("saturation($color: hsl(20, 52, 20%))"))
250
284
  end
251
285
 
252
286
  def test_saturation_exception
@@ -256,6 +290,7 @@ class SassFunctionTest < Test::Unit::TestCase
256
290
  def test_lightness
257
291
  assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86%))"))
258
292
  assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86))"))
293
+ assert_equal("86%", evaluate("lightness($color: hsl(120, 50%, 86))"))
259
294
  end
260
295
 
261
296
  def test_lightness_exception
@@ -266,6 +301,7 @@ class SassFunctionTest < Test::Unit::TestCase
266
301
  assert_equal("1", evaluate("alpha(#123456)"))
267
302
  assert_equal("0.34", evaluate("alpha(rgba(0, 1, 2, 0.34))"))
268
303
  assert_equal("0", evaluate("alpha(hsla(0, 1, 2, 0))"))
304
+ assert_equal("0", evaluate("alpha($color: hsla(0, 1, 2, 0))"))
269
305
  end
270
306
 
271
307
  def test_alpha_exception
@@ -279,6 +315,8 @@ class SassFunctionTest < Test::Unit::TestCase
279
315
  assert_equal("black", evaluate("fade_in(rgba(0, 0, 0, 0.2), 0.8)"))
280
316
  assert_equal("black", evaluate("opacify(rgba(0, 0, 0, 0.2), 1)"))
281
317
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0%)"))
318
+ assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify($color: rgba(0, 0, 0, 0.2), $amount: 0%)"))
319
+ assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-in($color: rgba(0, 0, 0, 0.2), $amount: 0%)"))
282
320
  end
283
321
 
284
322
  def test_opacify_tests_bounds
@@ -300,6 +338,8 @@ class SassFunctionTest < Test::Unit::TestCase
300
338
  assert_equal("rgba(0, 0, 0, 0)", evaluate("fade_out(rgba(0, 0, 0, 0.2), 0.2)"))
301
339
  assert_equal("rgba(0, 0, 0, 0)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 1)"))
302
340
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0)"))
341
+ assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
342
+ assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
303
343
  end
304
344
 
305
345
  def test_transparentize_tests_bounds
@@ -321,6 +361,7 @@ class SassFunctionTest < Test::Unit::TestCase
321
361
  assert_equal("white", evaluate("lighten(#800, 100%)"))
322
362
  assert_equal("#880000", evaluate("lighten(#800, 0%)"))
323
363
  assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten(rgba(136, 0, 0, 0.5), 20%)"))
364
+ assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten($color: rgba(136, 0, 0, 0.5), $amount: 20%)"))
324
365
  end
325
366
 
326
367
  def test_lighten_tests_bounds
@@ -342,6 +383,7 @@ class SassFunctionTest < Test::Unit::TestCase
342
383
  assert_equal("black", evaluate("darken(#800, 100%)"))
343
384
  assert_equal("#880000", evaluate("darken(#800, 0%)"))
344
385
  assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken(rgba(136, 0, 0, 0.5), 20%)"))
386
+ assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken($color: rgba(136, 0, 0, 0.5), $amount: 20%)"))
345
387
  end
346
388
 
347
389
  def test_darken_tests_bounds
@@ -364,6 +406,7 @@ class SassFunctionTest < Test::Unit::TestCase
364
406
  assert_equal("#33ff33", evaluate("saturate(#8a8, 100%)"))
365
407
  assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
366
408
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
409
+ assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)"))
367
410
  end
368
411
 
369
412
  def test_saturate_tests_bounds
@@ -386,6 +429,7 @@ class SassFunctionTest < Test::Unit::TestCase
386
429
  assert_equal("#999999", evaluate("desaturate(#8a8, 100%)"))
387
430
  assert_equal("#88aa88", evaluate("desaturate(#8a8, 0%)"))
388
431
  assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate(rgba(136, 85, 85, 0.5), 20%)"))
432
+ assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)"))
389
433
  end
390
434
 
391
435
  def test_desaturate_tests_bounds
@@ -409,6 +453,7 @@ class SassFunctionTest < Test::Unit::TestCase
409
453
  assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 360deg)"))
410
454
  assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 0deg)"))
411
455
  assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue(rgba(136, 17, 17, 0.5), 45deg)"))
456
+ assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue($color: rgba(136, 17, 17, 0.5), $degrees: 45deg)"))
412
457
  end
413
458
 
414
459
  def test_adjust_hue_tests_types
@@ -430,6 +475,7 @@ class SassFunctionTest < Test::Unit::TestCase
430
475
  assert_equal("blue", evaluate("mix(transparentize(#f00, 1), #00f, 0%)"))
431
476
  assert_equal("rgba(0, 0, 255, 0)", evaluate("mix(#f00, transparentize(#00f, 1), 0%)"))
432
477
  assert_equal("rgba(255, 0, 0, 0)", evaluate("mix(transparentize(#f00, 1), #00f, 100%)"))
478
+ assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color-1: transparentize(#f00, 1), $color-2: #00f, $weight: 100%)"))
433
479
  end
434
480
 
435
481
  def test_mix_tests_types
@@ -451,6 +497,7 @@ class SassFunctionTest < Test::Unit::TestCase
451
497
  assert_equal("gray", evaluate("grayscale(#00f)"))
452
498
  assert_equal("white", evaluate("grayscale(white)"))
453
499
  assert_equal("black", evaluate("grayscale(black)"))
500
+ assert_equal("black", evaluate("grayscale($color: black)"))
454
501
  end
455
502
 
456
503
  def tets_grayscale_tests_types
@@ -463,6 +510,7 @@ class SassFunctionTest < Test::Unit::TestCase
463
510
  assert_equal("red", evaluate("complement(aqua)"))
464
511
  assert_equal("white", evaluate("complement(white)"))
465
512
  assert_equal("black", evaluate("complement(black)"))
513
+ assert_equal("black", evaluate("complement($color: black)"))
466
514
  end
467
515
 
468
516
  def tets_complement_tests_types
@@ -481,6 +529,7 @@ class SassFunctionTest < Test::Unit::TestCase
481
529
  def test_unquote
482
530
  assert_equal('foo', evaluate('unquote("foo")'))
483
531
  assert_equal('foo', evaluate('unquote(foo)'))
532
+ assert_equal('foo', evaluate('unquote($string: foo)'))
484
533
  end
485
534
 
486
535
  def test_unquote_tests_type
@@ -490,6 +539,7 @@ class SassFunctionTest < Test::Unit::TestCase
490
539
  def test_quote
491
540
  assert_equal('"foo"', evaluate('quote(foo)'))
492
541
  assert_equal('"foo"', evaluate('quote("foo")'))
542
+ assert_equal('"foo"', evaluate('quote($string: "foo")'))
493
543
  end
494
544
 
495
545
  def test_quote_tests_type
@@ -520,6 +570,7 @@ MSG
520
570
  assert_equal("number", evaluate("type-of(1px)"))
521
571
  assert_equal("bool", evaluate("type-of(true)"))
522
572
  assert_equal("color", evaluate("type-of(#fff)"))
573
+ assert_equal("color", evaluate("type-of($value: #fff)"))
523
574
  end
524
575
 
525
576
  def test_unit
@@ -528,12 +579,14 @@ MSG
528
579
  assert_equal(%Q{"em*px"}, evaluate("unit(10px * 5em)"))
529
580
  assert_equal(%Q{"em*px"}, evaluate("unit(5em * 10px)"))
530
581
  assert_equal(%Q{"em*px/cm*rem"}, evaluate("unit(10px * 5em / 30cm / 1rem)"))
582
+ assert_equal(%Q{"px"}, evaluate("unit($number: 100px)"))
531
583
  assert_error_message("#ff0000 is not a number for `unit'", "unit(#f00)")
532
584
  end
533
585
 
534
586
  def test_unitless
535
587
  assert_equal(%Q{true}, evaluate("unitless(100)"))
536
588
  assert_equal(%Q{false}, evaluate("unitless(100px)"))
589
+ assert_equal(%Q{false}, evaluate("unitless($number: 100px)"))
537
590
  assert_error_message("#ff0000 is not a number for `unitless'", "unitless(#f00)")
538
591
  end
539
592
 
@@ -541,10 +594,46 @@ MSG
541
594
  assert_equal(%Q{true}, evaluate("comparable(2px, 1px)"))
542
595
  assert_equal(%Q{true}, evaluate("comparable(10cm, 3mm)"))
543
596
  assert_equal(%Q{false}, evaluate("comparable(100px, 3em)"))
597
+ assert_equal(%Q{false}, evaluate("comparable($number-1: 100px, $number-2: 3em)"))
544
598
  assert_error_message("#ff0000 is not a number for `comparable'", "comparable(#f00, 1px)")
545
599
  assert_error_message("#ff0000 is not a number for `comparable'", "comparable(1px, #f00)")
546
600
  end
547
601
 
602
+ def test_keyword_args_rgb
603
+ assert_equal(%Q{white}, evaluate("rgb($red: 255, $green: 255, $blue: 255)"))
604
+ end
605
+
606
+ def test_keyword_args_rgba
607
+ assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5)"))
608
+ assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($color: #fff, $alpha: 0.5)"))
609
+ end
610
+
611
+ def test_keyword_args_rgba_with_extra_args
612
+ assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5, $extra: error)"))
613
+ rescue Sass::SyntaxError => e
614
+ assert_equal("Function rgba doesn't take an argument named $extra", e.message)
615
+ end
616
+
617
+ def test_keyword_args_must_have_signature
618
+ evaluate("no-kw-args($fake: value)")
619
+ rescue Sass::SyntaxError => e
620
+ assert_equal("Function no_kw_args doesn't support keyword arguments", e.message)
621
+ end
622
+
623
+ def test_keyword_args_with_missing_argument
624
+ evaluate("rgb($red: 255, $green: 255)")
625
+ rescue Sass::SyntaxError => e
626
+ assert_equal("Function rgb requires an argument named $blue", e.message)
627
+ end
628
+
629
+ def test_only_var_args
630
+ assert_equal "only-var-args(2px, 3px, 4px)", evaluate("only-var-args(1px, 2px, 3px)")
631
+ end
632
+
633
+ def test_only_kw_args
634
+ assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)")
635
+ end
636
+
548
637
  private
549
638
 
550
639
  def evaluate(value)