sass 3.4.0 → 3.4.25

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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +26 -20
  7. data/Rakefile +103 -20
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/extra/sass-spec-ref.sh +32 -0
  11. data/extra/update_watch.rb +1 -1
  12. data/lib/sass/cache_stores/filesystem.rb +7 -7
  13. data/lib/sass/cache_stores/memory.rb +4 -5
  14. data/lib/sass/callbacks.rb +2 -2
  15. data/lib/sass/css.rb +11 -10
  16. data/lib/sass/deprecation.rb +55 -0
  17. data/lib/sass/engine.rb +83 -38
  18. data/lib/sass/environment.rb +26 -2
  19. data/lib/sass/error.rb +12 -12
  20. data/lib/sass/exec/base.rb +15 -3
  21. data/lib/sass/exec/sass_convert.rb +34 -15
  22. data/lib/sass/exec/sass_scss.rb +23 -7
  23. data/lib/sass/features.rb +2 -2
  24. data/lib/sass/importers/base.rb +1 -1
  25. data/lib/sass/importers/deprecated_path.rb +51 -0
  26. data/lib/sass/importers/filesystem.rb +24 -16
  27. data/lib/sass/importers.rb +1 -0
  28. data/lib/sass/logger/base.rb +8 -2
  29. data/lib/sass/logger/delayed.rb +50 -0
  30. data/lib/sass/logger.rb +8 -3
  31. data/lib/sass/plugin/compiler.rb +42 -25
  32. data/lib/sass/plugin/configuration.rb +38 -22
  33. data/lib/sass/plugin/merb.rb +2 -2
  34. data/lib/sass/plugin/rack.rb +3 -3
  35. data/lib/sass/plugin/rails.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +3 -3
  37. data/lib/sass/plugin.rb +3 -2
  38. data/lib/sass/script/css_parser.rb +2 -3
  39. data/lib/sass/script/css_variable_warning.rb +52 -0
  40. data/lib/sass/script/functions.rb +140 -73
  41. data/lib/sass/script/lexer.rb +37 -22
  42. data/lib/sass/script/parser.rb +235 -40
  43. data/lib/sass/script/tree/funcall.rb +12 -5
  44. data/lib/sass/script/tree/interpolation.rb +109 -4
  45. data/lib/sass/script/tree/list_literal.rb +31 -4
  46. data/lib/sass/script/tree/literal.rb +4 -0
  47. data/lib/sass/script/tree/node.rb +21 -3
  48. data/lib/sass/script/tree/operation.rb +54 -1
  49. data/lib/sass/script/tree/string_interpolation.rb +58 -37
  50. data/lib/sass/script/tree/variable.rb +1 -1
  51. data/lib/sass/script/value/base.rb +10 -9
  52. data/lib/sass/script/value/color.rb +42 -24
  53. data/lib/sass/script/value/helpers.rb +16 -6
  54. data/lib/sass/script/value/map.rb +1 -1
  55. data/lib/sass/script/value/number.rb +52 -19
  56. data/lib/sass/script/value/string.rb +46 -5
  57. data/lib/sass/script.rb +3 -3
  58. data/lib/sass/scss/css_parser.rb +16 -2
  59. data/lib/sass/scss/parser.rb +120 -75
  60. data/lib/sass/scss/rx.rb +9 -10
  61. data/lib/sass/scss/static_parser.rb +19 -14
  62. data/lib/sass/scss.rb +0 -2
  63. data/lib/sass/selector/abstract_sequence.rb +8 -6
  64. data/lib/sass/selector/comma_sequence.rb +25 -9
  65. data/lib/sass/selector/pseudo.rb +45 -35
  66. data/lib/sass/selector/sequence.rb +54 -18
  67. data/lib/sass/selector/simple.rb +11 -11
  68. data/lib/sass/selector/simple_sequence.rb +34 -15
  69. data/lib/sass/selector.rb +7 -10
  70. data/lib/sass/shared.rb +1 -1
  71. data/lib/sass/source/map.rb +7 -4
  72. data/lib/sass/source/position.rb +4 -4
  73. data/lib/sass/stack.rb +2 -2
  74. data/lib/sass/supports.rb +8 -10
  75. data/lib/sass/tree/comment_node.rb +1 -1
  76. data/lib/sass/tree/css_import_node.rb +9 -1
  77. data/lib/sass/tree/function_node.rb +8 -3
  78. data/lib/sass/tree/import_node.rb +6 -5
  79. data/lib/sass/tree/node.rb +5 -3
  80. data/lib/sass/tree/prop_node.rb +5 -6
  81. data/lib/sass/tree/rule_node.rb +14 -4
  82. data/lib/sass/tree/visitors/check_nesting.rb +18 -22
  83. data/lib/sass/tree/visitors/convert.rb +43 -26
  84. data/lib/sass/tree/visitors/cssize.rb +5 -1
  85. data/lib/sass/tree/visitors/deep_copy.rb +1 -1
  86. data/lib/sass/tree/visitors/extend.rb +15 -13
  87. data/lib/sass/tree/visitors/perform.rb +42 -17
  88. data/lib/sass/tree/visitors/set_options.rb +1 -1
  89. data/lib/sass/tree/visitors/to_css.rb +58 -30
  90. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  91. data/lib/sass/util/normalized_map.rb +0 -1
  92. data/lib/sass/util/subset_map.rb +1 -2
  93. data/lib/sass/util.rb +125 -68
  94. data/lib/sass/version.rb +2 -2
  95. data/lib/sass.rb +10 -3
  96. data/test/sass/compiler_test.rb +6 -2
  97. data/test/sass/conversion_test.rb +187 -53
  98. data/test/sass/css2sass_test.rb +50 -1
  99. data/test/sass/css_variable_test.rb +132 -0
  100. data/test/sass/engine_test.rb +207 -61
  101. data/test/sass/exec_test.rb +10 -0
  102. data/test/sass/extend_test.rb +101 -29
  103. data/test/sass/functions_test.rb +60 -9
  104. data/test/sass/importer_test.rb +9 -0
  105. data/test/sass/more_templates/more1.sass +10 -10
  106. data/test/sass/more_templates/more_import.sass +2 -2
  107. data/test/sass/plugin_test.rb +10 -8
  108. data/test/sass/results/script.css +3 -3
  109. data/test/sass/script_conversion_test.rb +58 -29
  110. data/test/sass/script_test.rb +430 -53
  111. data/test/sass/scss/css_test.rb +73 -7
  112. data/test/sass/scss/rx_test.rb +4 -0
  113. data/test/sass/scss/scss_test.rb +309 -4
  114. data/test/sass/source_map_test.rb +152 -74
  115. data/test/sass/superselector_test.rb +19 -0
  116. data/test/sass/templates/_partial.sass +1 -1
  117. data/test/sass/templates/basic.sass +10 -10
  118. data/test/sass/templates/bork1.sass +1 -1
  119. data/test/sass/templates/bork5.sass +1 -1
  120. data/test/sass/templates/compact.sass +10 -10
  121. data/test/sass/templates/complex.sass +187 -187
  122. data/test/sass/templates/compressed.sass +10 -10
  123. data/test/sass/templates/expanded.sass +10 -10
  124. data/test/sass/templates/import.sass +2 -2
  125. data/test/sass/templates/importee.sass +3 -3
  126. data/test/sass/templates/mixins.sass +22 -22
  127. data/test/sass/templates/multiline.sass +4 -4
  128. data/test/sass/templates/nested.sass +13 -13
  129. data/test/sass/templates/parent_ref.sass +12 -12
  130. data/test/sass/templates/script.sass +70 -70
  131. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  132. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  133. data/test/sass/templates/subdir/subdir.sass +3 -3
  134. data/test/sass/templates/units.sass +10 -10
  135. data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
  136. data/test/sass/util_test.rb +15 -44
  137. data/test/sass-spec.yml +3 -0
  138. data/test/test_helper.rb +5 -4
  139. metadata +302 -295
  140. data/CONTRIBUTING +0 -3
  141. data/lib/sass/scss/script_lexer.rb +0 -15
  142. data/lib/sass/scss/script_parser.rb +0 -25
