sass 3.2.7 → 3.3.0.rc.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 (184) hide show
  1. data/MIT-LICENSE +2 -2
  2. data/README.md +14 -2
  3. data/Rakefile +25 -1
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/lib/sass/cache_stores/base.rb +4 -2
  8. data/lib/sass/cache_stores/chain.rb +2 -1
  9. data/lib/sass/cache_stores/filesystem.rb +2 -6
  10. data/lib/sass/cache_stores/memory.rb +1 -1
  11. data/lib/sass/cache_stores/null.rb +2 -2
  12. data/lib/sass/callbacks.rb +1 -0
  13. data/lib/sass/css.rb +10 -10
  14. data/lib/sass/engine.rb +403 -150
  15. data/lib/sass/environment.rb +136 -57
  16. data/lib/sass/error.rb +7 -7
  17. data/lib/sass/exec.rb +123 -39
  18. data/lib/sass/features.rb +41 -0
  19. data/lib/sass/importers/base.rb +33 -2
  20. data/lib/sass/importers/deprecated_path.rb +45 -0
  21. data/lib/sass/importers/filesystem.rb +25 -14
  22. data/lib/sass/importers.rb +1 -0
  23. data/lib/sass/logger/base.rb +3 -3
  24. data/lib/sass/logger/log_level.rb +4 -6
  25. data/lib/sass/media.rb +19 -19
  26. data/lib/sass/plugin/compiler.rb +141 -101
  27. data/lib/sass/plugin/configuration.rb +18 -22
  28. data/lib/sass/plugin/merb.rb +1 -1
  29. data/lib/sass/plugin/staleness_checker.rb +24 -8
  30. data/lib/sass/plugin.rb +4 -2
  31. data/lib/sass/repl.rb +3 -3
  32. data/lib/sass/script/css_lexer.rb +9 -4
  33. data/lib/sass/script/css_parser.rb +6 -2
  34. data/lib/sass/script/functions.rb +1343 -590
  35. data/lib/sass/script/lexer.rb +84 -52
  36. data/lib/sass/script/parser.rb +217 -97
  37. data/lib/sass/script/tree/funcall.rb +290 -0
  38. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +34 -13
  39. data/lib/sass/script/tree/list_literal.rb +80 -0
  40. data/lib/sass/script/tree/literal.rb +47 -0
  41. data/lib/sass/script/tree/map_literal.rb +64 -0
  42. data/lib/sass/script/{node.rb → tree/node.rb} +22 -12
  43. data/lib/sass/script/{operation.rb → tree/operation.rb} +17 -25
  44. data/lib/sass/script/tree/selector.rb +30 -0
  45. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +5 -4
  46. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +14 -9
  47. data/lib/sass/script/tree/variable.rb +57 -0
  48. data/lib/sass/script/tree.rb +16 -0
  49. data/lib/sass/script/{arg_list.rb → value/arg_list.rb} +4 -24
  50. data/lib/sass/script/value/base.rb +248 -0
  51. data/lib/sass/script/value/bool.rb +36 -0
  52. data/lib/sass/script/{color.rb → value/color.rb} +239 -195
  53. data/lib/sass/script/value/helpers.rb +155 -0
  54. data/lib/sass/script/value/list.rb +119 -0
  55. data/lib/sass/script/value/map.rb +70 -0
  56. data/lib/sass/script/value/null.rb +45 -0
  57. data/lib/sass/script/{number.rb → value/number.rb} +91 -65
  58. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  59. data/lib/sass/script/value.rb +11 -0
  60. data/lib/sass/script.rb +35 -8
  61. data/lib/sass/scss/css_parser.rb +2 -1
  62. data/lib/sass/scss/parser.rb +338 -170
  63. data/lib/sass/scss/rx.rb +5 -6
  64. data/lib/sass/scss/script_lexer.rb +1 -0
  65. data/lib/sass/scss/script_parser.rb +1 -0
  66. data/lib/sass/scss/static_parser.rb +23 -6
  67. data/lib/sass/selector/abstract_sequence.rb +2 -2
  68. data/lib/sass/selector/comma_sequence.rb +21 -16
  69. data/lib/sass/selector/sequence.rb +60 -34
  70. data/lib/sass/selector/simple.rb +11 -12
  71. data/lib/sass/selector/simple_sequence.rb +55 -33
  72. data/lib/sass/selector.rb +52 -48
  73. data/lib/sass/source/map.rb +211 -0
  74. data/lib/sass/source/position.rb +39 -0
  75. data/lib/sass/source/range.rb +41 -0
  76. data/lib/sass/stack.rb +120 -0
  77. data/lib/sass/supports.rb +12 -13
  78. data/lib/sass/tree/at_root_node.rb +82 -0
  79. data/lib/sass/tree/comment_node.rb +3 -3
  80. data/lib/sass/tree/css_import_node.rb +11 -11
  81. data/lib/sass/tree/debug_node.rb +2 -2
  82. data/lib/sass/tree/directive_node.rb +13 -2
  83. data/lib/sass/tree/each_node.rb +8 -8
  84. data/lib/sass/tree/extend_node.rb +13 -6
  85. data/lib/sass/tree/for_node.rb +4 -4
  86. data/lib/sass/tree/function_node.rb +5 -4
  87. data/lib/sass/tree/if_node.rb +1 -1
  88. data/lib/sass/tree/import_node.rb +4 -5
  89. data/lib/sass/tree/media_node.rb +4 -14
  90. data/lib/sass/tree/mixin_def_node.rb +4 -4
  91. data/lib/sass/tree/mixin_node.rb +21 -8
  92. data/lib/sass/tree/node.rb +29 -12
  93. data/lib/sass/tree/prop_node.rb +38 -18
  94. data/lib/sass/tree/return_node.rb +3 -2
  95. data/lib/sass/tree/root_node.rb +19 -3
  96. data/lib/sass/tree/rule_node.rb +25 -17
  97. data/lib/sass/tree/supports_node.rb +0 -13
  98. data/lib/sass/tree/trace_node.rb +2 -1
  99. data/lib/sass/tree/variable_node.rb +9 -3
  100. data/lib/sass/tree/visitors/base.rb +6 -6
  101. data/lib/sass/tree/visitors/check_nesting.rb +12 -9
  102. data/lib/sass/tree/visitors/convert.rb +63 -38
  103. data/lib/sass/tree/visitors/cssize.rb +63 -23
  104. data/lib/sass/tree/visitors/deep_copy.rb +6 -5
  105. data/lib/sass/tree/visitors/extend.rb +7 -7
  106. data/lib/sass/tree/visitors/perform.rb +256 -151
  107. data/lib/sass/tree/visitors/set_options.rb +6 -6
  108. data/lib/sass/tree/visitors/to_css.rb +231 -81
  109. data/lib/sass/tree/warn_node.rb +2 -2
  110. data/lib/sass/tree/while_node.rb +2 -2
  111. data/lib/sass/util/multibyte_string_scanner.rb +2 -0
  112. data/lib/sass/util/normalized_map.rb +65 -0
  113. data/lib/sass/util/ordered_hash.rb +188 -0
  114. data/lib/sass/util/subset_map.rb +3 -2
  115. data/lib/sass/util/test.rb +9 -0
  116. data/lib/sass/util.rb +220 -34
  117. data/lib/sass/version.rb +9 -9
  118. data/lib/sass.rb +14 -7
  119. data/test/sass/compiler_test.rb +213 -0
  120. data/test/sass/conversion_test.rb +235 -9
  121. data/test/sass/engine_test.rb +230 -60
  122. data/test/sass/exec_test.rb +86 -0
  123. data/test/sass/extend_test.rb +215 -147
  124. data/test/sass/functions_test.rb +584 -99
  125. data/test/sass/importer_test.rb +165 -17
  126. data/test/sass/plugin_test.rb +19 -13
  127. data/test/sass/script_conversion_test.rb +40 -0
  128. data/test/sass/script_test.rb +231 -21
  129. data/test/sass/scss/css_test.rb +14 -5
  130. data/test/sass/scss/scss_test.rb +1266 -66
  131. data/test/sass/source_map_test.rb +879 -0
  132. data/test/sass/templates/bork5.sass +3 -0
  133. data/test/sass/util/normalized_map_test.rb +30 -0
  134. data/test/sass/util_test.rb +90 -0
  135. data/test/sass/value_helpers_test.rb +181 -0
  136. data/test/test_helper.rb +7 -2
  137. metadata +316 -291
  138. data/lib/sass/script/bool.rb +0 -18
  139. data/lib/sass/script/funcall.rb +0 -231
  140. data/lib/sass/script/list.rb +0 -84
  141. data/lib/sass/script/literal.rb +0 -239
  142. data/lib/sass/script/null.rb +0 -34
  143. data/lib/sass/script/variable.rb +0 -58
  144. data/test/Gemfile +0 -3
  145. data/vendor/listen/CHANGELOG.md +0 -221
  146. data/vendor/listen/CONTRIBUTING.md +0 -38
  147. data/vendor/listen/Gemfile +0 -30
  148. data/vendor/listen/Guardfile +0 -8
  149. data/vendor/listen/LICENSE +0 -20
  150. data/vendor/listen/README.md +0 -315
  151. data/vendor/listen/Rakefile +0 -47
  152. data/vendor/listen/Vagrantfile +0 -96
  153. data/vendor/listen/lib/listen/adapter.rb +0 -214
  154. data/vendor/listen/lib/listen/adapters/bsd.rb +0 -112
  155. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -85
  156. data/vendor/listen/lib/listen/adapters/linux.rb +0 -113
  157. data/vendor/listen/lib/listen/adapters/polling.rb +0 -67
  158. data/vendor/listen/lib/listen/adapters/windows.rb +0 -87
  159. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  160. data/vendor/listen/lib/listen/directory_record.rb +0 -371
  161. data/vendor/listen/lib/listen/listener.rb +0 -225
  162. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  163. data/vendor/listen/lib/listen/turnstile.rb +0 -28
  164. data/vendor/listen/lib/listen/version.rb +0 -3
  165. data/vendor/listen/lib/listen.rb +0 -40
  166. data/vendor/listen/listen.gemspec +0 -22
  167. data/vendor/listen/spec/listen/adapter_spec.rb +0 -183
  168. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
  169. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
  170. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
  171. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  172. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
  173. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  174. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1225
  175. data/vendor/listen/spec/listen/listener_spec.rb +0 -169
  176. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
  177. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  178. data/vendor/listen/spec/listen_spec.rb +0 -73
  179. data/vendor/listen/spec/spec_helper.rb +0 -21
  180. data/vendor/listen/spec/support/adapter_helper.rb +0 -629
  181. data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
  182. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  183. data/vendor/listen/spec/support/listeners_helper.rb +0 -156
  184. data/vendor/listen/spec/support/platform_helper.rb +0 -15
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'pathname'
2
3
 
