sass 3.1.21 → 3.2.0.alpha.3

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 (180) hide show
  1. data/README.md +5 -4
  2. data/REVISION +1 -1
  3. data/Rakefile +6 -15
  4. data/VERSION +1 -1
  5. data/VERSION_NAME +1 -1
  6. data/lib/sass.rb +0 -1
  7. data/lib/sass/cache_stores/base.rb +1 -3
  8. data/lib/sass/cache_stores/filesystem.rb +0 -3
  9. data/lib/sass/css.rb +49 -145
  10. data/lib/sass/engine.rb +23 -47
  11. data/lib/sass/environment.rb +5 -30
  12. data/lib/sass/exec.rb +7 -30
  13. data/lib/sass/importers/base.rb +1 -2
  14. data/lib/sass/importers/filesystem.rb +13 -18
  15. data/lib/sass/less.rb +1 -1
  16. data/lib/sass/plugin.rb +8 -4
  17. data/lib/sass/plugin/compiler.rb +67 -93
  18. data/lib/sass/plugin/configuration.rb +2 -0
  19. data/lib/sass/plugin/staleness_checker.rb +4 -14
  20. data/lib/sass/repl.rb +3 -2
  21. data/lib/sass/script.rb +1 -0
  22. data/lib/sass/script/color.rb +9 -4
  23. data/lib/sass/script/funcall.rb +3 -16
  24. data/lib/sass/script/functions.rb +55 -98
  25. data/lib/sass/script/interpolation.rb +0 -9
  26. data/lib/sass/script/lexer.rb +4 -2
  27. data/lib/sass/script/list.rb +0 -8
  28. data/lib/sass/script/literal.rb +20 -5
  29. data/lib/sass/script/node.rb +0 -8
  30. data/lib/sass/script/number.rb +11 -35
  31. data/lib/sass/script/operation.rb +0 -16
  32. data/lib/sass/script/parser.rb +5 -12
  33. data/lib/sass/script/string_interpolation.rb +0 -9
  34. data/lib/sass/script/unary_operation.rb +0 -7
  35. data/lib/sass/script/variable.rb +1 -5
  36. data/lib/sass/scss/parser.rb +54 -191
  37. data/lib/sass/scss/rx.rb +3 -15
  38. data/lib/sass/scss/static_parser.rb +3 -3
  39. data/lib/sass/selector.rb +3 -15
  40. data/lib/sass/selector/abstract_sequence.rb +2 -11
  41. data/lib/sass/selector/comma_sequence.rb +3 -8
  42. data/lib/sass/selector/sequence.rb +11 -74
  43. data/lib/sass/selector/simple.rb +1 -7
  44. data/lib/sass/selector/simple_sequence.rb +8 -28
  45. data/lib/sass/shared.rb +5 -3
  46. data/lib/sass/tree/comment_node.rb +12 -25
  47. data/lib/sass/tree/debug_node.rb +1 -1
  48. data/lib/sass/tree/directive_node.rb +0 -5
  49. data/lib/sass/tree/each_node.rb +1 -1
  50. data/lib/sass/tree/extend_node.rb +1 -1
  51. data/lib/sass/tree/for_node.rb +2 -2
  52. data/lib/sass/tree/function_node.rb +1 -1
  53. data/lib/sass/tree/if_node.rb +14 -1
  54. data/lib/sass/tree/media_node.rb +4 -4
  55. data/lib/sass/tree/mixin_def_node.rb +1 -1
  56. data/lib/sass/tree/mixin_node.rb +2 -2
  57. data/lib/sass/tree/node.rb +26 -10
  58. data/lib/sass/tree/return_node.rb +1 -1
  59. data/lib/sass/tree/root_node.rb +1 -1
  60. data/lib/sass/tree/rule_node.rb +11 -9
  61. data/lib/sass/tree/variable_node.rb +1 -1
  62. data/lib/sass/tree/visitors/base.rb +1 -1
  63. data/lib/sass/tree/visitors/check_nesting.rb +36 -29
  64. data/lib/sass/tree/visitors/convert.rb +9 -16
  65. data/lib/sass/tree/visitors/cssize.rb +9 -40
  66. data/lib/sass/tree/visitors/perform.rb +23 -79
  67. data/lib/sass/tree/visitors/to_css.rb +21 -23
  68. data/lib/sass/tree/warn_node.rb +1 -1
  69. data/lib/sass/tree/while_node.rb +1 -1
  70. data/lib/sass/util.rb +9 -147
  71. data/lib/sass/version.rb +0 -14
  72. data/test/sass/cache_test.rb +0 -15
  73. data/test/sass/conversion_test.rb +8 -50
  74. data/test/sass/css2sass_test.rb +0 -33
  75. data/test/sass/engine_test.rb +32 -283
  76. data/test/sass/extend_test.rb +0 -315
  77. data/test/sass/functions_test.rb +23 -60
  78. data/test/sass/importer_test.rb +0 -110
  79. data/test/sass/more_results/more_import.css +2 -2
  80. data/test/sass/plugin_test.rb +13 -40
  81. data/test/sass/results/import.css +2 -2
  82. data/test/sass/results/import_charset.css +0 -1
  83. data/test/sass/results/import_charset_1_8.css +0 -1
  84. data/test/sass/results/import_charset_ibm866.css +0 -1
  85. data/test/sass/results/scss_import.css +2 -2
  86. data/test/sass/results/units.css +1 -1
  87. data/test/sass/script_conversion_test.rb +0 -2
  88. data/test/sass/script_test.rb +4 -28
  89. data/test/sass/scss/css_test.rb +1 -79
  90. data/test/sass/scss/scss_test.rb +16 -96
  91. data/test/sass/templates/import_charset.sass +0 -2
  92. data/test/sass/templates/import_charset_1_8.sass +0 -2
  93. data/test/sass/templates/import_charset_ibm866.sass +0 -2
  94. data/test/sass/test_helper.rb +1 -1
  95. data/test/sass/util_test.rb +0 -28
  96. data/test/test_helper.rb +0 -2
  97. data/vendor/{listen → fssm}/LICENSE +1 -1
  98. data/vendor/fssm/README.markdown +55 -0
  99. data/vendor/fssm/Rakefile +59 -0
  100. data/vendor/fssm/VERSION.yml +5 -0
  101. data/vendor/fssm/example.rb +9 -0
  102. data/vendor/fssm/fssm.gemspec +77 -0
  103. data/vendor/fssm/lib/fssm.rb +33 -0
  104. data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  105. data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  106. data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  107. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  108. data/vendor/fssm/lib/fssm/monitor.rb +26 -0
  109. data/vendor/fssm/lib/fssm/path.rb +91 -0
  110. data/vendor/fssm/lib/fssm/pathname.rb +502 -0
  111. data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  112. data/vendor/fssm/lib/fssm/state/file.rb +24 -0
  113. data/vendor/fssm/lib/fssm/support.rb +63 -0
  114. data/vendor/fssm/lib/fssm/tree.rb +176 -0
  115. data/vendor/fssm/profile/prof-cache.rb +40 -0
  116. data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  117. data/vendor/fssm/profile/prof-pathname.rb +68 -0
  118. data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  119. data/vendor/fssm/profile/prof.html +2379 -0
  120. data/vendor/fssm/spec/path_spec.rb +75 -0
  121. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  122. data/vendor/fssm/spec/root/file.css +0 -0
  123. data/vendor/fssm/spec/root/file.rb +0 -0
  124. data/vendor/fssm/spec/root/file.yml +0 -0
  125. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  126. data/vendor/fssm/spec/spec_helper.rb +14 -0
  127. metadata +246 -281
  128. data/VERSION_DATE +0 -1
  129. data/lib/sass/logger.rb +0 -15
  130. data/lib/sass/logger/base.rb +0 -32
  131. data/lib/sass/logger/log_level.rb +0 -49
  132. data/lib/sass/tree/visitors/deep_copy.rb +0 -87
  133. data/lib/sass/tree/visitors/extend.rb +0 -42
  134. data/lib/sass/tree/visitors/set_options.rb +0 -97
  135. data/lib/sass/util/multibyte_string_scanner.rb +0 -134
  136. data/test/Gemfile +0 -4
  137. data/test/Gemfile.lock +0 -19
  138. data/test/sass/fixtures/test_staleness_check_across_importers.css +0 -1
  139. data/test/sass/fixtures/test_staleness_check_across_importers.scss +0 -1
  140. data/test/sass/logger_test.rb +0 -58
  141. data/test/sass/templates/_double_import_loop2.sass +0 -1
  142. data/test/sass/templates/bork5.sass +0 -3
  143. data/test/sass/templates/double_import_loop1.sass +0 -1
  144. data/test/sass/templates/nested_bork5.sass +0 -2
  145. data/test/sass/templates/single_import_loop.sass +0 -1
  146. data/test/sass/util/multibyte_string_scanner_test.rb +0 -147
  147. data/vendor/listen/CHANGELOG.md +0 -147
  148. data/vendor/listen/Gemfile +0 -23
  149. data/vendor/listen/Guardfile +0 -8
  150. data/vendor/listen/README.md +0 -312
  151. data/vendor/listen/Rakefile +0 -47
  152. data/vendor/listen/Vagrantfile +0 -96
  153. data/vendor/listen/lib/listen.rb +0 -38
  154. data/vendor/listen/lib/listen/adapter.rb +0 -167
  155. data/vendor/listen/lib/listen/adapters/darwin.rb +0 -84
  156. data/vendor/listen/lib/listen/adapters/linux.rb +0 -110
  157. data/vendor/listen/lib/listen/adapters/polling.rb +0 -66
  158. data/vendor/listen/lib/listen/adapters/windows.rb +0 -81
  159. data/vendor/listen/lib/listen/directory_record.rb +0 -318
  160. data/vendor/listen/lib/listen/listener.rb +0 -203
  161. data/vendor/listen/lib/listen/multi_listener.rb +0 -121
  162. data/vendor/listen/lib/listen/turnstile.rb +0 -28
  163. data/vendor/listen/lib/listen/version.rb +0 -3
  164. data/vendor/listen/listen.gemspec +0 -26
  165. data/vendor/listen/spec/listen/adapter_spec.rb +0 -142
  166. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -31
  167. data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -41
  168. data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
  169. data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -24
  170. data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1138
  171. data/vendor/listen/spec/listen/listener_spec.rb +0 -155
  172. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -156
  173. data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
  174. data/vendor/listen/spec/listen_spec.rb +0 -73
  175. data/vendor/listen/spec/spec_helper.rb +0 -18
  176. data/vendor/listen/spec/support/adapter_helper.rb +0 -716
  177. data/vendor/listen/spec/support/directory_record_helper.rb +0 -55
  178. data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
  179. data/vendor/listen/spec/support/listeners_helper.rb +0 -144
  180. data/vendor/listen/spec/support/platform_helper.rb +0 -11
