sass 3.1.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
data/lib/sass/util.rb CHANGED
@@ -2,8 +2,10 @@ require 'erb'
2
2
  require 'set'
3
3
  require 'enumerator'
4
4
  require 'stringio'
5
- require 'strscan'
6
5
  require 'rbconfig'
6
+ require 'uri'
7
+ require 'thread'
8
+ require 'pathname'
7
9
 
8
10
  require 'sass/root'
9
11
  require 'sass/util/subset_map'
@@ -38,7 +40,7 @@ module Sass
38
40
  # @param arr [Array<(Object, Object)>] An array of pairs
39
41
  # @return [Hash] A hash
40
42
  def to_hash(arr)
41
- Hash[arr.compact]
43
+ ordered_hash(*arr.compact)
42
44
  end
43
45
 
44
46
  # Maps the keys in a hash according to a block.
@@ -54,7 +56,7 @@ module Sass
54
56
  # @see #map_vals
55
57
  # @see #map_hash
56
58
  def map_keys(hash)
57
- to_hash(hash.map {|k, v| [yield(k), v]})
59
+ map_hash(hash) {|k, v| [yield(k), v]}
58
60
  end
59
61
 
60
62
  # Maps the values in a hash according to a block.
@@ -70,7 +72,14 @@ module Sass
70
72
  # @see #map_keys
71
73
  # @see #map_hash
72
74
  def map_vals(hash)
73
- to_hash(hash.map {|k, v| [k, yield(v)]})
75
+ # We don't delegate to map_hash for performance here
76
+ # because map_hash does more than is necessary.
77
+ rv = hash.class.new
78
+ hash = hash.as_stored if hash.is_a?(NormalizedMap)
79
+ hash.each do |k, v|
80
+ rv[k] = yield(v)
81
+ end
82
+ rv
74
83
  end
75
84
 
76
85
  # Maps the key-value pairs of a hash according to a block.
@@ -86,8 +95,16 @@ module Sass
86
95
  # @return [Hash] The mapped hash
87
96
  # @see #map_keys
88
97
  # @see #map_vals
89
- def map_hash(hash, &block)
90
- to_hash(hash.map(&block))
98
+ def map_hash(hash)
99
+ # Copy and modify is more performant than mapping to an array and using
100
+ # to_hash on the result.
101
+ rv = hash.class.new
102
+ hash.each do |k, v|
103
+ new_key, new_value = yield(k, v)
104
+ new_key = hash.denormalize(new_key) if hash.is_a?(NormalizedMap) && new_key == k
105
+ rv[new_key] = new_value
106
+ end
107
+ rv
91
108
  end
92
109
 
93
110
  # Computes the powerset of the given array.
@@ -155,6 +172,19 @@ module Sass
155
172
  enum.inject([]) {|a, e| a << e << val}[0...-1]
156
173
  end
157
174
 
175
+ def slice_by(enum)
176
+ results = []
177
+ enum.each do |value|
178
+ key = yield(value)
179
+ if !results.empty? && results.last.first == key
180
+ results.last.last << value
181
+ else
182
+ results << [key, [value]]
183
+ end
184
+ end
185
+ results
186
+ end
187
+
158
188
  # Substitutes a sub-array of one array with another sub-array.
159
189
  #
160
190
  # @param ary [Array] The array in which to make the substitution
@@ -164,8 +194,8 @@ module Sass
164
194
  res = ary.dup
165
195
  i = 0
166
196
  while i < res.size
167
- if res[i...i+from.size] == from
168
- res[i...i+from.size] = to
197
+ if res[i...i + from.size] == from
198
+ res[i...i + from.size] = to
169
199
  end
170
200
  i += 1
171
201
  end
@@ -216,15 +246,120 @@ module Sass
216
246
  x = [nil, *x]
217
247
  y = [nil, *y]
218
248
  block ||= proc {|a, b| a == b && a}
