sass 3.7.4 → 4.0.0.alpha.1

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 (257) hide show
  1. checksums.yaml +13 -5
  2. data/.yardopts +1 -1
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/CONTRIBUTING.md +1 -146
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +25 -39
  7. data/Rakefile +274 -0
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/lib/sass.rb +3 -3
  11. data/lib/sass/cache_stores/filesystem.rb +2 -2
  12. data/lib/sass/cache_stores/memory.rb +5 -4
  13. data/lib/sass/callbacks.rb +2 -2
  14. data/lib/sass/css.rb +12 -12
  15. data/lib/sass/engine.rb +44 -62
  16. data/lib/sass/environment.rb +7 -35
  17. data/lib/sass/error.rb +14 -14
  18. data/lib/sass/exec/base.rb +14 -3
  19. data/lib/sass/exec/sass_convert.rb +6 -20
  20. data/lib/sass/exec/sass_scss.rb +29 -5
  21. data/lib/sass/features.rb +2 -3
  22. data/lib/sass/importers/filesystem.rb +6 -11
  23. data/lib/sass/logger.rb +3 -8
  24. data/lib/sass/logger/base.rb +2 -19
  25. data/lib/sass/plugin.rb +2 -3
  26. data/lib/sass/plugin/compiler.rb +67 -48
  27. data/lib/sass/plugin/configuration.rb +3 -3
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/rack.rb +3 -3
  30. data/lib/sass/plugin/staleness_checker.rb +3 -3
  31. data/lib/sass/railtie.rb +1 -1
  32. data/lib/sass/script.rb +3 -3
  33. data/lib/sass/script/css_parser.rb +15 -5
  34. data/lib/sass/script/functions.rb +121 -337
  35. data/lib/sass/script/lexer.rb +36 -102
  36. data/lib/sass/script/parser.rb +153 -529
  37. data/lib/sass/script/tree/funcall.rb +34 -42
  38. data/lib/sass/script/tree/interpolation.rb +26 -171
  39. data/lib/sass/script/tree/list_literal.rb +8 -23
  40. data/lib/sass/script/tree/map_literal.rb +2 -2
  41. data/lib/sass/script/tree/node.rb +3 -3
  42. data/lib/sass/script/tree/operation.rb +16 -43
  43. data/lib/sass/script/tree/string_interpolation.rb +43 -64
  44. data/lib/sass/script/tree/variable.rb +1 -1
  45. data/lib/sass/script/value.rb +0 -2
  46. data/lib/sass/script/value/arg_list.rb +1 -1
  47. data/lib/sass/script/value/base.rb +9 -27
  48. data/lib/sass/script/value/color.rb +18 -26
  49. data/lib/sass/script/value/helpers.rb +18 -44
  50. data/lib/sass/script/value/list.rb +14 -35
  51. data/lib/sass/script/value/map.rb +2 -2
  52. data/lib/sass/script/value/number.rb +16 -26
  53. data/lib/sass/script/value/string.rb +1 -30
  54. data/lib/sass/scss.rb +2 -0
  55. data/lib/sass/scss/css_parser.rb +3 -7
  56. data/lib/sass/scss/parser.rb +78 -196
  57. data/lib/sass/scss/rx.rb +14 -7
  58. data/lib/sass/scss/script_lexer.rb +15 -0
  59. data/lib/sass/scss/script_parser.rb +25 -0
  60. data/lib/sass/scss/static_parser.rb +55 -38
  61. data/lib/sass/selector.rb +10 -7
  62. data/lib/sass/selector/abstract_sequence.rb +12 -15
  63. data/lib/sass/selector/comma_sequence.rb +6 -24
  64. data/lib/sass/selector/pseudo.rb +6 -19
  65. data/lib/sass/selector/sequence.rb +16 -14
  66. data/lib/sass/selector/simple.rb +7 -9
  67. data/lib/sass/selector/simple_sequence.rb +12 -16
  68. data/lib/sass/shared.rb +1 -1
  69. data/lib/sass/source/map.rb +9 -7
  70. data/lib/sass/source/position.rb +4 -4
  71. data/lib/sass/stack.rb +3 -23
  72. data/lib/sass/tree/charset_node.rb +1 -1
  73. data/lib/sass/tree/comment_node.rb +1 -1
  74. data/lib/sass/tree/function_node.rb +3 -2
  75. data/lib/sass/tree/node.rb +3 -5
  76. data/lib/sass/tree/prop_node.rb +58 -49
  77. data/lib/sass/tree/rule_node.rb +8 -15
  78. data/lib/sass/tree/visitors/check_nesting.rb +23 -19
  79. data/lib/sass/tree/visitors/convert.rb +13 -15
  80. data/lib/sass/tree/visitors/cssize.rb +15 -4
  81. data/lib/sass/tree/visitors/deep_copy.rb +2 -2
  82. data/lib/sass/tree/visitors/extend.rb +14 -10
  83. data/lib/sass/tree/visitors/perform.rb +18 -29
  84. data/lib/sass/tree/visitors/set_options.rb +2 -2
  85. data/lib/sass/tree/visitors/to_css.rb +47 -77
  86. data/lib/sass/util.rb +311 -98
  87. data/lib/sass/util/cross_platform_random.rb +19 -0
  88. data/lib/sass/util/multibyte_string_scanner.rb +133 -127
  89. data/lib/sass/util/normalized_map.rb +8 -1
  90. data/lib/sass/util/ordered_hash.rb +192 -0
  91. data/lib/sass/version.rb +6 -2
  92. data/test/sass/cache_test.rb +131 -0
  93. data/test/sass/callbacks_test.rb +61 -0
  94. data/test/sass/compiler_test.rb +236 -0
  95. data/test/sass/conversion_test.rb +2171 -0
  96. data/test/sass/css2sass_test.rb +526 -0
  97. data/test/sass/data/hsl-rgb.txt +319 -0
  98. data/test/sass/encoding_test.rb +219 -0
  99. data/test/sass/engine_test.rb +3400 -0
  100. data/test/sass/exec_test.rb +86 -0
  101. data/test/sass/extend_test.rb +1719 -0
  102. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  103. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  104. data/test/sass/functions_test.rb +1984 -0
  105. data/test/sass/importer_test.rb +421 -0
  106. data/test/sass/logger_test.rb +58 -0
  107. data/test/sass/mock_importer.rb +49 -0
  108. data/test/sass/more_results/more1.css +9 -0
  109. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  110. data/test/sass/more_results/more_import.css +29 -0
  111. data/test/sass/more_templates/_more_partial.sass +2 -0
  112. data/test/sass/more_templates/more1.sass +23 -0
  113. data/test/sass/more_templates/more_import.sass +11 -0
  114. data/test/sass/plugin_test.rb +556 -0
  115. data/test/sass/results/alt.css +4 -0
  116. data/test/sass/results/basic.css +9 -0
  117. data/test/sass/results/cached_import_option.css +3 -0
  118. data/test/sass/results/compact.css +5 -0
  119. data/test/sass/results/complex.css +86 -0
  120. data/test/sass/results/compressed.css +1 -0
  121. data/test/sass/results/expanded.css +19 -0
  122. data/test/sass/results/filename_fn.css +3 -0
  123. data/test/sass/results/if.css +3 -0
  124. data/test/sass/results/import.css +31 -0
  125. data/test/sass/results/import_charset.css +5 -0
  126. data/test/sass/results/import_charset_1_8.css +5 -0
  127. data/test/sass/results/import_charset_ibm866.css +5 -0
  128. data/test/sass/results/import_content.css +1 -0
  129. data/test/sass/results/line_numbers.css +49 -0
  130. data/test/sass/results/mixins.css +95 -0
  131. data/test/sass/results/multiline.css +24 -0
  132. data/test/sass/results/nested.css +22 -0
  133. data/test/sass/results/options.css +1 -0
  134. data/test/sass/results/parent_ref.css +13 -0
  135. data/test/sass/results/script.css +16 -0
  136. data/test/sass/results/scss_import.css +31 -0
  137. data/test/sass/results/scss_importee.css +2 -0
  138. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  139. data/test/sass/results/subdir/subdir.css +3 -0
  140. data/test/sass/results/units.css +11 -0
  141. data/test/sass/results/warn.css +0 -0
  142. data/test/sass/results/warn_imported.css +0 -0
  143. data/test/sass/script_conversion_test.rb +306 -0
  144. data/test/sass/script_test.rb +1206 -0
  145. data/test/sass/scss/css_test.rb +1281 -0
  146. data/test/sass/scss/rx_test.rb +160 -0
  147. data/test/sass/scss/scss_test.rb +4147 -0
  148. data/test/sass/scss/test_helper.rb +37 -0
  149. data/test/sass/source_map_test.rb +1055 -0
  150. data/test/sass/superselector_test.rb +210 -0
  151. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  152. data/test/sass/templates/_double_import_loop2.sass +1 -0
  153. data/test/sass/templates/_filename_fn_import.scss +11 -0
  154. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  155. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  156. data/test/sass/templates/_imported_content.sass +3 -0
  157. data/test/sass/templates/_partial.sass +2 -0
  158. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  159. data/test/sass/templates/alt.sass +16 -0
  160. data/test/sass/templates/basic.sass +23 -0
  161. data/test/sass/templates/bork1.sass +2 -0
  162. data/test/sass/templates/bork2.sass +2 -0
  163. data/test/sass/templates/bork3.sass +2 -0
  164. data/test/sass/templates/bork4.sass +2 -0
  165. data/test/sass/templates/bork5.sass +3 -0
  166. data/test/sass/templates/cached_import_option.scss +3 -0
  167. data/test/sass/templates/compact.sass +17 -0
  168. data/test/sass/templates/complex.sass +305 -0
  169. data/test/sass/templates/compressed.sass +15 -0
  170. data/test/sass/templates/double_import_loop1.sass +1 -0
  171. data/test/sass/templates/expanded.sass +17 -0
  172. data/test/sass/templates/filename_fn.scss +18 -0
  173. data/test/sass/templates/if.sass +11 -0
  174. data/test/sass/templates/import.sass +12 -0
  175. data/test/sass/templates/import_charset.sass +9 -0
  176. data/test/sass/templates/import_charset_1_8.sass +6 -0
  177. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  178. data/test/sass/templates/import_content.sass +4 -0
  179. data/test/sass/templates/importee.less +2 -0
  180. data/test/sass/templates/importee.sass +19 -0
  181. data/test/sass/templates/line_numbers.sass +13 -0
  182. data/test/sass/templates/mixin_bork.sass +5 -0
  183. data/test/sass/templates/mixins.sass +76 -0
  184. data/test/sass/templates/multiline.sass +20 -0
  185. data/test/sass/templates/nested.sass +25 -0
  186. data/test/sass/templates/nested_bork1.sass +2 -0
  187. data/test/sass/templates/nested_bork2.sass +2 -0
  188. data/test/sass/templates/nested_bork3.sass +2 -0
  189. data/test/sass/templates/nested_bork4.sass +2 -0
  190. data/test/sass/templates/nested_import.sass +2 -0
  191. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  192. data/test/sass/templates/options.sass +2 -0
  193. data/test/sass/templates/parent_ref.sass +25 -0
  194. data/test/sass/templates/same_name_different_ext.sass +2 -0
  195. data/test/sass/templates/same_name_different_ext.scss +1 -0
  196. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  197. data/test/sass/templates/script.sass +101 -0
  198. data/test/sass/templates/scss_import.scss +12 -0
  199. data/test/sass/templates/scss_importee.scss +1 -0
  200. data/test/sass/templates/single_import_loop.sass +1 -0
  201. data/test/sass/templates/subdir/import_up1.scss +1 -0
  202. data/test/sass/templates/subdir/import_up2.scss +1 -0
  203. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  204. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  205. data/test/sass/templates/subdir/subdir.sass +6 -0
  206. data/test/sass/templates/units.sass +11 -0
  207. data/test/sass/templates/warn.sass +3 -0
  208. data/test/sass/templates/warn_imported.sass +4 -0
  209. data/test/sass/test_helper.rb +8 -0
  210. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  211. data/test/sass/util/normalized_map_test.rb +51 -0
  212. data/test/sass/util/subset_map_test.rb +91 -0
  213. data/test/sass/util_test.rb +438 -0
  214. data/test/sass/value_helpers_test.rb +179 -0
  215. data/test/test_helper.rb +110 -0
  216. data/vendor/listen/CHANGELOG.md +1 -0
  217. data/vendor/listen/CONTRIBUTING.md +38 -0
  218. data/vendor/listen/Gemfile +20 -0
  219. data/vendor/listen/Guardfile +8 -0
  220. data/vendor/listen/LICENSE +20 -0
  221. data/vendor/listen/README.md +349 -0
  222. data/vendor/listen/Rakefile +5 -0
  223. data/vendor/listen/Vagrantfile +96 -0
  224. data/vendor/listen/lib/listen.rb +54 -0
  225. data/vendor/listen/lib/listen/adapter.rb +327 -0
  226. data/vendor/listen/lib/listen/adapters/bsd.rb +75 -0
  227. data/vendor/listen/lib/listen/adapters/darwin.rb +48 -0
  228. data/vendor/listen/lib/listen/adapters/linux.rb +81 -0
  229. data/vendor/listen/lib/listen/adapters/polling.rb +58 -0
  230. data/vendor/listen/lib/listen/adapters/windows.rb +91 -0
  231. data/vendor/listen/lib/listen/directory_record.rb +406 -0
  232. data/vendor/listen/lib/listen/listener.rb +323 -0
  233. data/vendor/listen/lib/listen/turnstile.rb +32 -0
  234. data/vendor/listen/lib/listen/version.rb +3 -0
  235. data/vendor/listen/listen.gemspec +28 -0
  236. data/vendor/listen/spec/listen/adapter_spec.rb +149 -0
  237. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  238. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  239. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  240. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  241. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  242. data/vendor/listen/spec/listen/directory_record_spec.rb +1250 -0
  243. data/vendor/listen/spec/listen/listener_spec.rb +258 -0
  244. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  245. data/vendor/listen/spec/listen_spec.rb +67 -0
  246. data/vendor/listen/spec/spec_helper.rb +25 -0
  247. data/vendor/listen/spec/support/adapter_helper.rb +666 -0
  248. data/vendor/listen/spec/support/directory_record_helper.rb +57 -0
  249. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  250. data/vendor/listen/spec/support/listeners_helper.rb +179 -0
  251. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  252. metadata +217 -76
  253. data/extra/sass-spec-ref.sh +0 -40
  254. data/lib/sass/deprecation.rb +0 -55
  255. data/lib/sass/logger/delayed.rb +0 -50
  256. data/lib/sass/script/value/callable.rb +0 -25
  257. data/lib/sass/script/value/function.rb +0 -19