@@ -26,7 +26,7 @@ module Sass
26
26
  unless parent
27
27
  @stack = []
28
28
  @mixins_in_use = Set.new
29
- @files_in_use = Set.new
29
+ set_var("important", Script::String.new("!important"))
30
30
  end
31
31
  end
32
32
 
@@ -59,8 +59,7 @@ module Sass
59
59
  else
60
60
  stack.push(top_of_stack = frame_info)
61
61
  end
62
- mixins_in_use << top_of_stack[:mixin] if top_of_stack[:mixin]
63
- files_in_use << top_of_stack[:filename] if top_of_stack[:filename]
62
+ mixins_in_use << top_of_stack[:mixin] if top_of_stack[:mixin] && !top_of_stack[:prepared]
64
63
  end
65
64
 
66
65
  # Like \{#push\_frame}, but next time a stack frame is pushed,
@@ -73,8 +72,9 @@ module Sass
73
72
 
74
73
  # Pop a stack frame from the mixin/include stack.
75
74
  def pop_frame
76
- pop_and_unuse if stack.last && stack.last[:prepared]
77
- pop_and_unuse
75
+ stack.pop if stack.last && stack.last[:prepared]
76
+ popped = stack.pop
77
+ mixins_in_use.delete(popped[:mixin]) if popped && popped[:mixin]
78
78
  end