219
- lcs_backtrace(lcs_table(x, y, &block), x, y, x.size-1, y.size-1, &block)
249
+ lcs_backtrace(lcs_table(x, y, &block), x, y, x.size - 1, y.size - 1, &block)
250
+ end
251
+
252
+ # Converts a Hash to an Array. This is usually identical to `Hash#to_a`,
253
+ # with the following exceptions:
254
+ #
255
+ # * In Ruby 1.8, `Hash#to_a` is not deterministically ordered, but this is.
256
+ # * In Ruby 1.9 when running tests, this is ordered in the same way it would
257
+ # be under Ruby 1.8 (sorted key order rather than insertion order).
258
+ #
259
+ # @param hash [Hash]
260
+ # @return [Array]
261
+ def hash_to_a(hash)
262
+ return hash.to_a unless ruby1_8? || defined?(Test::Unit)
263
+ hash.sort_by {|k, v| k}
264
+ end
265
+
266
+ # Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
267
+ # order. Unlike {Util#hash_to_a}, the resulting order isn't sorted key order;
268
+ # instead, it's the same order as `#group_by` has under Ruby 1.9 (key
269
+ # appearance order).
270
+ #
271
+ # @param enum [Enumerable]
272
+ # @return [Array<[Object, Array]>] An array of pairs.
273
+ def group_by_to_a(enum)
274
+ return enum.group_by {|e| yield(e)}.to_a unless ruby1_8?
275
+ order = {}
276
+ arr = []
277
+ groups = enum.group_by do |e|
278
+ res = yield(e)
279
+ unless order.include?(res)
280
+ order[res] = order.size
281
+ end
282
+ res
283
+ end
284
+ groups.each do |key, vals|
285
+ arr[order[key]] = [key, vals]
286
+ end
287
+ arr
288
+ end
289
+
290
+ # Returns a sub-array of `minuend` containing only elements that are also in
291
+ # `subtrahend`. Ensures that the return value has the same order as
292
+ # `minuend`, even on Rubinius where that's not guaranteed by `Array#-`.
293
+ #
294
+ # @param minuend [Array]
295
+ # @param subtrahend [Array]
296
+ # @return [Array]
297
+ def array_minus(minuend, subtrahend)
298
+ return minuend - subtrahend unless rbx?
299
+ set = Set.new(minuend) - subtrahend
300
+ minuend.select {|e| set.include?(e)}
301
+ end
302
+
303
+ # Returns a string description of the character that caused an
304
+ # `Encoding::UndefinedConversionError`.
305
+ #
306
+ # @param e [Encoding::UndefinedConversionError]
307
+ # @return [String]
308
+ def undefined_conversion_error_char(e)
309
+ # Rubinius (as of 2.0.0.rc1) pre-quotes the error character.
310
+ return e.error_char if rbx?
311
+ # JRuby (as of 1.7.2) doesn't have an error_char field on
312
+ # Encoding::UndefinedConversionError.
313
+ return e.error_char.dump unless jruby?
314
+ e.message[/^"[^"]+"/] # "
315
+ end
316
+
317
+ # Asserts that `value` falls within `range` (inclusive), leaving
318
+ # room for slight floating-point errors.
319
+ #
320
+ # @param name [String] The name of the value. Used in the error message.
321
+ # @param range [Range] The allowed range of values.
322
+ # @param value [Numeric, Sass::Script::Value::Number] The value to check.
323
+ # @param unit [String] The unit of the value. Used in error reporting.
324
+ # @return [Numeric] `value` adjusted to fall within range, if it
325
+ # was outside by a floating-point margin.
326
+ def check_range(name, range, value, unit = '')
327
+ grace = (-0.00001..0.00001)
328
+ str = value.to_s
329
+ value = value.value if value.is_a?(Sass::Script::Value::Number)
330
+ return value if range.include?(value)
331
+ return range.first if grace.include?(value - range.first)
332
+ return range.last if grace.include?(value - range.last)
333
+ raise ArgumentError.new(
334
+ "#{name} #{str} must be between #{range.first}#{unit} and #{range.last}#{unit}")
335
+ end
336
+
337
+ # Returns whether or not `seq1` is a subsequence of `seq2`. That is, whether
338
+ # or not `seq2` contains every element in `seq1` in the same order (and
339
+ # possibly more elements besides).
340
+ #
341
+ # @param seq1 [Array]
342
+ # @param seq2 [Array]
343
+ # @return [Boolean]
344
+ def subsequence?(seq1, seq2)
345
+ i = j = 0
346
+ loop do
347
+ return true if i == seq1.size
348
+ return false if j == seq2.size
349
+ i += 1 if seq1[i] == seq2[j]
350
+ j += 1
351
+ end
220
352
  end
221
353
 
222
354
  # Returns information about the caller of the previous method.
223
355
  #
224
356
  # @param entry [String] An entry in the `#caller` list, or a similarly formatted string
225
- # @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller.
357
+ # @return [[String, Fixnum, (String, nil)]]
358
+ # An array containing the filename, line, and method name of the caller.
226
359
  # The method name may be nil