@@ -33,6 +33,17 @@ module Sass
33
33
  File.join(Sass::ROOT_DIR, file)
34
34
  end
35
35
 
36
+ # Converts an array of `[key, value]` pairs to a hash.
37
+ #
38
+ # @example
39
+ # to_hash([[:foo, "bar"], [:baz, "bang"]])
40
+ # #=> {:foo => "bar", :baz => "bang"}
41
+ # @param arr [Array<(Object, Object)>] An array of pairs
42
+ # @return [Hash] A hash
43
+ def to_hash(arr)
44
+ ordered_hash(*arr.compact)
45
+ end
46
+
36
47
  # Maps the keys in a hash according to a block.
37
48
  #
38
49
  # @example
@@ -135,13 +146,8 @@ module Sass
135
146
  def round(value)
136
147
  # If the number is within epsilon of X.5, round up (or down for negative
137
148
  # numbers).
138
- mod = value % 1
139
- mod_is_half = (mod - 0.5).abs < Script::Value::Number.epsilon
140
- if value > 0
141
- !mod_is_half && mod < 0.5 ? value.floor : value.ceil
142
- else
143
- mod_is_half || mod < 0.5 ? value.floor : value.ceil
144
- end
149
+ return value.round if (value % 1) - 0.5 <= -1 * Script::Value::Number.epsilon
150
+ value > 0 ? value.ceil : value.floor
145
151
  end