79
79
 
80
80
  # A list of stack frames in the mixin/include stack.
@@ -93,33 +93,8 @@ module Sass
93
93
  @mixins_in_use ||= @parent.mixins_in_use
94
94
  end
95
95
 
96
- # A set of names of files currently present in the stack.
97
- #
98
- # @return [Set<String>] The filenames.
99
- def files_in_use
100
- @files_in_use ||= @parent.files_in_use
101
- end
102
-
103
- def stack_trace
104
- trace = []
105
- stack.reverse.each_with_index do |entry, i|
106
- msg = "#{i == 0 ? "on" : "from"} line #{entry[:line]}"
107
- msg << " of #{entry[:filename] || "an unknown file"}"
108
- msg << ", in `#{entry[:mixin]}'" if entry[:mixin]
109
- trace << msg
110
- end
111
- trace
112
- end
113
-
114
96
  private
115
97
 
116
- def pop_and_unuse
117
- popped = stack.pop
118
- mixins_in_use.delete(popped[:mixin]) if popped && popped[:mixin]
119
- files_in_use.delete(popped[:filename]) if popped && popped[:filename]
120
- popped
121
- end
122
-
123
98
  def parent_options
124
99
  @parent_options ||= @parent && @parent.options
125
100
  end
@@ -229,10 +229,6 @@ END
229
229
  'Only meaningful for --watch and --update.') do