3
4
  require 'sass'
4
5
  # XXX CE: is this still necessary now that we have the compiler class?
@@ -32,10 +33,10 @@ module Sass::Plugin
32
33
 
33
34
  # Creates a new compiler.
34
35
  #
35
- # @param options [{Symbol => Object}]
36
+ # @param opts [{Symbol => Object}]
36
37
  # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
37
- def initialize(options = {})
38
- self.options.merge!(options)
38
+ def initialize(opts = {})
39
+ options.merge!(opts)
39
40
  end
40
41
 
41
42
  # Register a callback to be run after stylesheets are mass-updated.
@@ -65,31 +66,10 @@ module Sass::Plugin
65
66
  # The location of the Sass/SCSS file being updated.
66
67
  # @yieldparam css [String]
67
68
  # The location of the CSS file being generated.
69
+ # @yieldparam sourcemap [String]
70
+ # The location of the sourcemap being generated, if any.
68
71
  define_callback :updated_stylesheet
69
72
 
70
- # Register a callback to be run before a single stylesheet is updated.
71
- # The callback is only run if the stylesheet is guaranteed to be updated;
72
- # if the CSS file is fresh, this won't be run.
73
- #
74
- # Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
75
- # is enabled, this callback won't be run
76
- # when an exception CSS file is being written.
77
- # To run an action for those files, use \{#on\_compilation\_error}.
78
- #
79
- # @yield [template, css]
80
- # @yieldparam template [String]
81
- # The location of the Sass/SCSS file being updated.
82
- # @yieldparam css [String]
83
- # The location of the CSS file being generated.
84
- define_callback :updating_stylesheet
85
-
86
- def on_updating_stylesheet_with_deprecation_warning(&block)
87
- Sass::Util.sass_warn("Sass::Compiler#on_updating_stylesheet callback is deprecated and will be removed in a future release. Use Sass::Compiler#on_updated_stylesheet instead, which is run after stylesheet compilation.")
88
- on_updating_stylesheet_without_deprecation_warning(&block)
89
- end
90
- alias_method :on_updating_stylesheet_without_deprecation_warning, :on_updating_stylesheet
91
- alias_method :on_updating_stylesheet, :on_updating_stylesheet_with_deprecation_warning
92
-
93
73
  # Register a callback to be run when Sass decides not to update a stylesheet.