146
152
 
147
153
  # Concatenates all strings that are adjacent in an array,
@@ -246,67 +252,18 @@ module Sass
246
252
  res
247
253
  end
248
254
 
249
- # Destructively strips whitespace from the beginning and end of the first
250
- # and last elements, respectively, in the array (if those elements are
251
- # strings). Preserves CSS escapes at the end of the array.
255
+ # Destructively strips whitespace from the beginning and end
256
+ # of the first and last elements, respectively,
257
+ # in the array (if those elements are strings).
252
258
  #
253
259
  # @param arr [Array]
254
260
  # @return [Array] `arr`
255
261
  def strip_string_array(arr)
256
262
  arr.first.lstrip! if arr.first.is_a?(String)
257
- arr[-1] = Sass::Util.rstrip_except_escapes(arr[-1]) if arr.last.is_a?(String)
263
+ arr.last.rstrip! if arr.last.is_a?(String)
258
264
  arr
259
265
  end
260
266
 
261
- # Normalizes identifier escapes.
262
- #
263
- # See https://github.com/sass/language/blob/master/accepted/identifier-escapes.md.
264
- #
265
- # @param ident [String]
266
- # @return [String]
267
- def normalize_ident_escapes(ident, start: true)
268
- ident.gsub(/(^)?(#{Sass::SCSS::RX::ESCAPE})/) do |s|
269
- at_start = start && $1
270
- char = escaped_char(s)
271
- next char if char =~ (at_start ? Sass::SCSS::RX::NMSTART : Sass::SCSS::RX::NMCHAR)
272
- if char =~ (at_start ? /[\x0-\x1F\x7F0-9]/ : /[\x0-\x1F\x7F]/)
273
- "\\#{char.ord.to_s(16)} "
274
- else
275
- "\\#{char}"
276
- end
277
- end
278
- end
279
-
280
- # Returns the character encoded by the given escape sequence.
281
- #
282
- # @param escape [String]
283
- # @return [String]
284
- def escaped_char(escape)
285
- if escape =~ /^\\([0-9a-fA-F]{1,6})[ \t\r\n\f]?/
286
- $1.to_i(16).chr(Encoding::UTF_8)
287
- else
288
- escape[1]
289
- end
290
- end
291
-
292
- # Like [String#strip], but preserves escaped whitespace at the end of the
293
- # string.
294
- #
295
- # @param string [String]
296
- # @return [String]
297
- def strip_except_escapes(string)
298
- rstrip_except_escapes(string.lstrip)
299
- end
300
-
301
- # Like [String#rstrip], but preserves escaped whitespace at the end of the
302
- # string.
303
- #
304
- # @param string [String]
305
- # @return [String]
306
- def rstrip_except_escapes(string)
307
- string.sub(/(?<!\\)\s+$/, '')
308
- end
309
-
310
267
  # Return an array of all possible paths through the given arrays.
311
268
  #
312
269
  # @param arrs [Array<Array>]
@@ -342,16 +299,42 @@ module Sass
342
299
  lcs_backtrace(lcs_table(x, y, &block), x, y, x.size - 1, y.size - 1, &block)
343
300
  end
344
301
 
345
- # Like `String.upcase`, but only ever upcases ASCII letters.
346
- def upcase(string)
347
- return string.upcase unless ruby2_4?
348
- string.upcase(:ascii)
302
+ # Converts a Hash to an Array. This is usually identical to `Hash#to_a`,
303
+ # with the following exceptions:
304
+ #
305
+ # * In Ruby 1.8, `Hash#to_a` is not deterministically ordered, but this is.
306
+ # * In Ruby 1.9 when running tests, this is ordered in the same way it would
307
+ # be under Ruby 1.8 (sorted key order rather than insertion order).
308
+ #
309
+ # @param hash [Hash]
310
+ # @return [Array]
311
+ def hash_to_a(hash)
312
+ return hash.to_a unless ruby1_8? || defined?(Test::Unit)
313
+ hash.sort_by {|k, v| k}
349
314
  end
350
315
 
351
- # Like `String.downcase`, but only ever downcases ASCII letters.
352
- def downcase(string)
353
- return string.downcase unless ruby2_4?
354
- string.downcase(:ascii)
316
+ # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
317
+ # order. Unlike {Util#hash_to_a}, the resulting order isn't sorted key order;
318
+ # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
319
+ # appearance order).
320
+ #
321
+ # @param enum [Enumerable]
322
+ # @return [Array<[Object, Array]>] An array of pairs.
323
+ def group_by_to_a(enum)
324
+ return enum.group_by {|e| yield(e)}.to_a unless ruby1_8?
325
+ order = {}
326
+ arr = []
327
+ groups = enum.group_by do |e|
328
+ res = yield(e)
329
+ unless order.include?(res)
330
+ order[res] = order.size
331
+ end
332
+ res
333
+ end
334
+ groups.each do |key, vals|
335
+ arr[order[key]] = [key, vals]
336
+ end
337
+ arr
355
338
  end
356
339
 
357
340
  # Returns a sub-array of `minuend` containing only elements that are also in
@@ -433,7 +416,7 @@ module Sass
433
416
  # Returns information about the caller of the previous method.
434
417
  #
435
418
  # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
436
- # @return [[String, Integer, (String, nil)]]
419
+ # @return [[String, Fixnum, (String, nil)]]
437
420
  # An array containing the filename, line, and method name of the caller.
438
421
  # The method name may be nil
439
422
  def caller_info(entry = nil)
@@ -503,6 +486,16 @@ module Sass
503
486
  Sass::Util.sass_warn full_message
504
487
  end
505
488
 
489
+ # Silence all output to STDERR within a block.
490
+ #
491
+ # @yield A block in which no output will be printed to STDERR
492
+ def silence_warnings
493
+ the_real_stderr, $stderr = $stderr, StringIO.new
494
+ yield
495
+ ensure
496
+ $stderr = the_real_stderr
497
+ end
498
+
506
499
  # Silences all Sass warnings within a block.
507
500
  #
508
501
  # @yield A block in which no Sass warnings will be printed
@@ -517,7 +510,8 @@ module Sass
517
510
  #
518
511
  # @param msg [String]
519
512
  def sass_warn(msg)
520
- Sass.logger.warn("#{msg}\n")
513
+ msg = msg + "\n" unless ruby1?
514
+ Sass.logger.warn(msg)
521
515
  end
522
516
 
523
517
  ## Cross Rails Version Compatibility
@@ -570,6 +564,24 @@ module Sass
570
564
  version_geq(ActionPack::VERSION::STRING, version)
571
565
  end
572
566
 
567
+ # Returns whether this environment is using Listen
568
+ # version 2.0.0 or greater.
569
+ #
570
+ # @return [Boolean]
571
+ def listen_geq_2?
572
+ return @listen_geq_2 unless @listen_geq_2.nil?
573
+ @listen_geq_2 =
574
+ begin
575
+ # Make sure we're loading listen/version from the same place that
576
+ # we're loading listen itself.
577
+ load_listen!
578
+ require 'listen/version'
579
+ version_geq(::Listen::VERSION, '2.0.0')
580
+ rescue LoadError
581
+ false
582
+ end
583
+ end
584
+
573
585
  # Returns an ActionView::Template* class.
574
586
  # In pre-3.0 versions of Rails, most of these classes
575
587
  # were of the form `ActionView::TemplateFoo`,
@@ -622,7 +634,7 @@ module Sass
622
634
 
623
635
  # Returns an array of ints representing the JRuby version number.
624
636
  #
625
- # @return [Array<Integer>]
637
+ # @return [Array<Fixnum>]
626
638
  def jruby_version
627
639
  @jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
628
640
  end
@@ -631,7 +643,7 @@ module Sass
631
643
  #
632
644
  # @param path [String]
633
645
  def glob(path)
634
- path = path.tr('\\', '/') if windows?
646
+ path = path.gsub('\\', '/') if windows?
635
647
  if block_given?
636
648
  Dir.glob(path) {|f| yield(f)}
637
649
  else
@@ -713,10 +725,10 @@ module Sass
713
725
  def file_uri_from_path(path)
714
726
  path = path.to_s if path.is_a?(Pathname)
715
727
  path = path.tr('\\', '/') if windows?
716
- path = URI::DEFAULT_PARSER.escape(path)
728
+ path = Sass::Util.escape_uri(path)
717
729
  return path.start_with?('/') ? "file://" + path : path unless windows?
718
- return "file:///" + path.tr("\\", "/") if path =~ %r{^[a-zA-Z]:[/\\]}
719
- return "file:" + path.tr("\\", "/") if path =~ %r{\\\\[^\\]+\\[^\\/]+}
730
+ return "file:///" + path.tr("\\", "/") if path =~ /^[a-zA-Z]:[\/\\]/
731
+ return "file:" + path.tr("\\", "/") if path =~ /\\\\[^\\]+\\[^\\\/]+/
720
732
  path.tr("\\", "/")
721
733
  end
722
734
 
@@ -748,25 +760,87 @@ module Sass
748
760
  val || []
749
761
  end
750
762
 
751
- CHARSET_REGEXP = /\A@charset "([^"]+)"/
752
- bom = "\uFEFF"
753
- UTF_8_BOM = bom.encode("UTF-8").force_encoding('BINARY')
754
- UTF_16BE_BOM = bom.encode("UTF-16BE").force_encoding('BINARY')
755
- UTF_16LE_BOM = bom.encode("UTF-16LE").force_encoding('BINARY')
756
-
757
763
  ## Cross-Ruby-Version Compatibility