230
230
  @options[:stop_on_error] = true
231
231
  end
232
- opts.on('-f', '--force', 'Recompile all Sass files, even if the CSS file is newer.',
233
- 'Only meaningful for --update.') do
234
- @options[:force] = true
235
- end
236
232
  opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
237
233
  require 'stringio'
238
234
  @options[:check_syntax] = true
@@ -242,10 +238,6 @@ END
242
238
  'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
243
239
  @options[:for_engine][:style] = name.to_sym
244
240
  end
245
- opts.on('--precision NUMBER_OF_DIGITS', Integer,
246
- 'How many digits of precision to use when outputting decimal numbers. Defaults to 3.') do |precision|
247
- ::Sass::Script::Number.precision = precision
248
- end
249
241
  opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
250
242
  @options[:for_engine][:quiet] = true
251
243
  end
@@ -358,11 +350,6 @@ END
358
350
  ::Sass::Plugin.options.merge! @options[:for_engine]
359
351
  ::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
360
352
 
361
- if @options[:force]
362
- raise "The --force flag may only be used with --update." unless @options[:update]
363
- ::Sass::Plugin.options[:always_update] = true
364
- end
365
-
366
353
  raise <<MSG if @args.empty?
367
354
  What files should I watch? Did you mean something like:
368
355
  #{@default_syntax} --watch input.#{@default_syntax}:output.css
@@ -385,11 +372,11 @@ MSG
385
372
 
386
373
  dirs, files = @args.map {|name| split_colon_path(name)}.
387
374
  partition {|i, _| File.directory? i}
388
- files.map! {|from, to| [from, to || from.gsub(/\.[^.]*?$/, '.css')]}
375
+ files.map! {|from, to| [from, to || from.gsub(/\..*?$/, '.css')]}
389
376
  dirs.map! {|from, to| [from, to || from]}
390
377
  ::Sass::Plugin.options[:template_location] = dirs
391
378
 
392
- ::Sass::Plugin.on_updated_stylesheet do |_, css|
379
+ ::Sass::Plugin.on_updating_stylesheet do |_, css|
393
380
  if File.exists? css
394
381
  puts_action :overwrite, :yellow, css
395
382
  else
@@ -404,7 +391,6 @@ MSG
404
391
  raise error unless error.is_a?(::Sass::SyntaxError) && !@options[:stop_on_error]
405
392
  had_error = true