94
74
  # In particular, the callback is run when Sass finds that
95
75
  # the template file and none of its dependencies
@@ -169,9 +149,18 @@ module Sass::Plugin
169
149
  # The location of the CSS file that was deleted.
170
150
  define_callback :deleting_css
171
151
 
152
+ # Register a callback to be run when Sass deletes a sourcemap file.
153
+ # This happens when the corresponding Sass/SCSS file has been deleted.
154
+ #
155
+ # @yield [filename]
156
+ # @yieldparam filename [String]
157
+ # The location of the sourcemap file that was deleted.
158
+ define_callback :deleting_sourcemap
159
+
172
160
  # Updates out-of-date stylesheets.
173
161
  #
174
- # Checks each Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`}
162
+ # Checks each Sass/SCSS file in
163
+ # {file:SASS_REFERENCE.md#template_location-option `:template_location`}
175
164
  # to see if it's been modified more recently than the corresponding CSS file
176
165
  # in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
177
166
  # If it has, it updates the CSS file.
@@ -192,17 +181,17 @@ module Sass::Plugin
192
181
  # Get the relative path to the file
193
182
  name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
194
183
  css = css_filename(name, css_location)
195
- individual_files << [file, css]
184
+ sourcemap = Sass::Util.sourcemap_name(css) if engine_options[:sourcemap]
185
+ individual_files << [file, css, sourcemap]
196
186
  end