758
764
 
759
- # Whether or not this is running under Ruby 2.4 or higher.
765
+ # Whether or not this is running under a Ruby version under 2.0.
760
766
  #
761
767
  # @return [Boolean]
762
- def ruby2_4?
763
- return @ruby2_4 if defined?(@ruby2_4)
764
- @ruby2_4 =
765
- if RUBY_VERSION_COMPONENTS[0] == 2
766
- RUBY_VERSION_COMPONENTS[1] >= 4
767
- else
768
- RUBY_VERSION_COMPONENTS[0] > 2
769
- end
768
+ def ruby1?
769
+ return @ruby1 if defined?(@ruby1)
770
+ @ruby1 = RUBY_VERSION_COMPONENTS[0] <= 1
771
+ end
772
+
773
+ # Whether or not this is running under Ruby 1.8 or lower.
774
+ #
775
+ # Note that IronRuby counts as Ruby 1.8,
776
+ # because it doesn't support the Ruby 1.9 encoding API.
777
+ #
778
+ # @return [Boolean]
779
+ def ruby1_8?
780
+ # IronRuby says its version is 1.9, but doesn't support any of the encoding APIs.
781
+ # We have to fall back to 1.8 behavior.
782
+ return @ruby1_8 if defined?(@ruby1_8)
783
+ @ruby1_8 = ironruby? ||
784
+ (RUBY_VERSION_COMPONENTS[0] == 1 && RUBY_VERSION_COMPONENTS[1] < 9)
785
+ end
786
+
787
+ # Whether or not this is running under Ruby 1.9.2 exactly.
788
+ #
789
+ # @return [Boolean]
790
+ def ruby1_9_2?
791
+ return @ruby1_9_2 if defined?(@ruby1_9_2)
792
+ @ruby1_9_2 = RUBY_VERSION_COMPONENTS == [1, 9, 2]
793
+ end
794
+
795
+ # Wehter or not this is running under JRuby 1.6 or lower.
796
+ def jruby1_6?
797
+ return @jruby1_6 if defined?(@jruby1_6)
798
+ @jruby1_6 = jruby? && jruby_version[0] == 1 && jruby_version[1] < 7
799
+ end
800
+
801
+ # Whether or not this is running under MacRuby.
802
+ #
803
+ # @return [Boolean]
804
+ def macruby?
805
+ return @macruby if defined?(@macruby)
806
+ @macruby = RUBY_ENGINE == 'macruby'
807
+ end
808
+
809
+ require 'sass/util/ordered_hash' if ruby1_8?
810
+
811
+ # Converts a hash or a list of pairs into an order-preserving hash.
812
+ #
813
+ # On Ruby 1.8.7, this uses the orderedhash gem to simulate an
814
+ # order-preserving hash. On Ruby 1.9 and up, it just uses the native Hash
815
+ # class, since that preserves the order itself.
816
+ #
817
+ # @overload ordered_hash(hash)
818
+ # @param hash [Hash] a normal hash to convert to an ordered hash
819
+ # @return [Hash]
820
+ # @overload ordered_hash(*pairs)
821
+ # @example
822
+ # ordered_hash([:foo, "bar"], [:baz, "bang"])
823
+ # #=> {:foo => "bar", :baz => "bang"}
824
+ # ordered_hash #=> {}
825
+ # @param pairs [Array<(Object, Object)>] the list of key/value pairs for
826
+ # the hash.
827
+ # @return [Hash]
828
+ def ordered_hash(*pairs_or_hash)
829
+ if pairs_or_hash.length == 1 && pairs_or_hash.first.is_a?(Hash)
830
+ hash = pairs_or_hash.first
831
+ return hash unless ruby1_8?
832
+ return OrderedHash.new.merge hash
833
+ end
834
+
835
+ return Hash[pairs_or_hash] unless ruby1_8?
836
+ (pairs_or_hash.is_a?(NormalizedMap) ? NormalizedMap : OrderedHash)[*pairs_or_hash.flatten(1)]
837
+ end
838
+
839
+ unless ruby1_8?
840
+ CHARSET_REGEXP = /\A@charset "([^"]+)"/
841
+ UTF_8_BOM = "\xEF\xBB\xBF".force_encoding('BINARY')
842
+ UTF_16BE_BOM = "\xFE\xFF".force_encoding('BINARY')
843
+ UTF_16LE_BOM = "\xFF\xFE".force_encoding('BINARY')
770
844
  end