406
393
  puts_action :error, :red, "#{error.sass_filename} (Line #{error.sass_line}: #{error.message})"
407
- STDOUT.flush
408
394
  end
409
395
 
410
396
  if @options[:update]
@@ -415,18 +401,9 @@ MSG
415
401
 
416
402
  puts ">>> Sass is watching for changes. Press Ctrl-C to stop."
417
403
 
418
- ::Sass::Plugin.on_template_modified do |template|
419
- puts ">>> Change detected to: #{template}"
420
- STDOUT.flush
421
- end
422
- ::Sass::Plugin.on_template_created do |template|
423
- puts ">>> New template detected: #{template}"
424
- STDOUT.flush
425
- end
426
- ::Sass::Plugin.on_template_deleted do |template|
427
- puts ">>> Deleted template detected: #{template}"
428
- STDOUT.flush
429
- end
404
+ ::Sass::Plugin.on_template_modified {|template| puts ">>> Change detected to: #{template}"}
405
+ ::Sass::Plugin.on_template_created {|template| puts ">>> New template detected: #{template}"}
406
+ ::Sass::Plugin.on_template_deleted {|template| puts ">>> Deleted template detected: #{template}"}
430
407
 
431
408
  ::Sass::Plugin.watch(files)
432
409
  end
@@ -452,7 +429,7 @@ MSG
452
429
  def probably_dest_dir?(path)
453
430
  return false unless path
454
431
  return false if colon_path?(path)
455
- return ::Sass::Util.glob(File.join(path, "*.s[ca]ss")).empty?
432
+ return Dir.glob(File.join(path, "*.s[ca]ss")).empty?
456
433
  end
457
434
  end
458
435
 
@@ -584,7 +561,7 @@ END
584
561
  end
585
562
 
586
563
  ext = @options[:from]
587
- ::Sass::Util.glob("#{@options[:input]}/**/*.#{ext}") do |f|
564
+ Dir.glob("#{@options[:input]}/**/*.#{ext}") do |f|
588
565
  output =
589
566
  if @options[:in_place]
590
567
  f
@@ -72,8 +72,7 @@ module Sass
72
72
  # If no such files exist, it should return nil.
73
73
  #
74
74
  # The {Sass::Engine} to be returned should be passed `options`,
75
- # with a few modifications. `:syntax` should be set appropriately,
76
- # `:filename` should be set to `uri`,
75
+ # with a few modifications. `:filename` and `:syntax` should be set appropriately,
77
76
  # and `:importer` should be set to this importer.
78
77
  #
79
78
  # @param uri [String] The URI to import.
@@ -13,7 +13,7 @@ module Sass
13
13
  # @param root [String] The root path.
14
14
  # This importer will import files relative to this path.
15
15
  def initialize(root)
16
- @root = File.expand_path(root)
16
+ @root = root
17
17
  end
18
18
 
19
19
  # @see Base#find_relative
@@ -45,21 +45,14 @@ module Sass
45
45
  @root
46
46
  end
47
47
 
48
- def hash
49
- @root.hash
50
- end
51
-
52
- def eql?(other)
53
- root.eql?(other.root)
54
- end
55
-
56
48
  protected
57
49
 
58
50
  # If a full uri is passed, this removes the root from it
59
51
  # otherwise returns the name unchanged
60
52
  def remove_root(name)
61
- if name.index(@root + "/") == 0
62
- name[(@root.length + 1)..-1]
53
+ root = @root.end_with?('/') ? @root : @root + '/'
54
+ if name.index(root) == 0
55
+ name[root.length..-1]
63
56
  else
64
57
  name
65
58
  end
@@ -84,7 +77,6 @@ module Sass
84
77
  # The first element of each pair is a filename to look for;
85
78
  # the second element is the syntax that file would be in (`:sass` or `:scss`).
86
79
  def possible_files(name)
87
- name = escape_glob_characters(name)
88
80
  dirname, basename, extname = split(name)
89
81
  sorted_exts = extensions.sort
90
82
  syntax = extensions[extname]