227
- def caller_info(entry = caller[1])
360
+ def caller_info(entry = nil)
361
+ # JRuby evaluates `caller` incorrectly when it's in an actual default argument.
362
+ entry ||= caller[1]
228
363
  info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first
229
364
  info[1] = info[1].to_i
230
365
  # This is added by Rubinius to designate a block, but we don't care about it.
@@ -278,6 +413,17 @@ module Sass
278
413
  raise NotImplementedError.new("#{obj.class} must implement ##{caller_info[2]}")
279
414
  end
280
415
 
416
+ # Prints a deprecation warning for the caller method.
417
+ #
418
+ # @param obj [Object] `self`
419
+ # @param message [String] A message describing what to do instead.
420
+ def deprecated(obj, message = nil)
421
+ obj_class = obj.is_a?(Class) ? "#{obj}." : "#{obj.class}#"
422
+ full_message = "DEPRECATION WARNING: #{obj_class}#{caller_info[2]} " +
423
+ "will be removed in a future version of Sass.#{("\n" + message) if message}"
424
+ Sass::Util.sass_warn full_message
425
+ end
426
+
281
427
  # Silence all output to STDERR within a block.
282
428
  #
283
429
  # @yield A block in which no output will be printed to STDERR
@@ -288,24 +434,22 @@ module Sass
288
434
  $stderr = the_real_stderr
289
435
  end
290
436
 
291
- @@silence_warnings = false
292
437
  # Silences all Sass warnings within a block.
293
438
  #
294
439
  # @yield A block in which no Sass warnings will be printed
295
440
  def silence_sass_warnings
296
- old_silence_warnings = @@silence_warnings
297
- @@silence_warnings = true
441
+ old_level, Sass.logger.log_level = Sass.logger.log_level, :error
298
442
  yield
299
443
  ensure
300
- @@silence_warnings = old_silence_warnings
444
+ Sass.logger.log_level = old_level
301
445
  end
302
446
 
303
447
  # The same as `Kernel#warn`, but is silenced by \{#silence\_sass\_warnings}.
304
448
  #
305
449
  # @param msg [String]
306
450
  def sass_warn(msg)
307
- return if @@silence_warnings
308
- warn(msg)
451
+ msg = msg + "\n" unless ruby1?
452
+ Sass.logger.warn(msg)
309
453
  end
310
454
 
311
455
  ## Cross Rails Version Compatibility
@@ -321,7 +465,7 @@ module Sass
321
465
  raise "ERROR: Rails.root is nil!"
322
466
  end
323
467
  return RAILS_ROOT.to_s if defined?(RAILS_ROOT)
324
- return nil
468
+ nil
325
469
  end
326
470
 
327
471
  # Returns the environment of the Rails application,
@@ -332,7 +476,7 @@ module Sass
332
476
  def rails_env
333
477
  return ::Rails.env.to_s if defined?(::Rails.env)
334
478
  return RAILS_ENV.to_s if defined?(RAILS_ENV)
335
- return nil
479
+ nil
336
480
  end
337
481
 
338
482
  # Returns whether this environment is using ActionPack
@@ -358,6 +502,15 @@ module Sass
358
502
  version_geq(ActionPack::VERSION::STRING, version)
359
503
  end
360
504
 
505
+ # Returns whether this environment is using Listen
506
+ # version 2.0.0 or greater.
507
+ #
508
+ # @return [Boolean]
509
+ def listen_geq_2?
510
+ require 'listen/version'
511
+ version_geq(::Listen::VERSION, '2.0.0')
512
+ end
513
+
361
514
  # Returns an ActionView::Template* class.
362
515
  # In pre-3.0 versions of Rails, most of these classes
363
516
  # were of the form `ActionView::TemplateFoo`,
@@ -368,27 +521,98 @@ module Sass
368
521
  # or `ActionView::Template::Error`.
369
522
  def av_template_class(name)
370
523
  return ActionView.const_get("Template#{name}") if ActionView.const_defined?("Template#{name}")
371
- return ActionView::Template.const_get(name.to_s)
524
+ ActionView::Template.const_get(name.to_s)
372
525
  end
373
526
 
374
527
  ## Cross-OS Compatibility
528
+ #
529
+ # These methods are cached because some of them are called quite frequently
530
+ # and even basic checks like String#== are too costly to be called repeatedly.
375
531
 
376
532
  # Whether or not this is running on Windows.
377
533
  #
378
534
  # @return [Boolean]
379
535
  def windows?
380
- RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i
536
+ return @windows if defined?(@windows)
537
+ @windows = (RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i)
381
538
  end
382
539
 