771
845
 
772
846
  # Like {\#check\_encoding}, but also checks for a `@charset` declaration
@@ -776,7 +850,7 @@ module Sass
776
850
  #
777
851
  # @param str [String] The string of which to check the encoding
778
852
  # @return [(String, Encoding)] The original string encoded as UTF-8,
779
- # and the source encoding of the string
853
+ # and the source encoding of the string (or `nil` under Ruby 1.8)
780
854
  # @raise [Encoding::UndefinedConversionError] if the source encoding
781
855
  # cannot be converted to UTF-8
782
856
  # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
@@ -784,6 +858,15 @@ module Sass
784
858
  # doesn't match its contents, or it doesn't declare an encoding and its
785
859
  # contents are invalid in the native encoding.
786
860
  def check_sass_encoding(str)
861
+ # On Ruby 1.8 we can't do anything complicated with encodings.
862
+ # Instead, we just strip out a UTF-8 BOM if it exists and
863
+ # sanitize according to Section 3.3 of CSS Syntax Level 3. We
864
+ # don't sanitize null characters since they might be components
865
+ # of other characters.
866
+ if ruby1_8?
867
+ return str.gsub(/\A\xEF\xBB\xBF/, '').gsub(/\r\n?|\f/, "\n"), nil
868
+ end
869
+
787
870
  # Determine the fallback encoding following section 3.2 of CSS Syntax Level 3 and Encodings:
788
871
  # http://www.w3.org/TR/2013/WD-css-syntax-3-20130919/#determine-the-fallback-encoding
789
872
  # http://encoding.spec.whatwg.org/#decode
@@ -799,9 +882,14 @@ module Sass
799
882
  str = binary.force_encoding('UTF-16LE')
800
883
  elsif binary =~ CHARSET_REGEXP
801
884
  charset = $1.force_encoding('US-ASCII')
802
- encoding = Encoding.find(charset)
803
- if encoding.name == 'UTF-16' || encoding.name == 'UTF-16BE'
885
+ # Ruby 1.9.2 doesn't recognize a UTF-16 encoding without an endian marker.
886
+ if ruby1_9_2? && charset.downcase == 'utf-16'
804
887
  encoding = Encoding.find('UTF-8')
888
+ else
889
+ encoding = Encoding.find(charset)
890
+ if encoding.name == 'UTF-16' || encoding.name == 'UTF-16BE'
891
+ encoding = Encoding.find('UTF-8')
892
+ end
805
893
  end
806
894
  str = binary.force_encoding(encoding)
807
895
  elsif str.encoding.name == "ASCII-8BIT"
@@ -821,6 +909,50 @@ module Sass
821
909
  end
822
910
  end
823
911
 
912
+ # Checks to see if a class has a given method.
913
+ # For example:
914
+ #
915
+ # Sass::Util.has?(:public_instance_method, String, :gsub) #=> true
916
+ #
917
+ # Method collections like `Class#instance_methods`
918
+ # return strings in Ruby 1.8 and symbols in Ruby 1.9 and on,
919
+ # so this handles checking for them in a compatible way.
920
+ #
921
+ # @param attr [#to_s] The (singular) name of the method-collection method
922
+ # (e.g. `:instance_methods`, `:private_methods`)
923
+ # @param klass [Module] The class to check the methods of which to check
924
+ # @param method [String, Symbol] The name of the method do check for
925
+ # @return [Boolean] Whether or not the given collection has the given method
926
+ def has?(attr, klass, method)
927
+ klass.send("#{attr}s").include?(ruby1_8? ? method.to_s : method.to_sym)
928
+ end
929
+
930
+ # A version of `Enumerable#enum_with_index` that works in Ruby 1.8 and 1.9.
931
+ #
932
+ # @param enum [Enumerable] The enumerable to get the enumerator for
933
+ # @return [Enumerator] The with-index enumerator
934
+ def enum_with_index(enum)
935
+ ruby1_8? ? enum.enum_with_index : enum.each_with_index
936
+ end
937
+
938
+ # A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9.
939
+ #
940
+ # @param enum [Enumerable] The enumerable to get the enumerator for
941
+ # @param n [Fixnum] The size of each cons
942
+ # @return [Enumerator] The consed enumerator
943
+ def enum_cons(enum, n)
944
+ ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n)
945
+ end
946
+
947
+ # A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9.
948
+ #
949
+ # @param enum [Enumerable] The enumerable to get the enumerator for
950
+ # @param n [Fixnum] The size of each slice
951
+ # @return [Enumerator] The consed enumerator
952
+ def enum_slice(enum, n)
953
+ ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
954
+ end
955
+
824
956
  # Destructively removes all elements from an array that match a block, and