197
187
  end
198
188
 
199
- run_updating_stylesheets individual_files
200
-
201
- individual_files.each do |file, css|
189
+ individual_files.each do |file, css, sourcemap|
190
+ # TODO: Does staleness_checker need to check the sourcemap file as well?
202
191
  if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
203
- update_stylesheet(file, css)
192
+ update_stylesheet(file, css, sourcemap)
204
193
  else
205
- run_not_updating_stylesheet(file, css)
194
+ run_not_updating_stylesheet(file, css, sourcemap)
206
195
  end
207
196
  end
208
197
  end
@@ -234,80 +223,72 @@ module Sass::Plugin
234
223
  def watch(individual_files = [])
235
224
  update_stylesheets(individual_files)
236
225
 
237
- begin
238
- require 'listen'
239
- rescue LoadError => e
240
- dir = Sass::Util.scope("vendor/listen/lib")
241
- if $LOAD_PATH.include?(dir)
242
- e.message << "\n" <<
243
- if File.exists?(scope(".git"))
244
- 'Run "git submodule update --init" to get the recommended version.'
245
- else
246
- 'Run "gem install listen" to get it.'
247
- end
248
- raise e
249
- else
250
- $LOAD_PATH.unshift dir
251
- retry
252
- end
226
+ directories = watched_paths
227
+ individual_files.each do |(source, _, _)|
228
+ directories << File.dirname(File.expand_path(source))
253
229
  end
254
-
255
- template_paths = template_locations # cache the locations
256
- individual_files_hash = individual_files.inject({}) do |h, files|
257
- parent = File.dirname(files.first)
258
- (h[parent] ||= []) << files unless template_paths.include?(parent)
259
- h
260
- end
261
- directories = template_paths + individual_files_hash.keys +
262
- [{:relative_paths => true}]
230
+ directories = remove_redundant_directories(directories)
263
231
 
264
232
  # TODO: Keep better track of what depends on what
265
233
  # so we don't have to run a global update every time anything changes.
266
- listener = Listen::MultiListener.new(*directories) do |modified, added, removed|
267
- modified.each do |f|
268
- parent = File.dirname(f)
269
- if files = individual_files_hash[parent]
270
- next unless files.first == f
271
- else
272
- next unless f =~ /\.s[ac]ss$/
273
- end
274
- run_template_modified(f)
234
+ listener_args = directories + [{:relative_paths => false}]
235
+ listener = create_listener(*listener_args) do |modified, added, removed|
236
+ recompile_required = false
237
+
238
+ modified.uniq.each do |f|
239
+ next unless watched_file?(f)
240
+ recompile_required = true
241
+ run_template_modified(relative_to_pwd(f))
275
242
  end
276
243
 
277
- added.each do |f|
278
- parent = File.dirname(f)
279
- if files = individual_files_hash[parent]
280
- next unless files.first == f
281
- else
282
- next unless f =~ /\.s[ac]ss$/
283
- end
284
- run_template_created(f)
244
+ added.uniq.each do |f|
245
+ next unless watched_file?(f)
246
+ recompile_required = true
247
+ run_template_created(relative_to_pwd(f))
285
248
  end