@@ -93,11 +85,6 @@ module Sass
93
85
  sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
94
86
  end
95
87
 
96
- def escape_glob_characters(name)
97
- name.gsub(/[\*\[\]\{\}\?]/) do |char|
98
- "\\#{char}"
99
- end
100
- end
101
88
 
102
89
  REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
103
90
  # Given a base directory and an `@import`ed name,
@@ -108,7 +95,7 @@ module Sass
108
95
  # @return [(String, Symbol)] A filename-syntax pair.
109
96
  def find_real_file(dir, name)
110
97
  for (f,s) in possible_files(remove_root(name))
111
- path = (dir == "." || Pathname.new(f).absolute?) ? f : "#{dir}/#{f}"
98
+ path = (dir == ".") ? f : "#{dir}/#{f}"
112
99
  if full_path = Dir[path].first
113
100
  full_path.gsub!(REDUNDANT_DIRECTORY,File::SEPARATOR)
114
101
  return full_path, s
@@ -129,6 +116,14 @@ module Sass
129
116
  [dirname, basename, extension]
130
117
  end
131
118
 
119
+ def hash
120
+ @root.hash
121
+ end
122
+
123
+ def eql?(other)
124
+ root.eql?(other.root)
125
+ end
126
+
132
127
  private
133
128
 
134
129
  def _find(dir, name, options)
@@ -31,7 +31,7 @@ module Less
31
31
  WARNING: Sass doesn't support mixing in selector sequences.
32
32
  Replacing "#{sel}" with "@extend #{base}"
33
33
  WARNING
34
- env << Node::SassNode.new(Sass::Tree::CommentNode.new(["// #{sel};"], true, false))
34
+ env << Node::SassNode.new(Sass::Tree::CommentNode.new("// #{sel};", true))
35
35
  env << Node::SassNode.new(Sass::Tree::ExtendNode.new([base]))
36
36
  end
37
37
  end
@@ -92,10 +92,14 @@ module Sass
92
92
  # the second is the location of the CSS file that it should be compiled to.
93
93
  # @see #update_stylesheets
94
94
  def force_update_stylesheets(individual_files = [])
95
- Compiler.new(options.dup.merge(
96
- :never_update => false,
97
- :always_update => true,
98
- :cache => false)).update_stylesheets(individual_files)
95
+ old_options = options
96
+ self.options = options.dup
97
+ options[:never_update] = false
98
+ options[:always_update] = true
99
+ options[:cache] = false
100
+ update_stylesheets(individual_files)
101
+ ensure
102
+ self.options = old_options
99
103
  end
100
104
 
101
105
  # All other method invocations are proxied to the \{#compiler}.
@@ -38,7 +38,7 @@ module Sass::Plugin
38
38
  self.options.merge!(options)
39
39
  end
40
40
 
41
- # Register a callback to be run after stylesheets are mass-updated.
41
+ # Register a callback to be run before stylesheets are mass-updated.
42
42
  # This is run whenever \{#update\_stylesheets} is called,
43
43
  # unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
44
44
  # is enabled.
@@ -51,22 +51,6 @@ module Sass::Plugin
51
51
  # the second is the target CSS file.
52
52
  define_callback :updating_stylesheets
53
53
 
54
- # Register a callback to be run after a single stylesheet is updated.
55
- # The callback is only run if the stylesheet is really updated;
56
- # if the CSS file is fresh, this won't be run.
57
- #
58
- # Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
59
- # is enabled, this callback won't be run
60
- # when an exception CSS file is being written.
61
- # To run an action for those files, use \{#on\_compilation\_error}.
62
- #
63
- # @yield [template, css]
64
- # @yieldparam template [String]
65
- # The location of the Sass/SCSS file being updated.
66
- # @yieldparam css [String]
67
- # The location of the CSS file being generated.
68
- define_callback :updated_stylesheet
69
-
70
54
  # Register a callback to be run before a single stylesheet is updated.
71
55
  # The callback is only run if the stylesheet is guaranteed to be updated;
72
56
  # if the CSS file is fresh, this won't be run.