383
540
  # Whether or not this is running on IronRuby.
384
541
  #
385
542
  # @return [Boolean]
386
543
  def ironruby?
387
- RUBY_ENGINE == "ironruby"
544
+ return @ironruby if defined?(@ironruby)
545
+ @ironruby = RUBY_ENGINE == "ironruby"
546
+ end
547
+
548
+ # Whether or not this is running on Rubinius.
549
+ #
550
+ # @return [Boolean]
551
+ def rbx?
552
+ return @rbx if defined?(@rbx)
553
+ @rbx = RUBY_ENGINE == "rbx"
554
+ end
555
+
556
+ # Whether or not this is running on JRuby.
557
+ #
558
+ # @return [Boolean]
559
+ def jruby?
560
+ return @jruby if defined?(@jruby)
561
+ @jruby = RUBY_PLATFORM =~ /java/
562
+ end
563
+
564
+ # Returns an array of ints representing the JRuby version number.
565
+ #
566
+ # @return [Array<Fixnum>]
567
+ def jruby_version
568
+ @jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
569
+ end
570
+
571
+ # Like `Dir.glob`, but works with backslash-separated paths on Windows.
572
+ #
573
+ # @param path [String]
574
+ def glob(path)
575
+ path = path.gsub('\\', '/') if windows?
576
+ if block_given?
577
+ Dir.glob(path) {|f| yield(f)}
578
+ else
579
+ Dir.glob(path)
580
+ end
581
+ end
582
+
583
+ # Like `Pathname.new`, but normalizes Windows paths to always use backslash
584
+ # separators.
585
+ #
586
+ # `Pathname.relative_path_from` can break if the two pathnames aren't
587
+ # consistent in their slash style.
588
+ def pathname(path)
589
+ path = path.tr("/", "\\") if windows?
590
+ Pathname.new(path)
591
+ end
592
+
593
+ # Prepare a value for a destructuring assignment (e.g. `a, b =
594
+ # val`). This works around a performance bug when using
595
+ # ActiveSupport, and only needs to be called when `val` is likely
596
+ # to be `nil` reasonably often.
597
+ #
598
+ # See [this bug report](http://redmine.ruby-lang.org/issues/4917).
599
+ #
600
+ # @param val [Object]
601
+ # @return [Object]
602
+ def destructure(val)
603
+ val || []
388
604
  end
389
605
 
390
606
  ## Cross-Ruby-Version Compatibility
391
607
 
608
+ # Whether or not this is running under a Ruby version under 2.0.
609
+ #
610
+ # @return [Boolean]
611
+ def ruby1?
612
+ return @ruby1 if defined?(@ruby1)
613
+ @ruby1 = Sass::Util::RUBY_VERSION[0] <= 1
614
+ end
615
+
392
616
  # Whether or not this is running under Ruby 1.8 or lower.
393
617
  #
394
618
  # Note that IronRuby counts as Ruby 1.8,
@@ -398,7 +622,9 @@ module Sass
398
622
  def ruby1_8?
399
623
  # IronRuby says its version is 1.9, but doesn't support any of the encoding APIs.
400
624
  # We have to fall back to 1.8 behavior.
401
- ironruby? || (Sass::Util::RUBY_VERSION[0] == 1 && Sass::Util::RUBY_VERSION[1] < 9)
625
+ return @ruby1_8 if defined?(@ruby1_8)
626
+ @ruby1_8 = ironruby? ||
627
+ (Sass::Util::RUBY_VERSION[0] == 1 && Sass::Util::RUBY_VERSION[1] < 9)
402
628
  end
403
629
 
404
630
  # Whether or not this is running under Ruby 1.8.6 or lower.
@@ -406,7 +632,52 @@ module Sass
406
632
  #
407
633
  # @return [Boolean]
408
634
  def ruby1_8_6?