286
249
 
287
- removed.each do |f|
288
- parent = File.dirname(f)
289
- if files = individual_files_hash[parent]
290
- next unless files.first == f
250
+ removed.uniq.each do |f|
251
+ if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
252
+ recompile_required = true
253
+ # This was a file we were watching explicitly and compiling to a particular location.
254
+ # Delete the corresponding file.
291
255
  try_delete_css files[1]
292
256
  else
293
- next unless f =~ /\.s[ac]ss$/
294
- try_delete_css f.gsub(/\.s[ac]ss$/, '.css')
257
+ next unless watched_file?(f)
258
+ recompile_required = true
259
+ # Look for the sass directory that contained the sass file
260
+ # And try to remove the css file that corresponds to it
261
+ template_location_array.each do |(sass_dir, css_dir)|
262
+ sass_dir = File.expand_path(sass_dir)
263
+ if child_of_directory?(sass_dir, f)
264
+ remainder = f[(sass_dir.size + 1)..-1]
265
+ try_delete_css(css_filename(remainder, css_dir))
266
+ break
267
+ end
268
+ end
295
269
  end
296
- run_template_deleted(f)
270
+ run_template_deleted(relative_to_pwd(f))
297
271
  end
298
272
 
299
- update_stylesheets(individual_files)
273
+ if recompile_required
274
+ # In case a file we're watching is removed and then recreated we
275
+ # prune out the non-existant files here.
276
+ watched_files_remaining = individual_files.select {|(source, _, _)| File.exists?(source)}
277
+ update_stylesheets(watched_files_remaining)
278
+ end
300
279
  end
301
280
 
302
- # The native windows listener is much slower than the polling
303
- # option, according to https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e#commitcomment-1295118
281
+ # The native windows listener is much slower than the polling option, according to
282
+ # https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
304
283
  listener.force_polling(true) if @options[:poll] || Sass::Util.windows?
305
284
 
285
+ # rubocop:disable RescueException
306
286
  begin
307
- listener.start
287
+ listener.start!
308
288
  rescue Exception => e
309
289
  raise e unless e.is_a?(Interrupt)
310
290
  end
291
+ # rubocop:enable RescueException
311
292
  end
312
293
 
313
294
  # Non-destructively modifies \{#options} so that default values are properly set,
@@ -328,7 +309,28 @@ module Sass::Plugin
328
309
 
329
310
  private
330
311
 
331
- def update_stylesheet(filename, css)
312
+ def create_listener(*args, &block)
313
+ require 'listen'
314
+ Listen::Listener.new(*args, &block)
315
+ end
316
+
317
+ def remove_redundant_directories(directories)
318
+ dedupped = []
319
+ directories.each do |new_directory|
320
+ # no need to add a directory that is already watched.
321
+ next if dedupped.any? do |existing_directory|
322
+ child_of_directory?(existing_directory, new_directory)
323
+ end
324
+ # get rid of any sub directories of this new directory
325
+ dedupped.reject! do |existing_directory|
326
+ child_of_directory?(new_directory, existing_directory)
327
+ end
328
+ dedupped << new_directory
329
+ end
330
+ dedupped
331
+ end
332
+
333
+ def update_stylesheet(filename, css, sourcemap)
332
334
  dir = File.dirname(css)
333
335
  unless File.exists?(dir)
334
336
  run_creating_directory dir
@@ -338,32 +340,58 @@ module Sass::Plugin
338
340
  begin
339
341
  File.read(filename) unless File.readable?(filename) # triggers an error for handling
340
342
  engine_opts = engine_options(:css_filename => css, :filename => filename)
341
- result = Sass::Engine.for_file(filename, engine_opts).render
342
- rescue Exception => e
343
+ mapping = nil
344
+ engine = Sass::Engine.for_file(filename, engine_opts)
345
+ if sourcemap
346
+ rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
347
+ else
348
+ rendered = engine.render
349
+ end
350
+ rescue StandardError => e
343
351
  compilation_error_occured = true
344
- run_compilation_error e, filename, css
345
- result = Sass::SyntaxError.exception_to_css(e, options)
346
- else
347
- run_updating_stylesheet filename, css
352
+ run_compilation_error e, filename, css, sourcemap
353
+ rendered = Sass::SyntaxError.exception_to_css(e, options)
348
354
  end
349
355
 