@@ -83,13 +67,6 @@ module Sass::Plugin
83
67
  # The location of the CSS file being generated.
84
68
  define_callback :updating_stylesheet
85
69
 
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
70
  # Register a callback to be run when Sass decides not to update a stylesheet.
94
71
  # In particular, the callback is run when Sass finds that
95
72
  # the template file and none of its dependencies
@@ -183,25 +160,28 @@ module Sass::Plugin
183
160
  # The first string in each pair is the location of the Sass/SCSS file,
184
161
  # the second is the location of the CSS file that it should be compiled to.
185
162
  def update_stylesheets(individual_files = [])
163
+ run_updating_stylesheets individual_files
186
164
  Sass::Plugin.checked_for_updates = true
187
165
  staleness_checker = StalenessChecker.new(engine_options)
188
166
 
167
+ individual_files.each do |t, c|
168
+ if options[:always_update] || staleness_checker.stylesheet_needs_update?(c, t)
169
+ update_stylesheet(t, c)
170
+ end
171
+ end
172
+
189
173
  template_location_array.each do |template_location, css_location|
190
- Sass::Util.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
174
+
175
+ Dir.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
191
176
  # Get the relative path to the file
192
177
  name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
193
178
  css = css_filename(name, css_location)
194
- individual_files << [file, css]
195
- end
196
- end
197
-
198
- run_updating_stylesheets individual_files
199
179
 
200
- individual_files.each do |file, css|
201
- if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
202
- update_stylesheet(file, css)
203
- else
204
- run_not_updating_stylesheet(file, css)
180
+ if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
181
+ update_stylesheet file, css
182
+ else
183
+ run_not_updating_stylesheet file, css
184
+ end
205
185
  end
206
186
  end
207
187
  end
@@ -218,10 +198,10 @@ module Sass::Plugin
218
198
  #
219
199
  # Before the watching starts in earnest, `watch` calls \{#update\_stylesheets}.
220
200
  #
221
- # Note that `watch` uses the [Listen](http://github.com/guard/listen) library
201
+ # Note that `watch` uses the [FSSM](http://github.com/ttilley/fssm) library
222
202
  # to monitor the filesystem for changes.
223
- # Listen isn't loaded until `watch` is run.
224
- # The version of Listen distributed with Sass is loaded by default,
203
+ # FSSM isn't loaded until `watch` is run.
204
+ # The version of FSSM distributed with Sass is loaded by default,
225
205
  # but if another version has already been loaded that will be used instead.
226
206
  #
227
207
  # @param individual_files [Array<(String, String)>]
@@ -234,15 +214,15 @@ module Sass::Plugin
234
214
  update_stylesheets(individual_files)
235
215
 
236
216
  begin
237
- require 'listen'
217
+ require 'fssm'
238
218
  rescue LoadError => e
239
- dir = Sass::Util.scope("vendor/listen/lib")
219
+ dir = Sass::Util.scope("vendor/fssm/lib")
240
220
  if $LOAD_PATH.include?(dir)
241
221
  e.message << "\n" <<
242
222
  if File.exists?(scope(".git"))
243
223
  'Run "git submodule update --init" to get the recommended version.'
244
224
  else
245
- 'Run "gem install listen" to get it.'
225
+ 'Run "gem install fssm" to get it.'
246
226
  end
247
227
  raise e
248
228
  else
@@ -251,61 +231,60 @@ module Sass::Plugin
251
231
  end
252
232
  end
253
233
 
254
- template_paths = template_locations # cache the locations
255
- individual_files_hash = individual_files.inject({}) do |h, files|
256
- parent = File.dirname(files.first)
257
- (h[parent] ||= []) << files unless template_paths.include?(parent)
258
- h
234
+ unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
235
+ # As of FSSM 0.1.4, it doesn't support FSevents on individual files,
236
+ # but it also isn't smart enough to switch to polling itself.
237
+ require 'fssm/backends/polling'
238
+ Sass::Util.silence_warnings do
239
+ FSSM::Backends.const_set(:Default, FSSM::Backends::Polling)
240
+ end
259
241
  end