409
- ruby1_8? && Sass::Util::RUBY_VERSION[2] < 7
635
+ return @ruby1_8_6 if defined?(@ruby1_8_6)
636
+ @ruby1_8_6 = ruby1_8? && Sass::Util::RUBY_VERSION[2] < 7
637
+ end
638
+
639
+ # Wehter or not this is running under JRuby 1.6 or lower.
640
+ def jruby1_6?
641
+ return @jruby1_6 if defined?(@jruby1_6)
642
+ @jruby1_6 = jruby? && jruby_version[0] == 1 && jruby_version[1] < 7
643
+ end
644
+
645
+ # Whether or not this is running under MacRuby.
646
+ #
647
+ # @return [Boolean]
648
+ def macruby?
649
+ return @macruby if defined?(@macruby)
650
+ @macruby = RUBY_ENGINE == 'macruby'
651
+ end
652
+
653
+ require 'sass/util/ordered_hash' if ruby1_8?
654
+
655
+ # Converts a hash or a list of pairs into an order-preserving hash.
656
+ #
657
+ # On Ruby 1.8.7, this uses the orderedhash gem to simulate an
658
+ # order-preserving hash. On Ruby 1.9 and up, it just uses the native Hash
659
+ # class, since that preserves the order itself.
660
+ #
661
+ # @overload ordered_hash(hash)
662
+ # @param hash [Hash] a normal hash to convert to an ordered hash
663
+ # @return [Hash]
664
+ # @overload ordered_hash(*pairs)
665
+ # @example
666
+ # ordered_hash([:foo, "bar"], [:baz, "bang"])
667
+ # #=> {:foo => "bar", :baz => "bang"}
668
+ # ordered_hash #=> {}
669
+ # @param pairs [Array<(Object, Object)>] the list of key/value pairs for
670
+ # the hash.
671
+ # @return [Hash]
672
+ def ordered_hash(*pairs_or_hash)
673
+ if pairs_or_hash.length == 1 && pairs_or_hash.first.is_a?(Hash)
674
+ hash = pairs_or_hash.first
675
+ return hash unless ruby1_8?
676
+ return OrderedHash.new.merge hash
677
+ end
678
+
679
+ return Hash[pairs_or_hash] unless ruby1_8?
680
+ (pairs_or_hash.is_a?(NormalizedMap) ? NormalizedMap : OrderedHash)[*flatten(pairs_or_hash, 1)]
410
681
  end
411
682
 
412
683
  # Checks that the encoding of a string is valid in Ruby 1.9
@@ -438,11 +709,11 @@ module Sass
438
709
  line.encode(encoding)
439
710
  rescue Encoding::UndefinedConversionError => e
440
711
  yield <<MSG.rstrip, i + 1
441
- Invalid #{encoding.name} character #{e.error_char.dump}
712
+ Invalid #{encoding.name} character #{undefined_conversion_error_char(e)}
442
713
  MSG
443
714
  end
444
715
  end
445
- return str
716
+ str
446
717
  end
447
718
 
448
719
  # Like {\#check\_encoding}, but also checks for a `@charset` declaration
@@ -469,12 +740,13 @@ MSG
469
740
  # We allow any printable ASCII characters but double quotes in the charset decl
470
741
  bin = str.dup.force_encoding("BINARY")
471
742
  encoding = Sass::Util::ENCODINGS_TO_CHECK.find do |enc|
472
- bin =~ Sass::Util::CHARSET_REGEXPS[enc]
743
+ re = Sass::Util::CHARSET_REGEXPS[enc]
744
+ re && bin =~ re
473
745
  end
474
746
  charset, bom = $1, $2
475
747
  if charset
476
748
  charset = charset.force_encoding(encoding).encode("UTF-8")
477
- if endianness = encoding[/[BL]E$/]
749
+ if (endianness = encoding[/[BL]E$/])
478
750
  begin
479
751
  Encoding.find(charset + endianness)
480
752
  charset << endianness
@@ -510,6 +782,8 @@ MSG
510
782
  Regexp.new(/\A(?:#{_enc("\uFEFF", e)})?#{
511
783
  _enc('@charset "', e)}(.*?)#{_enc('"', e)}|\A(#{
512
784
  _enc("\uFEFF", e)})/)
785
+ rescue Encoding::ConverterNotFoundError => _
786
+ nil # JRuby on Java 5 doesn't support UTF-32
513
787
  rescue
514
788
  # /\A@charset "(.*?)"/