350
- write_file(css, result)
351
- run_updated_stylesheet(filename, css) unless compilation_error_occured
356
+ write_file(css, rendered)
357
+ if mapping
358
+ write_file(sourcemap, mapping.to_json(:css_path => css, :sourcemap_path => sourcemap))
359
+ end
360
+ run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
352
361
  end
353
362
 
354
- def write_file(css, content)
363
+ def write_file(fileName, content)
355
364
  flag = 'w'
356
365
  flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
357
- File.open(css, flag) do |file|
366
+ File.open(fileName, flag) do |file|
358
367
  file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
359
368
  file.print(content)
360
369
  end
361
370
  end
362
371
 
363
372
  def try_delete_css(css)
364
- return unless File.exists?(css)
365
- run_deleting_css css
366
- File.delete css
373
+ if File.exists?(css)
374
+ run_deleting_css css
375
+ File.delete css
376
+ end
377
+ map = Sass::Util.sourcemap_name(css)
378
+ if File.exists?(map)
379
+ run_deleting_sourcemap map
380
+ File.delete map
381
+ end
382
+ end
383
+
384
+ def watched_file?(file)
385
+ normalized_load_paths.find {|lp| lp.watched_file?(file)}
386
+ end
387
+
388
+ def watched_paths
389
+ @watched_paths ||= normalized_load_paths.map {|lp| lp.directories_to_watch}.compact.flatten
390
+ end
391
+
392
+ def normalized_load_paths
393
+ @normalized_load_paths ||=
394
+ Sass::Engine.normalize_options(:load_paths => load_paths)[:load_paths]
367
395
  end
368
396
 
369
397
  def load_paths(opts = options)
@@ -379,7 +407,19 @@ module Sass::Plugin
379
407
  end
380
408
 
381
409
  def css_filename(name, path)
382
- "#{path}/#{name}".gsub(/\.s[ac]ss$/, '.css')
410
+ "#{path}#{File::SEPARATOR unless path.end_with?(File::SEPARATOR)}#{name}".
411
+ gsub(/\.s[ac]ss$/, '.css')
412
+ end
413
+
414
+ def relative_to_pwd(f)
415
+ Pathname.new(f).relative_path_from(Pathname.new(Dir.pwd)).to_s
416
+ rescue ArgumentError # when a relative path cannot be computed
417
+ f
418
+ end
419
+
420
+ def child_of_directory?(parent, child)
421
+ parent_dir = parent.end_with?(File::SEPARATOR) ? parent : (parent + File::SEPARATOR)
422
+ child.start_with?(parent_dir) || parent == child
383
423
  end
384
424
  end
385
425
  end
@@ -1,9 +1,8 @@
1
- # We keep configuration in its own self-contained file
2
- # so that we can load it independently in Rails 3,
3
- # where the full plugin stuff is lazy-loaded.
4
-
5
1
  module Sass
6
2
  module Plugin
3
+ # We keep configuration in its own self-contained file
4
+ # so that we can load it independently in Rails 3,
5
+ # where the full plugin stuff is lazy-loaded.
7
6
  module Configuration
8
7
 
9
8
  # Returns the default options for a {Sass::Plugin::Compiler}.
@@ -19,7 +18,8 @@ module Sass
19
18
  }.freeze
20
19
  end
21
20
 
22
- # Resets the options and {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
21
+ # Resets the options and
22
+ # {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
23
23
  def reset!
24
24
  @options = nil
25
25
  clear_callbacks!
@@ -33,22 +33,12 @@ module Sass
33
33
  @options ||= default_options.dup
34
34
  end
35
35
 
36
- # Sets the options hash.
37
- # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
38
- # See {Sass::Plugin::Configuration#reset!}
39
- # @deprecated Instead, modify the options hash in-place.
40
- # @param value [{Symbol => Object}] The options hash
41
- def options=(value)
42
- Sass::Util.sass_warn("Setting Sass::Plugin.options is deprecated " +
43
- "and will be removed in a future release.")
44
- options.merge!(value)
45
- end
46
-
47
36
  # Adds a new template-location/css-location mapping.
48
37
  # This means that Sass/SCSS files in `template_location`
49
38
  # will be compiled to CSS files in `css_location`.
50
39
  #
51
- # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
40
+ # This is preferred over manually manipulating the
41
+ # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
52
42
  # since the option can be in multiple formats.
53
43
  #
54
44
  # Note that this method will change `options[:template_location]`
@@ -68,7 +58,8 @@ module Sass
68
58
  # This means that Sass/SCSS files in `template_location`