@@ -31,6 +31,11 @@ class SassScriptTest < MiniTest::Test
31
31
  assert_equal 0, Sass::Script::Value::Color.new([1, 2, 3, -0.1]).alpha
32
32
  end
33
33
 
34
+ def test_color_from_hex
35
+ assert_equal Sass::Script::Value::Color.new([0,0,0]), Sass::Script::Value::Color.from_hex('000000')
36
+ assert_equal Sass::Script::Value::Color.new([0,0,0]), Sass::Script::Value::Color.from_hex('#000000')
37
+ end
38
+
34
39
  def test_string_escapes
35
40
  assert_equal "'", resolve("\"'\"")
36
41
  assert_equal '"', resolve("\"\\\"\"")
@@ -39,6 +44,7 @@ class SassScriptTest < MiniTest::Test
39
44
  assert_equal "☃f", resolve("\"\\2603 f\"")
40
45
  assert_equal "☃x", resolve("\"\\2603x\"")
41
46
  assert_equal "\\2603", resolve("\"\\\\2603\"")
47
+ assert_equal "\#{foo}", resolve("\"\\\#{foo}\"")
42
48
 
43
49
  # U+FFFD is the replacement character, "�".
44
50
  assert_equal [0xFFFD].pack("U"), resolve("\"\\0\"")
@@ -66,12 +72,13 @@ class SassScriptTest < MiniTest::Test
66
72
  assert_equal '"☃abcdef"', resolve_quoted('"\2603 abcdef"')
67
73
  assert_equal '"\\\\"', resolve_quoted('"\\\\"')
68
74
  assert_equal '"foobar"', resolve_quoted("\"foo\\\nbar\"")
75
+ assert_equal '"#{foo}"', resolve_quoted("\"\\\#{foo}\"")
69
76
  end
70
77
 
71
78
  def test_color_names
72
79
  assert_equal "white", resolve("white")
73
80
  assert_equal "#ffffff", resolve("#ffffff")