515
789
  Regexp.new(/\A#{_enc('@charset "', e)}(.*?)#{_enc('"', e)}/)
@@ -561,6 +835,24 @@ MSG
561
835
  ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
562
836
  end
563
837
 
838
+ # Destructively removes all elements from an array that match a block, and
839
+ # returns the removed elements.
840
+ #
841
+ # @param array [Array] The array from which to remove elements.
842
+ # @yield [el] Called for each element.
843
+ # @yieldparam el [*] The element to test.
844
+ # @yieldreturn [Boolean] Whether or not to extract the element.
845
+ # @return [Array] The extracted elements.
846
+ def extract!(array)
847
+ out = []
848
+ array.reject! do |e|
849
+ next false unless yield e
850
+ out << e
851
+ true
852
+ end
853
+ out
854
+ end
855
+
564
856
  # Returns the ASCII code of the given character.
565
857
  #
566
858
  # @param c [String] All characters but the first are ignored.
@@ -580,6 +872,24 @@ MSG
580
872
  arr.inject([]) {|res, e| e.is_a?(Array) ? res.concat(flatten(e, n - 1)) : res << e}
581
873
  end
582
874
 
875
+ # Flattens the first level of nested arrays in `arrs`. Unlike
876
+ # `Array#flatten`, this orders the result by taking the first
877
+ # values from each array in order, then the second, and so on.
878
+ #
879
+ # @param arrs [Array] The array to flatten.
880
+ # @return [Array] The flattened array.
881
+ def flatten_vertically(arrs)
882
+ result = []
883
+ arrs = arrs.map {|sub| sub.is_a?(Array) ? sub.dup : Array(sub)}
884
+ until arrs.empty?
885
+ arrs.reject! do |arr|
886
+ result << arr.shift
887
+ arr.empty?
888
+ end
889
+ end
890
+ result
891
+ end
892
+
583
893
  # Returns the hash code for a set in a cross-version manner.
584
894
  # Aggravatingly, this is order-dependent in Ruby 1.8.6.
585
895
  #
@@ -601,8 +911,9 @@ MSG
601
911
  set1.to_a.uniq.sort_by {|e| e.hash}.eql?(set2.to_a.uniq.sort_by {|e| e.hash})
602
912
  end
603
913
 
604
- # Like `Object#inspect`, but preserves non-ASCII characters rather than escaping them under Ruby 1.9.2.
605
- # This is necessary so that the precompiled Haml template can be `#encode`d into `@options[:encoding]`
914
+ # Like `Object#inspect`, but preserves non-ASCII characters rather than
915
+ # escaping them under Ruby 1.9.2. This is necessary so that the
916
+ # precompiled Haml template can be `#encode`d into `@options[:encoding]`
606
917
  # before being evaluated.
607
918
  #
608
919
  # @param obj {Object}
@@ -614,6 +925,181 @@ MSG
614
925
  '"' + obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]} + '"'
615
926
  end
616
927
 