69
59
  # will no longer be compiled to CSS files in `css_location`.
70
60
  #
71
- # This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
61
+ # This is preferred over manually manipulating the
62
+ # {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
72
63
  # since the option can be in multiple formats.
73
64
  #
74
65
  # Note that this method will change `options[:template_location]`
@@ -112,10 +103,15 @@ module Sass
112
103
  options[:template_location] =
113
104
  case options[:template_location]
114
105
  when nil
115
- options[:css_location] ?
116
- [[File.join(options[:css_location], 'sass'), options[:css_location]]] : []
117
- when String; [[options[:template_location], options[:css_location]]]
118
- else; options[:template_location].to_a
106
+ if options[:css_location]
107
+ [[File.join(options[:css_location], 'sass'), options[:css_location]]]
108
+ else
109
+ []
110
+ end
111
+ when String
112
+ [[options[:template_location], options[:css_location]]]
113
+ else
114
+ options[:template_location].to_a
119
115
  end
120
116
  end
121
117
  end
@@ -5,7 +5,7 @@ unless defined?(Sass::MERB_LOADED)
5
5
  # Different default options in a m envirionment.
6
6
  def default_options
7
7
  @default_options ||= begin
8
- version = Merb::VERSION.split('.').map { |n| n.to_i }
8
+ version = Merb::VERSION.split('.').map {|n| n.to_i}
9
9
  if version[0] <= 0 && version[1] < 5
10
10
  root = MERB_ROOT
11
11
  env = MERB_ENV
@@ -1,3 +1,5 @@
1
+ require 'thread'
2
+
1
3
  module Sass
2
4
  module Plugin
3
5
  # The class handles `.s[ca]ss` file staleness checks via their mtime timestamps.
@@ -24,11 +26,13 @@ module Sass
24
26
  # as its instance-level caches are never explicitly expired.
25
27
  class StalenessChecker
26
28
  @dependencies_cache = {}
29
+ @dependency_cache_mutex = Mutex.new
27
30
 
28
31
  class << self
29
32
  # TODO: attach this to a compiler instance.
30
33
  # @private
31
34
  attr_accessor :dependencies_cache
35
+ attr_reader :dependency_cache_mutex
32
36
  end
33
37
 
34
38
  # Creates a new StalenessChecker
@@ -37,15 +41,13 @@ module Sass
37
41
  # @param options [{Symbol => Object}]
38
42
  # See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
39
43
  def initialize(options)
40
- @dependencies = self.class.dependencies_cache
41
-
42
44
  # URIs that are being actively checked for staleness. Protects against
43
45
  # import loops.
44
46
  @actively_checking = Set.new
45
47
 
46
48
  # Entries in the following instance-level caches are never explicitly expired.
47
- # Instead they are supposed to automaticaly go out of scope when a series of staleness checks
48
- # (this instance of StalenessChecker was created for) is finished.
49
+ # Instead they are supposed to automaticaly go out of scope when a series of staleness
50
+ # checks (this instance of StalenessChecker was created for) is finished.
49
51
  @mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
50
52
  @options = Sass::Engine.normalize_options(options)
51
53
  end
@@ -131,7 +133,7 @@ module Sass
131
133
  begin
132
134
  mtime = importer.mtime(uri, @options)
133
135
  if mtime.nil?
134
- @dependencies.delete([uri, importer])
136
+ with_dependency_cache {|cache| cache.delete([uri, importer])}
135
137
  nil
136
138
  else
137
139
  mtime
@@ -140,18 +142,21 @@ module Sass
140
142
  end
141
143
 
142
144
  def dependencies(uri, importer)
143
- stored_mtime, dependencies = Sass::Util.destructure(@dependencies[[uri, importer]])
145
+ stored_mtime, dependencies =
146
+ with_dependency_cache {|cache| Sass::Util.destructure(cache[[uri, importer]])}
144
147
 
145
148
  if !stored_mtime || stored_mtime < mtime(uri, importer)
146
149
  dependencies = compute_dependencies(uri, importer)
147
- @dependencies[[uri, importer]] = [mtime(uri, importer), dependencies]
150
+ with_dependency_cache do |cache|
151
+ cache[[uri, importer]] = [mtime(uri, importer), dependencies]
152
+ end
148
153
  end
149
154
 
150
155
  dependencies
151
156
  end
152
157
 
153
158
  def dependency_updated?(css_mtime)