74
- assert_equal "#fffffe", resolve("white - #000001")
81
+ silence_warnings {assert_equal "#fffffe", resolve("white - #000001")}
75
82
  assert_equal "transparent", resolve("transparent")
76
83
  assert_equal "transparent", resolve("rgba(0, 0, 0, 0)")
77
84
  end
@@ -90,29 +97,56 @@ class SassScriptTest < MiniTest::Test
90
97
  end
91
98
 
92
99
  def test_rgba_color_math
93
- assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")
94
- assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")
100
+ silence_warnings {assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")}
101
+ silence_warnings {assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")}
95
102
 
96
103
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)") do
97
- resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")
104
+ silence_warnings {resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")}
98
105
  end
99
106
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: #123456 * rgba(50, 50, 50, 0.75)") do
100
- resolve("#123456 * rgba(50, 50, 50, 0.75)")
107
+ silence_warnings {resolve("#123456 * rgba(50, 50, 50, 0.75)")}
101
108
  end
102
109
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(50, 50, 50, 0.75) / #123456") do
103
- resolve("rgba(50, 50, 50, 0.75) / #123456")
110
+ silence_warnings {resolve("rgba(50, 50, 50, 0.75) / #123456")}
104
111
  end
105
112
  end
106
113
 
107
114
  def test_rgba_number_math
108
- assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")
109
- assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")
115
+ silence_warnings {assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")}
116
+ silence_warnings {assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")}
110
117
  end
111
118
 
112
119
  def test_rgba_rounding
113
120
  assert_equal "rgba(10, 1, 0, 0.12346)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)")
114
121
  end
115
122
 
123
+ def test_rgb_calc
124
+ assert_equal "rgb(calc(255 - 5), 0, 0)", resolve("rgb(calc(255 - 5), 0, 0)")
125
+ end
126
+
127
+ def test_rgba_calc
128
+ assert_equal "rgba(calc(255 - 5), 0, 0, 0.1)",
129
+ resolve("rgba(calc(255 - 5), 0, 0, 0.1)")
130
+ assert_equal "rgba(127, 0, 0, calc(0.1 + 0.5))",
131
+ resolve("rgba(127, 0, 0, calc(0.1 + 0.5))")
132
+ end
133
+
134
+ def test_rgba_shorthand_calc
135
+ assert_equal "rgba(255, 0, 0, calc(0.1 + 0.5))",
136
+ resolve("rgba(red, calc(0.1 + 0.5))")
137
+ end
138
+
139
+ def test_hsl_calc
140
+ assert_equal "hsl(calc(360 * 5 / 6), 50%, 50%)", resolve("hsl(calc(360 * 5 / 6), 50%, 50%)")
141
+ end
142
+
143
+ def test_hsla_calc
144
+ assert_equal "hsla(calc(360 * 5 / 6), 50%, 50%, 0.1)",
145
+ resolve("hsla(calc(360 * 5 / 6), 50%, 50%, 0.1)")
146
+ assert_equal "hsla(270, 50%, 50%, calc(0.1 + 0.1))",
147
+ resolve("hsla(270, 50%, 50%, calc(0.1 + 0.1))")
148
+ end
149
+
116
150
  def test_compressed_colors
117
151
  assert_equal "#123456", resolve("#123456", :style => :compressed)
118
152
  assert_equal "rgba(1,2,3,0.5)", resolve("rgba(1, 2, 3, 0.5)", :style => :compressed)
@@ -157,43 +191,45 @@ class SassScriptTest < MiniTest::Test
157
191
  end
158
192
 
159
193
  def test_interpolation_near_operators
160
- assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
161
- assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
162
- assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
163
- assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
164
- assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
165
- assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
166
- assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
167
-
168
- assert_equal '3 / 7', resolve('3 / #{3 + 4}')
169
- assert_equal '3 /7', resolve('3 /#{3 + 4}')
170
- assert_equal '3/ 7', resolve('3/ #{3 + 4}')
171
- assert_equal '3/7', resolve('3/#{3 + 4}')
172
-
173
- assert_equal '3 * 7', resolve('#{1 + 2} * 7')
174
- assert_equal '3* 7', resolve('#{1 + 2}* 7')
175
- assert_equal '3 *7', resolve('#{1 + 2} *7')
176
- assert_equal '3*7', resolve('#{1 + 2}*7')
177
-
178
- assert_equal '-3', resolve('-#{1 + 2}')
179
- assert_equal '- 3', resolve('- #{1 + 2}')
180
-
181
- assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
182
- assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
183
- assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
184
- assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
185
- assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
186
- assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
187
-
188
- assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
189
- assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
190
- assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
191
- assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
192
- assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
193
- assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
194
-
195
- assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
196
- assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
194
+ silence_warnings do
195
+ assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
196
+ assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
197
+ assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
198
+ assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
199
+ assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
200
+ assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
201
+ assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
202
+
203
+ assert_equal '3 / 7', resolve('3 / #{3 + 4}')
204
+ assert_equal '3 /7', resolve('3 /#{3 + 4}')
205
+ assert_equal '3/ 7', resolve('3/ #{3 + 4}')
206
+ assert_equal '3/7', resolve('3/#{3 + 4}')
207
+
208
+ assert_equal '3 * 7', resolve('#{1 + 2} * 7')
209
+ assert_equal '3* 7', resolve('#{1 + 2}* 7')
210
+ assert_equal '3 *7', resolve('#{1 + 2} *7')
211
+ assert_equal '3*7', resolve('#{1 + 2}*7')
212
+
213
+ assert_equal '-3', resolve('-#{1 + 2}')
214
+ assert_equal '- 3', resolve('- #{1 + 2}')
215
+
216
+ assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
217
+ assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
218
+ assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
219
+ assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
220
+ assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
221
+ assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
222
+
223
+ assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
224
+ assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
225
+ assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
226
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
227
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
228
+ assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
229
+
230
+ assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
231
+ assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
232
+ end
197
233
  end
198
234
 
199
235
  def test_string_interpolation
@@ -206,6 +242,13 @@ class SassScriptTest < MiniTest::Test
206
242
  assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'')
207
243
  end
208
244
 
245
+ def test_interpolation_in_interpolation
246
+ assert_equal 'foo', resolve('#{#{foo}}')
247
+ assert_equal 'foo', resolve('"#{#{foo}}"')
248
+ assert_equal 'foo', resolve('#{"#{foo}"}')
249
+ assert_equal 'foo', resolve('"#{"#{foo}"}"')
250
+ end
251
+
209
252
  def test_interpolation_with_newline
210
253
  assert_equal "\nbang", resolve('"#{"\a "}bang"')
211
254
  assert_equal "\n\nbang", resolve('"#{"\a "}\a bang"')
@@ -341,6 +384,17 @@ SASS
341
384
  assert_equal "-1", resolve("-1")
342
385
  end
343
386
 
387
+ def test_subtraction_vs_minus_vs_identifier
388
+ assert_equal "0.25em", resolve("1em-.75")
389
+ assert_equal "0.25em", resolve("1em-0.75")
390
+ assert_equal "1em -0.75", resolve("1em -.75")
391
+ assert_equal "1em -0.75", resolve("1em -0.75")
392
+ assert_equal "1em- 0.75", resolve("1em- .75")
393
+ assert_equal "1em- 0.75", resolve("1em- 0.75")
394
+ assert_equal "0.25em", resolve("1em - .75")
395
+ assert_equal "0.25em", resolve("1em - 0.75")
396
+ end
397
+
344
398
  def test_string_ops
345
399
  assert_equal '"foo" "bar"', resolve('"foo" "bar"')
346
400
  assert_equal "true 1", resolve('true 1')
@@ -450,16 +504,33 @@ SASS
450
504
 
451
505
  def test_functions
452
506
  assert_equal "#80ff80", resolve("hsl(120, 100%, 75%)")
453
- assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")
507
+ silence_warnings {assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")}
454
508
  end
455
509
 
456
510
  def test_operator_unit_conversion
457
511
  assert_equal "1.1cm", resolve("1cm + 1mm")
512
+ assert_equal "8q", resolve("4q + 1mm")
513
+ assert_equal "40.025cm", resolve("40cm + 1q")
458
514
  assert_equal "2in", resolve("1in + 96px")
459
515
  assert_equal "true", resolve("2mm < 1cm")
460
516
  assert_equal "true", resolve("10mm == 1cm")
461
- assert_equal "true", resolve("1 == 1cm")
462
517
  assert_equal "true", resolve("1.1cm == 11mm")
518
+ assert_equal "true", resolve("2mm == 8q")
519
+ assert_equal "false", resolve("2px > 3q")
520
+
521
+ Sass::Deprecation.allow_double_warnings do
522
+ assert_warning(<<WARNING) {assert_equal "true", resolve("1 == 1cm")}
523
+ DEPRECATION WARNING on line 1 of test_operator_unit_conversion_inline.sass:
524
+ The result of `1 == 1cm` will be `false` in future releases of Sass.
525
+ Unitless numbers will no longer be equal to the same numbers with units.
526
+ WARNING
527
+
528
+ assert_warning(<<WARNING) {assert_equal "false", resolve("1 != 1cm")}
529
+ DEPRECATION WARNING on line 1 of test_operator_unit_conversion_inline.sass:
530
+ The result of `1 != 1cm` will be `true` in future releases of Sass.
531
+ Unitless numbers will no longer be equal to the same numbers with units.
532
+ WARNING
533
+ end
463
534
  end
464
535
 
465
536
  def test_length_units
@@ -469,6 +540,8 @@ SASS
469
540
  assert_equal "2.83465", resolve("(1mm/1pt)")
470
541
  assert_equal "1.33333", resolve("(1pt/1px)")
471
542
  assert_equal "0.01042", resolve("(1px/1in)")
543
+ assert_equal "1.05833", resolve("(1px/1q)")
544
+ assert_equal "0.05906", resolve("(1q/1pc)")
472
545
  end
473
546
 
474
547
  def test_angle_units
@@ -487,9 +560,9 @@ SASS
487
560
  end
488
561
 
489
562
  def test_resolution_units
490
- assert_equal "2.54", resolve("(1dpi/1dpcm)")
491
- assert_equal "37.79528", resolve("(1dpcm/1dppx)")
492
- assert_equal "0.01042", resolve("(1dppx/1dpi)")
563
+ assert_equal "0.3937", resolve("(1dpi/1dpcm)")
564
+ assert_equal "0.02646", resolve("(1dpcm/1dppx)")
565
+ assert_equal "96", resolve("(1dppx/1dpi)")
493
566
  end
494
567
 
495
568
  def test_operations_have_options
@@ -524,6 +597,13 @@ SASS
524
597
  assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px")))
525
598
  end
526
599
 
600
+ # Regression test for issue 1786.
601
+ def test_slash_division_within_list
602
+ assert_equal "1 1/2 1/2", resolve("(1 1/2 1/2)")
603
+ assert_equal "1/2 1/2", resolve("(1/2 1/2)")
604
+ assert_equal "1/2", resolve("(1/2,)")
605
+ end
606
+
527
607
  def test_non_ident_colors_with_wrong_number_of_digits
528
608
  assert_raise_message(Sass::SyntaxError,
529
609
  'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1"') {eval("#1")}
@@ -540,7 +620,7 @@ SASS
540
620
  def test_case_insensitive_color_names
541
621
  assert_equal "BLUE", resolve("BLUE")
542
622
  assert_equal "rEd", resolve("rEd")
543
- assert_equal "#7f4000", resolve("mix(GrEeN, ReD)")
623
+ assert_equal "#804000", resolve("mix(GrEeN, ReD)")
544
624
  end
545
625
 
546
626
  def test_empty_list
@@ -781,6 +861,112 @@ CSS
781
861
  SCSS
782
862
  end
783
863
 
864
+ def test_if_can_assign_to_global_variables
865
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
866
+ .a {
867
+ b: 2; }
868
+ CSS
869
+ $var: 1;
870
+ @if true {$var: 2}
871
+ .a {b: $var}
872
+ SCSS
873
+ end
874
+
875
+ def test_else_can_assign_to_global_variables
876
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
877
+ .a {
878
+ b: 2; }
879
+ CSS
880
+ $var: 1;
881
+ @if false {}
882
+ @else {$var: 2}
883
+ .a {b: $var}
884
+ SCSS
885
+ end
886
+
887
+ def test_for_can_assign_to_global_variables
888
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
889
+ .a {
890
+ b: 2; }
891
+ CSS
892
+ $var: 1;
893
+ @for $i from 1 to 2 {$var: 2}
894
+ .a {b: $var}
895
+ SCSS
896
+ end
897
+
898
+ def test_each_can_assign_to_global_variables
899
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
900
+ .a {
901
+ b: 2; }
902
+ CSS
903
+ $var: 1;
904
+ @each $a in 1 {$var: 2}
905
+ .a {b: $var}
906
+ SCSS
907
+ end
908
+
909
+ def test_while_can_assign_to_global_variables
910
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
911
+ .a {
912
+ b: 2; }
913
+ CSS
914
+ $var: 1;
915
+ @while $var != 2 {$var: 2}
916
+ .a {b: $var}
917
+ SCSS
918
+ end
919
+
920
+ def test_if_doesnt_leak_local_variables
921
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
922
+ render(<<SCSS, :syntax => :scss)
923
+ @if true {$var: 1}
924
+ .a {b: $var}
925
+ SCSS
926
+ end
927
+ end
928
+
929
+ def test_else_doesnt_leak_local_variables
930
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
931
+ render(<<SCSS, :syntax => :scss)
932
+ @if false {}
933
+ @else {$var: 1}
934
+ .a {b: $var}
935
+ SCSS
936
+ end
937
+ end
938
+
939
+ def test_for_doesnt_leak_local_variables
940
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
941
+ render(<<SCSS, :syntax => :scss)
942
+ @for $i from 1 to 2 {$var: 1}
943
+ .a {b: $var}
944
+ SCSS
945
+ end
946
+ end
947
+
948
+ def test_each_doesnt_leak_local_variables
949
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
950
+ render(<<SCSS, :syntax => :scss)
951
+ @each $a in 1 {$var: 1}
952
+ .a {b: $var}
953
+ SCSS
954
+ end
955
+ end
956
+
957
+ def test_while_doesnt_leak_local_variables
958
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
959
+ render(<<SCSS, :syntax => :scss)
960
+ $iter: true;
961
+ @while $iter {
962
+ $var: 1;
963
+ $iter: false;
964
+ }
965
+ .a {b: $var}
966
+ SCSS
967
+ end
968
+ end
969
+
784
970
  def test_color_format_is_preserved_by_default
785
971
  assert_equal "blue", resolve("blue")
786
972
  assert_equal "bLuE", resolve("bLuE")
@@ -804,7 +990,7 @@ SCSS
804
990
  end
805
991
 
806
992
  def test_color_format_isnt_preserved_when_modified
807
- assert_equal "magenta", resolve("#f00 + #00f")
993
+ assert_equal "magenta", resolve("change-color(#f00, $blue: 255)")
808
994
  end
809
995
 
810
996
  def test_ids
@@ -857,6 +1043,11 @@ SCSS
857
1043
 
858
1044
  # Regression Tests
859
1045
 
1046
+ def test_interpolation_after_string
1047
+ assert_equal '"foobar" 2', resolve('"foobar" #{2}')
1048
+ assert_equal "calc(1 + 2) 3", resolve('calc(1 + 2) #{3}')
1049
+ end
1050
+
860
1051
  def test_repeatedly_modified_color
861
1052
  assert_equal(<<CSS, render(<<SASS))
862
1053
  a {
@@ -912,7 +1103,7 @@ CSS
912
1103
  a
913
1104
  b: foo() / 2
914
1105
  SASS
915
- end
1106
+ end
916
1107
 
917
1108
  def test_funcall_has_higher_precedence_than_color_name
918
1109
  assert_equal "teal(12)", resolve("teal(12)")
@@ -994,12 +1185,198 @@ SASS
994
1185
  assert_equal "NaN", resolve("(0.0/0.0)")
995
1186
  end
996
1187
 
1188
+ def test_equality_uses_an_epsilon
1189
+ # At least on my machine, this calculation introduces a floating point error:
1190
+ # 29.0 / 7 * 7
1191
+ # => 29.000000000000004
1192
+ assert_equal "true", resolve("29 == (29 / 7 * 7)")
1193
+ end
1194
+
1195
+ def test_compressed_output_of_numbers_with_leading_zeros
1196
+ assert_equal "1.5", resolve("1.5", :style => :compressed)
1197
+ assert_equal ".5", resolve("0.5", :style => :compressed)
1198
+ assert_equal "-.5", resolve("-0.5", :style => :compressed)
1199
+ assert_equal "0.5", resolve("0.5", :style => :compact)
1200
+ end
1201
+
1202
+ def test_interpolation_without_deprecation_warning
1203
+ assert_no_warning {assert_equal "a", resolve('#{a}')}
1204
+ assert_no_warning {assert_equal "abc", resolve('a#{b}c')}
1205
+ assert_no_warning {assert_equal "+ a", resolve('+ #{a}')}
1206
+ assert_no_warning {assert_equal "/ a", resolve('/ #{a}')}
1207
+ assert_no_warning {assert_equal "1 / a", resolve('1 / #{a}')}
1208
+ assert_no_warning {assert_equal "a / b", resolve('#{a} / #{b}')}
1209
+ assert_no_warning {assert_equal "foo(1 = a)", resolve('foo(1 = #{a})')}
1210
+ assert_no_warning {assert_equal "foo(a = b)", resolve('foo(#{a} = #{b})')}
1211
+ assert_no_warning {assert_equal "-a", resolve('-#{a}')}
1212
+ assert_no_warning {assert_equal "1-a", resolve('1-#{a}')}
1213
+ assert_no_warning {assert_equal "a- 1", resolve('#{a}- 1')}
1214
+ assert_no_warning {assert_equal "a-1", resolve('#{a}-1')}
1215
+ assert_no_warning {assert_equal "a-b", resolve('#{a}-#{b}')}
1216
+ assert_no_warning {assert_equal "a1", resolve('#{a}1')}
1217
+ assert_no_warning {assert_equal "ab", resolve('#{a}b')}
1218
+ assert_no_warning {assert_equal "1a", resolve('1#{a}')}
1219
+ assert_no_warning {assert_equal "ba", resolve('b#{a}')}
1220
+ end
1221
+
1222
+ def test_leading_interpolation_with_deprecation_warning
1223
+ assert_equal "ab == 1", resolve_with_interp_warning('#{a + b} == 1')
1224
+ assert_equal "ab != 1", resolve_with_interp_warning('#{a + b} != 1')
1225
+ assert_equal "ab > 1", resolve_with_interp_warning('#{a + b} > 1')
1226
+ assert_equal "ab >= 1", resolve_with_interp_warning('#{a + b} >= 1')
1227
+ assert_equal "ab < 1", resolve_with_interp_warning('#{a + b} < 1')
1228
+ assert_equal "ab <= 1", resolve_with_interp_warning('#{a + b} <= 1')
1229
+ assert_equal "ab + 1", resolve_with_interp_warning('#{a + b} + 1')
1230
+ assert_equal "ab * 1", resolve_with_interp_warning('#{a + b} * 1')
1231
+ assert_equal "ab - 1", resolve_with_interp_warning('#{a + b} - 1')
1232
+ assert_equal "ab % 1", resolve_with_interp_warning('#{a + b} % 1')
1233
+ assert_equal(
1234
+ "abvar",
1235
+ resolve_with_interp_warning(
1236
+ '#{a + b}$var', '"#{a + b}#{$var}"',
1237
+ env('var' => Sass::Script::Value::String.new("var"))))
1238
+ assert_equal(
1239
+ "varab",
1240
+ resolve_with_interp_warning(
1241
+ '$var#{a + b}', '"#{$var}#{a + b}"',
1242
+ env('var' => Sass::Script::Value::String.new("var"))))
1243
+ assert_equal "ab1", resolve_with_interp_warning('#{a + b}(1)', '"#{a + b}1"')
1244
+ assert_equal "1ab", resolve_with_interp_warning('(1)#{a + b}', '"1#{a + b}"')
1245
+ end
1246
+
1247
+ def test_trailing_interpolation_with_deprecation_warning
1248
+ assert_equal "not ab", resolve_with_interp_warning('not #{a + b}')
1249
+ assert_equal "1 and ab", resolve_with_interp_warning('1 and #{a + b}')
1250
+ assert_equal "1 or ab", resolve_with_interp_warning('1 or #{a + b}')
1251
+ assert_equal "1 == ab", resolve_with_interp_warning('1 == #{a + b}')
1252
+ assert_equal "1 != ab", resolve_with_interp_warning('1 != #{a + b}')
1253
+ assert_equal "1 > ab", resolve_with_interp_warning('1 > #{a + b}')
1254
+ assert_equal "1 >= ab", resolve_with_interp_warning('1 >= #{a + b}')
1255
+ assert_equal "1 < ab", resolve_with_interp_warning('1 < #{a + b}')
1256
+ assert_equal "1 <= ab", resolve_with_interp_warning('1 <= #{a + b}')
1257
+ assert_equal "1 + ab", resolve_with_interp_warning('1 + #{a + b}')
1258
+ assert_equal "1 * ab", resolve_with_interp_warning('1 * #{a + b}')
1259
+ assert_equal "1 - ab", resolve_with_interp_warning('1 - #{a + b}')
1260
+ assert_equal "1 % ab", resolve_with_interp_warning('1 % #{a + b}')
1261
+ assert_equal "- ab", resolve_with_interp_warning('- #{a + b}')
1262
+ assert_equal "1- ab", resolve_with_interp_warning('1- #{a + b}')
1263
+ assert_equal "- ab 2 3", resolve_with_interp_warning('- #{a + b} 2 3', '"- #{a + b} #{2 3}"')
1264
+ end
1265
+
1266
+ def test_brackteing_interpolation_with_deprecation_warning
1267
+ assert_equal "ab == cd", resolve_with_interp_warning('#{a + b} == #{c + d}')
1268
+ assert_equal "ab != cd", resolve_with_interp_warning('#{a + b} != #{c + d}')
1269
+ assert_equal "ab > cd", resolve_with_interp_warning('#{a + b} > #{c + d}')
1270
+ assert_equal "ab >= cd", resolve_with_interp_warning('#{a + b} >= #{c + d}')
1271
+ assert_equal "ab < cd", resolve_with_interp_warning('#{a + b} < #{c + d}')
1272
+ assert_equal "ab <= cd", resolve_with_interp_warning('#{a + b} <= #{c + d}')
1273
+ assert_equal "ab + cd", resolve_with_interp_warning('#{a + b} + #{c + d}')
1274
+ assert_equal "ab * cd", resolve_with_interp_warning('#{a + b} * #{c + d}')
1275
+ assert_equal "ab - cd", resolve_with_interp_warning('#{a + b} - #{c + d}')
1276
+ assert_equal "ab % cd", resolve_with_interp_warning('#{a + b} % #{c + d}')
1277
+ end
1278
+
1279
+ def test_interp_warning_formatting
1280
+ resolve_with_interp_warning('#{1} + 1', '"1 + 1"')
1281
+ resolve_with_interp_warning('#{1} + "foo"', '\'1 + "foo"\'')
1282
+ resolve_with_interp_warning('#{1} + \'foo\'', '\'1 + "foo"\'')
1283
+
1284
+ resolve_with_interp_warning('#{1} + "#{a + b}"', '\'1 + "#{a + b}"\'')
1285
+ resolve_with_interp_warning('"#{a + b}" + #{1}', '\'"#{a + b}" + 1\'')
1286
+ resolve_with_interp_warning('"#{a + b}" + #{1} + "#{c + d}"', '\'"#{a + b}" + 1 + "#{c + d}"\'')
1287
+
1288
+ resolve_with_interp_warning('#{1} + "\'"', '"1 + \\"\'\\""')
1289
+ resolve_with_interp_warning('#{1} + \'"\'', '"1 + \'\\"\'"')
1290
+ resolve_with_interp_warning('#{1} + "\'\\""', '"1 + \\"\'\\\\\\"\\""')
1291
+ end
1292
+
1293
+ def test_inactive_lazy_interpolation_deprecation_warning
1294
+ assert_equal '1, 2, 3', assert_no_warning {resolve('1, #{2}, 3')}
1295
+ assert_equal '1, 2, 3', assert_no_warning {resolve('1, 2, #{3}')}
1296
+ assert_equal '1,2,3', assert_no_warning {resolve('1,#{2},3')}
1297
+ assert_equal '1 2 3', assert_no_warning {resolve('#{1} 2 3')}
1298
+ assert_equal '1 2 3', assert_no_warning {resolve('1 #{2} 3')}
1299
+ assert_equal '1 2 3', assert_no_warning {resolve('1 2 #{3}')}
1300
+
1301
+ assert_equal '+1 2 3', assert_no_warning {resolve('+#{1} 2 3')}
1302
+ assert_equal '-1 2 3', assert_no_warning {resolve('-#{1} 2 3')}
1303
+ assert_equal '/1 2 3', assert_no_warning {resolve('/#{1} 2 3')}
1304
+
1305
+ assert_equal '1, 2, 31', assert_no_warning {resolve('(1, #{2}, 3) + 1')}
1306
+ assert_equal '11, 2, 3', assert_no_warning {resolve('1 + (1, #{2}, 3)')}
1307
+
1308
+ assert_equal 'a, b, c', assert_no_warning {resolve('selector-parse((a, #{b}, c))')}
1309
+ end
1310
+
1311
+ def test_active_lazy_interpolation_deprecation_warning
1312
+ Sass::Deprecation.allow_double_warnings do
1313
+ assert_equal "1, 2, 3", resolve_with_lazy_interp_warning('quote((1, #{2}, 3))', '"1, 2, 3"')
1314
+ assert_equal "1", resolve_with_lazy_interp_warning('length((1, #{2}, 3))', '"1, 2, 3"')
1315
+ assert_equal "1, 2, 3", resolve_with_lazy_interp_warning('inspect((1, #{2}, 3))', '"1, 2, 3"')
1316
+ assert_equal "string", resolve_with_lazy_interp_warning('type-of((1, #{2}, 3))', '"1, 2, 3"')
1317
+
1318
+ assert_equal "+1 2 3", resolve_with_lazy_interp_warning('quote((+#{1} 2 3))', '"+1 #{2 3}"')
1319
+ assert_equal "/1 2 3", resolve_with_lazy_interp_warning('quote((/#{1} 2 3))', '"/1 #{2 3}"')
1320
+ assert_equal "-1 2 3", resolve_with_lazy_interp_warning('quote((-#{1} 2 3))', '"-1 #{2 3}"')
1321
+ end
1322
+ end
1323
+
1324
+ def test_comparison_of_complex_units
1325
+ # Tests for issue #1960
1326
+ Sass::Deprecation.allow_double_warnings do
1327
+ assert_warning(<<WARNING) do
1328
+ DEPRECATION WARNING on line 1 of test_comparison_of_complex_units_inline.sass:
1329
+ The result of `10 == 10px` will be `false` in future releases of Sass.
1330
+ Unitless numbers will no longer be equal to the same numbers with units.
1331
+ WARNING
1332
+ assert_equal "true", resolve("10 == 2 * 5px")
1333
+ end
1334
+ assert_warning(<<WARNING) do
1335
+ DEPRECATION WARNING on line 1 of test_comparison_of_complex_units_inline.sass:
1336
+ The result of `10 == 10px*px` will be `false` in future releases of Sass.
1337
+ Unitless numbers will no longer be equal to the same numbers with units.
1338
+ WARNING
1339
+ assert_equal "true", resolve("10 == 2px * 5px")
1340
+ end
1341
+ end
1342
+
1343
+ assert_equal "true", resolve("10px * 1px == 2px * 5px")
1344
+ assert_equal "true", resolve("5px * 1px < 2px * 5px")
1345
+ end
1346
+
997
1347
  private
998
1348
 
1349
+ def resolve_with_lazy_interp_warning(str, contents = nil, environment = env)
1350
+ contents ||= "\"#{str}\""
1351
+ result = assert_warning(<<WARNING) {resolve(str, {}, environment)}
1352
+ DEPRECATION WARNING on line 1 of #{filename_for_test}:
1353
+ \#{} interpolation near operators will be simplified in a future version of Sass.
1354
+ To preserve the current behavior, use quotes:
1355
+
1356
+ unquote(#{contents})
1357
+ WARNING
1358
+ $_sass_deprecated_interp_warnings = nil
1359
+ result
1360
+ end
1361
+
1362
+ def resolve_with_interp_warning(str, contents = nil, environment = env)
1363
+ contents ||= "\"#{str}\""
1364
+ assert_warning(<<WARNING) {resolve(str, {}, environment)}
1365
+ DEPRECATION WARNING on line 1 of #{filename_for_test}:
1366
+ \#{} interpolation near operators will be simplified in a future version of Sass.
1367
+ To preserve the current behavior, use quotes:
1368
+
1369
+ unquote(#{contents})
1370
+
1371
+ You can use the sass-convert command to automatically fix most cases.
1372
+ WARNING
1373
+ end
1374
+
999
1375
  def resolve(str, opts = {}, environment = env)
1000
1376
  munge_filename opts
1001
1377
  val = eval(str, opts, environment)
1002
1378
  assert_kind_of Sass::Script::Value::Base, val
1379
+ val.options = opts
1003
1380
  val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s
1004
1381
  end
1005
1382