825
957
  # returns the removed elements.
826
958
  #
@@ -839,6 +971,14 @@ module Sass
839
971
  out
840
972
  end
841
973
 
974
+ # Returns the ASCII code of the given character.
975
+ #
976
+ # @param c [String] All characters but the first are ignored.
977
+ # @return [Fixnum] The ASCII code of `c`.
978
+ def ord(c)
979
+ ruby1_8? ? c[0] : c.ord
980
+ end
981
+
842
982
  # Flattens the first level of nested arrays in `arrs`. Unlike
843
983
  # `Array#flatten`, this orders the result by taking the first
844
984
  # values from each array in order, then the second, and so on.
@@ -959,11 +1099,11 @@ module Sass
959
1099
 
960
1100
  # Converts the argument into a valid JSON value.
961
1101
  #
962
- # @param v [Integer, String, Array, Boolean, nil]
1102
+ # @param v [Fixnum, String, Array, Boolean, nil]
963
1103
  # @return [String]
964
1104
  def json_value_of(v)
965
1105
  case v
966
- when Integer
1106
+ when Fixnum
967
1107
  v.to_s
968
1108
  when String
969
1109
  "\"" + json_escape_string(v) + "\""
@@ -985,10 +1125,10 @@ module Sass
985
1125
  VLQ_BASE_MASK = VLQ_BASE - 1
986
1126
  VLQ_CONTINUATION_BIT = VLQ_BASE
987
1127
 
988
- BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
1128
+ BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
989
1129
  BASE64_DIGIT_MAP = begin
990
1130
  map = {}
991
- BASE64_DIGITS.each_with_index.map do |digit, i|
1131
+ Sass::Util.enum_with_index(BASE64_DIGITS).map do |digit, i|
992
1132
  map[digit] = i