928
+ # Extracts the non-string vlaues from an array containing both strings and non-strings.
929
+ # These values are replaced with escape sequences.
930
+ # This can be undone using \{#inject\_values}.
931
+ #
932
+ # This is useful e.g. when we want to do string manipulation
933
+ # on an interpolated string.
934
+ #
935
+ # The precise format of the resulting string is not guaranteed.
936
+ # However, it is guaranteed that newlines and whitespace won't be affected.
937
+ #
938
+ # @param arr [Array] The array from which values are extracted.
939
+ # @return [(String, Array)] The resulting string, and an array of extracted values.
940
+ def extract_values(arr)
941
+ values = []
942
+ mapped = arr.map do |e|
943
+ next e.gsub('{', '{{') if e.is_a?(String)
944
+ values << e
945
+ next "{#{values.count - 1}}"
946
+ end
947
+ return mapped.join, values
948
+ end
949
+
950
+ # Undoes \{#extract\_values} by transforming a string with escape sequences
951
+ # into an array of strings and non-string values.
952
+ #
953
+ # @param str [String] The string with escape sequences.
954
+ # @param values [Array] The array of values to inject.
955
+ # @return [Array] The array of strings and values.
956
+ def inject_values(str, values)
957
+ return [str.gsub('{{', '{')] if values.empty?
958
+ # Add an extra { so that we process the tail end of the string
959
+ result = (str + '{{').scan(/(.*?)(?:(\{\{)|\{(\d+)\})/m).map do |(pre, esc, n)|
960
+ [pre, esc ? '{' : '', n ? values[n.to_i] : '']
961
+ end.flatten(1)
962
+ result[-2] = '' # Get rid of the extra {
963
+ merge_adjacent_strings(result).reject {|s| s == ''}
964
+ end
965
+
966
+ # Allows modifications to be performed on the string form
967
+ # of an array containing both strings and non-strings.
968
+ #
969
+ # @param arr [Array] The array from which values are extracted.
970
+ # @yield [str] A block in which string manipulation can be done to the array.
971
+ # @yieldparam str [String] The string form of `arr`.
972
+ # @yieldreturn [String] The modified string.
973
+ # @return [Array] The modified, interpolated array.
974
+ def with_extracted_values(arr)
975
+ str, vals = extract_values(arr)
976
+ str = yield str
977
+ inject_values(str, vals)
978
+ end
979
+
980
+ # Builds a sourcemap file name given the generated CSS file name.
981
+ #
982
+ # @param css [String] The generated CSS file name.
983
+ # @return [String] The source map file name.
984
+ def sourcemap_name(css)
985
+ css + ".map"
986
+ end
987
+
988
+ # Escapes certain characters so that the result can be used
989
+ # as the JSON string value. Returns the original string if
990
+ # no escaping is necessary.
991
+ #
992
+ # @param s [String] The string to be escaped
993
+ # @return [String] The escaped string
994
+ def json_escape_string(s)
995
+ return s if s !~ /["\\\b\f\n\r\t]/
996
+
997
+ result = ""
998
+ s.split("").each do |c|
999
+ case c
1000
+ when '"', "\\"
1001
+ result << "\\" << c
1002
+ when "\n" then result << "\\n"
1003
+ when "\t" then result << "\\t"
1004
+ when "\r" then result << "\\r"
1005
+ when "\f" then result << "\\f"
1006
+ when "\b" then result << "\\b"
1007
+ else
1008
+ result << c
1009
+ end
1010
+ end
1011
+ result
1012
+ end
1013
+
1014
+ # Converts the argument into a valid JSON value.
1015
+ #
1016
+ # @param v [Fixnum, String, Array, Boolean, nil]
1017
+ # @return [String]
1018
+ def json_value_of(v)
1019
+ case v
1020
+ when Fixnum
1021
+ v.to_s
1022
+ when String
1023
+ "\"" + json_escape_string(v) + "\""
1024
+ when Array
1025
+ "[" + v.map {|x| json_value_of(x)}.join(",") + "]"
1026
+ when NilClass
1027
+ "null"
1028
+ when TrueClass
1029
+ "true"
1030
+ when FalseClass
1031
+ "false"
1032
+ else
1033
+ raise ArgumentError.new("Unknown type: #{v.class.name}")
1034
+ end
1035
+ end
1036
+
1037
+ VLQ_BASE_SHIFT = 5
1038
+ VLQ_BASE = 1 << VLQ_BASE_SHIFT
1039
+ VLQ_BASE_MASK = VLQ_BASE - 1
1040
+ VLQ_CONTINUATION_BIT = VLQ_BASE
1041
+
1042
+ BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
1043
+ BASE64_DIGIT_MAP = begin
1044
+ map = {}
1045
+ Sass::Util.enum_with_index(BASE64_DIGITS).map do |digit, i|
1046
+ map[digit] = i
1047
+ end
1048
+ map
1049
+ end
1050
+
1051
+ # Encodes `value` as VLQ (http://en.wikipedia.org/wiki/VLQ).
1052
+ #
1053
+ # @param value [Fixnum]
1054
+ # @return [String] The encoded value
1055
+ def encode_vlq(value)
1056
+ if value < 0
1057
+ value = ((-value) << 1) | 1
1058
+ else
1059
+ value <<= 1
1060
+ end
1061
+
1062
+ result = ''
1063
+ begin
1064
+ digit = value & VLQ_BASE_MASK
1065
+ value >>= VLQ_BASE_SHIFT
1066
+ if value > 0
1067
+ digit |= VLQ_CONTINUATION_BIT
1068
+ end
1069
+ result << BASE64_DIGITS[digit]
1070
+ end while value > 0
1071
+ result
1072
+ end
1073
+
1074
+ # This is a hack around the fact that you can't instantiate a URI parser on
1075
+ # 1.8, so we have to have this hacky stuff to work around it. When 1.8
1076
+ # support is dropped, we can remove this method.
1077
+ #
1078
+ # @private
1079
+ URI_ESCAPE = URI.const_defined?("DEFAULT_PARSER") ? URI::DEFAULT_PARSER : URI
1080
+
1081
+ # URI-escape `string`.
1082
+ #
1083
+ # @param string [String]
1084
+ # @return [String]
1085
+ def escape_uri(string)
1086
+ URI_ESCAPE.escape string
1087
+ end
1088
+
1089
+ # A cross-platform implementation of `File.absolute_path`.
1090
+ #
1091
+ # @param path [String]
1092
+ # @param dir_string [String] The directory to consider [path] relative to.
1093
+ # @return [String] The absolute version of `path`.
1094
+ def absolute_path(path, dir_string = nil)
1095
+ # Ruby 1.8 doesn't support File.absolute_path.
1096
+ return File.absolute_path(path, dir_string) unless ruby1_8?
1097
+
1098
+ # File.expand_path expands "~", which we don't want.
1099
+ return File.expand_path(path, dir_string) unless path[0] == ?~
1100
+ File.expand_path(File.join(".", path), dir_string)
1101
+ end
1102
+
617
1103
  ## Static Method Stuff
618
1104
 
619
1105
  # The context in which the ERB for \{#def\_static\_method} will be run.
@@ -627,17 +1113,49 @@ MSG
627
1113
  #
628
1114
  # @param name [Symbol] The name of the variable
629
1115
  # @return [Boolean]
630
- def method_missing(name, *args, &block)
631
- super unless args.empty? && block.nil?
1116
+ def method_missing(name, *args)
1117
+ super unless args.empty? && !block_given?
632
1118
  @set.include?(name)
633
1119
  end
634
1120
  end
635
1121
 
1122
+ # @private
1123
+ ATOMIC_WRITE_MUTEX = Mutex.new
1124
+
1125
+ # This creates a temp file and yields it for writing. When the
1126
+ # write is complete, the file is moved into the desired location.
1127
+ # The atomicity of this operation is provided by the filesystem's
1128
+ # rename operation.
1129
+ #
1130
+ # @param filename [String] The file to write to.
1131
+ # @yieldparam tmpfile [Tempfile] The temp file that can be written to.
1132
+ # @return The value returned by the block.
1133
+ def atomic_create_and_write_file(filename)
1134
+ require 'tempfile'
1135
+ tmpfile = Tempfile.new(File.basename(filename), File.dirname(filename))
1136
+ tmpfile.binmode if tmpfile.respond_to?(:binmode)
1137
+ result = yield tmpfile
1138
+ tmpfile.close
1139
+ ATOMIC_WRITE_MUTEX.synchronize do
1140
+ File.rename tmpfile.path, filename
1141
+ end
1142
+ result
1143
+ ensure
1144
+ # close and remove the tempfile if it still exists,
1145
+ # presumably due to an error during write
1146
+ tmpfile.close if tmpfile
1147
+ tmpfile.unlink if tmpfile
1148
+ end
1149
+
636
1150
  private
637
1151
 
1152
+ # rubocop:disable LineLength
1153
+
638
1154
  # Calculates the memoization table for the Least Common Subsequence algorithm.
639
1155
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS)
640
1156
  def lcs_table(x, y)
1157
+ # This method does not take a block as an explicit parameter for performance reasons.
1158
+ # rubocop:enable LineLength
641
1159
  c = Array.new(x.size) {[]}
642
1160
  x.size.times {|i| c[i][0] = 0}
643
1161
  y.size.times {|j| c[0][j] = 0}
@@ -645,25 +1163,33 @@ MSG
645
1163
  (1...y.size).each do |j|
646
1164
  c[i][j] =
647
1165
  if yield x[i], y[j]
648
- c[i-1][j-1] + 1
1166
+ c[i - 1][j - 1] + 1
649
1167
  else
650
- [c[i][j-1], c[i-1][j]].max
1168
+ [c[i][j - 1], c[i - 1][j]].max
651
1169
  end
652
1170
  end
653
1171
  end
654
- return c
1172
+ c
655
1173
  end
1174
+ # rubocop:disable ParameterLists, LineLength
656
1175
 
657
1176
  # Computes a single longest common subsequence for arrays x and y.
658
1177
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
659
1178
  def lcs_backtrace(c, x, y, i, j, &block)
1179
+ # rubocop:enable ParameterList, LineLengths
660
1180
  return [] if i == 0 || j == 0
661
- if v = yield(x[i], y[j])
662
- return lcs_backtrace(c, x, y, i-1, j-1, &block) << v
1181
+ if (v = yield(x[i], y[j]))
1182
+ return lcs_backtrace(c, x, y, i - 1, j - 1, &block) << v
663
1183
  end
664
1184
 
665
- return lcs_backtrace(c, x, y, i, j-1, &block) if c[i][j-1] > c[i-1][j]
666
- return lcs_backtrace(c, x, y, i-1, j, &block)
1185
+ return lcs_backtrace(c, x, y, i, j - 1, &block) if c[i][j - 1] > c[i - 1][j]
1186
+ lcs_backtrace(c, x, y, i - 1, j, &block)
667
1187
  end
1188
+
1189
+ singleton_methods.each {|method| module_function method}
668
1190
  end
669
1191
  end
1192
+
1193
+ require 'sass/util/multibyte_string_scanner'
1194
+ require 'sass/util/normalized_map'
1195
+ require 'sass/util/cross_platform_random'