260
- directories = template_paths + individual_files_hash.keys +
261
- [{:relative_paths => true}]
262
242
 
263
243
  # TODO: Keep better track of what depends on what
264
244
  # so we don't have to run a global update every time anything changes.
265
- listener = Listen::MultiListener.new(*directories) do |modified, added, removed|
266
- modified.each do |f|
267
- parent = File.dirname(f)
268
- if files = individual_files_hash[parent]
269
- next unless files.first == f
270
- else
271
- next unless f =~ /\.s[ac]ss$/
272
- end
273
- run_template_modified(f)
274
- end
245
+ FSSM.monitor do |mon|
246
+ template_location_array.each do |template_location, css_location|
247
+ mon.path template_location do |path|
248
+ path.glob '**/*.s[ac]ss'
249
+
250
+ path.update do |base, relative|
251
+ run_template_modified File.join(base, relative)
252
+ update_stylesheets(individual_files)
253
+ end
275
254
 
276
- added.each do |f|
277
- parent = File.dirname(f)
278
- if files = individual_files_hash[parent]
279
- next unless files.first == f
280
- else
281
- next unless f =~ /\.s[ac]ss$/
282
- end
283
- run_template_created(f)
284
- end
255
+ path.create do |base, relative|
256
+ run_template_created File.join(base, relative)
257
+ update_stylesheets(individual_files)
258
+ end
285
259
 
286
- removed.each do |f|
287
- parent = File.dirname(f)
288
- if files = individual_files_hash[parent]
289
- next unless files.first == f
290
- try_delete_css files[1]
291
- else
292
- next unless f =~ /\.s[ac]ss$/
293
- try_delete_css f.gsub(/\.s[ac]ss$/, '.css')
260
+ path.delete do |base, relative|
261
+ run_template_deleted File.join(base, relative)
262
+ css = File.join(css_location, relative.gsub(/\.s[ac]ss$/, '.css'))
263
+ try_delete_css css
264
+ update_stylesheets(individual_files)
265
+ end
294
266
  end
295
- run_template_deleted(f)
296
267
  end
297
268
 
298
- update_stylesheets(individual_files)
299
- end
269
+ individual_files.each do |template, css|
270
+ mon.file template do |path|
271
+ path.update do
272
+ run_template_modified template
273
+ update_stylesheets(individual_files)
274
+ end
300
275
 
301
- # The native windows listener is much slower than the polling
302
- # option, according to https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e#commitcomment-1295118
303
- listener.force_polling(true) if Sass::Util.windows?
276
+ path.create do
277
+ run_template_created template
278
+ update_stylesheets(individual_files)
279
+ end
304
280
 
305
- begin
306
- listener.start
307
- rescue Exception => e
308
- raise e unless e.is_a?(Interrupt)
281
+ path.delete do
282
+ run_template_deleted template
283
+ try_delete_css css
284
+ update_stylesheets(individual_files)
285
+ end
286
+ end
287
+ end
309
288
  end
310
289
  end
311
290
 
@@ -339,23 +318,18 @@ module Sass::Plugin
339
318
  engine_opts = engine_options(:css_filename => css, :filename => filename)
340
319
  result = Sass::Engine.for_file(filename, engine_opts).render
341
320
  rescue Exception => e
342
- compilation_error_occured = true
343
321
  run_compilation_error e, filename, css
344
322
  result = Sass::SyntaxError.exception_to_css(e, options)
345
323
  else
346
324
  run_updating_stylesheet filename, css
347
325
  end
348
326
 
349
- write_file(css, result)
350
- run_updated_stylesheet(filename, css) unless compilation_error_occured
351
- end
352
-
353
- def write_file(css, content)
327
+ # Finally, write the file
354
328
  flag = 'w'
355
329
  flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
356
330
  File.open(css, flag) do |file|
357
- file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
358
- file.print(content)
331
+ file.set_encoding(result.encoding) unless Sass::Util.ruby1_8?
332
+ file.print(result)
359
333
  end
360
334
  end
361
335