993
1133
  end
994
1134
  map
@@ -996,7 +1136,7 @@ module Sass
996
1136
 
997
1137
  # Encodes `value` as VLQ (http://en.wikipedia.org/wiki/VLQ).
998
1138
  #
999
- # @param value [Integer]
1139
+ # @param value [Fixnum]
1000
1140
  # @return [String] The encoded value
1001
1141
  def encode_vlq(value)
1002
1142
  if value < 0
@@ -1017,6 +1157,35 @@ module Sass
1017
1157
  result
1018
1158
  end
1019
1159
 
1160
+ # This is a hack around the fact that you can't instantiate a URI parser on
1161
+ # 1.8, so we have to have this hacky stuff to work around it. When 1.8
1162
+ # support is dropped, we can remove this method.
1163
+ #
1164
+ # @private
1165
+ URI_ESCAPE = URI.const_defined?("DEFAULT_PARSER") ? URI::DEFAULT_PARSER : URI
1166
+
1167
+ # URI-escape `string`.
1168
+ #
1169
+ # @param string [String]
1170
+ # @return [String]
1171
+ def escape_uri(string)
1172
+ URI_ESCAPE.escape string
1173
+ end
1174
+
1175
+ # A cross-platform implementation of `File.absolute_path`.
1176
+ #
1177
+ # @param path [String]
1178
+ # @param dir_string [String] The directory to consider [path] relative to.
1179
+ # @return [String] The absolute version of `path`.
1180
+ def absolute_path(path, dir_string = nil)
1181
+ # Ruby 1.8 doesn't support File.absolute_path.
1182
+ return File.absolute_path(path, dir_string) unless ruby1_8?
1183
+
1184
+ # File.expand_path expands "~", which we don't want.
1185
+ return File.expand_path(path, dir_string) unless path[0] == ?~
1186
+ File.expand_path(File.join(".", path), dir_string)
1187
+ end
1188
+
1020
1189
  ## Static Method Stuff
1021
1190
 
1022
1191
  # The context in which the ERB for \{#def\_static\_method} will be run.
@@ -1074,6 +1243,44 @@ module Sass
1074
1243
  tmpfile.unlink if tmpfile
1075
1244
  end
1076
1245
 
1246
+ def load_listen!
1247
+ if defined?(gem)
1248
+ begin
1249
+ gem 'listen', '>= 1.1.0', '< 3.0.0'
1250
+ require 'listen'
1251
+ rescue Gem::LoadError
1252
+ dir = scope("vendor/listen/lib")
1253
+ $LOAD_PATH.unshift dir
1254
+ begin
1255
+ require 'listen'
1256
+ rescue LoadError => e
1257
+ if version_geq(RUBY_VERSION, "1.9.3")
1258
+ version_constraint = "~> 3.0"
1259
+ else
1260
+ version_constraint = "~> 1.1"
1261
+ end
1262
+ e.message << "\n" <<
1263
+ "Run \"gem install listen --version '#{version_constraint}'\" to get it."
1264
+ raise e
1265
+ end
1266
+ end
1267
+ else
1268
+ begin
1269
+ require 'listen'
1270
+ rescue LoadError => e
1271
+ dir = scope("vendor/listen/lib")
1272
+ if $LOAD_PATH.include?(dir)
1273
+ raise e unless File.exist?(scope(".git"))
1274
+ e.message << "\n" <<
1275
+ 'Run "git submodule update --init" to get the bundled version.'
1276
+ else
1277
+ $LOAD_PATH.unshift dir
1278
+ retry
1279
+ end
1280
+ end
1281
+ end
1282
+ end
1283
+
1077
1284
  private
1078
1285
 
1079
1286
  def find_encoding_error(str)
@@ -1097,10 +1304,13 @@ module Sass
1097
1304
  return str, str.encoding
1098
1305
  end
1099
1306
 
1307
+ # rubocop:disable LineLength
1308
+
1100
1309
  # Calculates the memoization table for the Least Common Subsequence algorithm.
1101
1310
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS)
1102
1311
  def lcs_table(x, y)
1103
1312
  # This method does not take a block as an explicit parameter for performance reasons.
1313
+ # rubocop:enable LineLength
1104
1314
  c = Array.new(x.size) {[]}
1105
1315
  x.size.times {|i| c[i][0] = 0}
1106
1316
  y.size.times {|j| c[0][j] = 0}
@@ -1116,10 +1326,12 @@ module Sass
1116
1326
  end
1117
1327
  c
1118
1328
  end
1329
+ # rubocop:disable ParameterLists, LineLength
1119
1330
 
1120
1331
  # Computes a single longest common subsequence for arrays x and y.
1121
1332
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
1122
1333
  def lcs_backtrace(c, x, y, i, j, &block)
1334
+ # rubocop:enable ParameterList, LineLengths
1123
1335
  return [] if i == 0 || j == 0
1124
1336
  if (v = yield(x[i], y[j]))
1125
1337
  return lcs_backtrace(c, x, y, i - 1, j - 1, &block) << v
@@ -1135,3 +1347,4 @@ end
1135
1347
 
1136
1348
  require 'sass/util/multibyte_string_scanner'
1137
1349
  require 'sass/util/normalized_map'
1350
+ require 'sass/util/cross_platform_random'