154
- Proc.new do |uri, importer|
159
+ proc do |uri, importer|
155
160
  next true if @actively_checking.include?(uri)
156
161
  begin
157
162
  @actively_checking << uri
@@ -178,6 +183,17 @@ module Sass
178
183
  def tree(uri, importer)
179
184
  @parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
180
185
  end
186
+
187
+ # Get access to the global dependency cache in a threadsafe manner.
188
+ # Inside the block, no other thread can access the dependency cache.
189
+ #
190
+ # @yieldparam cache [Hash] The hash that is the global dependency cache
191
+ # @return The value returned by the block to which this method yields
192
+ def with_dependency_cache
193
+ StalenessChecker.dependency_cache_mutex.synchronize do
194
+ yield StalenessChecker.dependencies_cache
195
+ end
196
+ end
181
197
  end
182
198
  end
183
199
  end
data/lib/sass/plugin.rb CHANGED
@@ -11,7 +11,8 @@ module Sass
11
11
  # This module is used as the primary interface with Sass
12
12
  # when it's used as a plugin for various frameworks.
13
13
  # All Rack-enabled frameworks are supported out of the box.
14
- # The plugin is {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
14
+ # The plugin is
15
+ # {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
15
16
  # Other frameworks must enable it explicitly; see {Sass::Plugin::Rack}.
16
17
  #
17
18
  # This module has a large set of callbacks available
@@ -65,7 +66,8 @@ module Sass
65
66
 
66
67
  # Updates out-of-date stylesheets.
67
68
  #
68
- # Checks each Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`}
69
+ # Checks each Sass/SCSS file in
70
+ # {file:SASS_REFERENCE.md#template_location-option `:template_location`}
69
71
  # to see if it's been modified more recently than the corresponding CSS file
70
72
  # in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
71
73
  # If it has, it updates the CSS file.
data/lib/sass/repl.rb CHANGED
@@ -18,7 +18,7 @@ module Sass
18
18
  @line = 0
19
19
  loop do
20
20
  @line += 1
21
- unless text = Readline.readline('>> ')
21
+ unless (text = Readline.readline('>> '))
22
22
  puts
23
23
  return
24
24
  end
@@ -48,8 +48,8 @@ module Sass
48
48
  rescue Sass::SyntaxError => e
49
49
  puts "SyntaxError: #{e.message}"
50
50
  if @options[:trace]
51
- e.backtrace.each do |e|
52
- puts "\tfrom #{e}"
51
+ e.backtrace.each do |line|
52
+ puts "\tfrom #{line}"
53
53
  end
54
54
  end
55
55
  end
@@ -4,6 +4,7 @@ module Sass
4
4
  #
5
5
  # @see Sass::SCSS::CssParser
6
6
  class CssLexer < Lexer
7
+
7
8
  private
8
9
 
9
10
  def token
@@ -12,16 +13,20 @@ module Sass
12
13
 
13
14
  def string(re, *args)
14
15
  if re == :uri
15
- return unless uri = scan(URI)
16
- return [:string, Script::String.new(uri)]
16
+ uri = scan(URI)
17
+ return unless uri
18
+ return [:string, Script::Value::String.new(uri)]
17
19
  end
18
20
 
19
21
  return unless scan(STRING)
20
- [:string, Script::String.new((@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1'), :string)]
22
+ string_value = (@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1')
23
+ value = Script::Value::String.new(string_value, :string)
24
+ [:string, value]
21
25
  end
22
26
 
23
27
  def important
24
- return unless s = scan(IMPORTANT)
28
+ s = scan(IMPORTANT)
29
+ return unless s
25
30
  [:raw, s]
26
31
  end
27
32
  end
@@ -7,6 +7,7 @@ module Sass
7
7
  #
8
8
  # @see Sass::SCSS::CssParser
9
9
  class CssParser < Parser
10
+
10
11
  private
11
12
 
12
13
  # @private
@@ -17,8 +18,11 @@ module Sass
17
18
  production :div, :unary_plus, :div
18
19
 
19
20
  def string
20
- return number unless tok = try_tok(:string)
21
- return tok.value unless @lexer.peek && @lexer.peek.type == :begin_interpolation
21
+ tok = try_tok(:string)
22
+ return number unless tok
23
+ unless @lexer.peek && @lexer.peek.type == :begin_interpolation
24
+ return literal_node(tok.value, tok.source_range)
25
+ end
22
26
  end
23
27
 
24
28
  # Short-circuit all the SassScript-only productions