sass 3.3.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/VERSION_DATE +1 -1
  4. data/lib/sass/importers/filesystem.rb +3 -3
  5. data/lib/sass/plugin/compiler.rb +95 -52
  6. data/lib/sass/script/functions.rb +1 -1
  7. data/lib/sass/source/map.rb +3 -3
  8. data/lib/sass/util.rb +16 -1
  9. data/vendor/listen/CHANGELOG.md +175 -35
  10. data/vendor/listen/Gemfile +5 -15
  11. data/vendor/listen/README.md +111 -77
  12. data/vendor/listen/Rakefile +0 -42
  13. data/vendor/listen/lib/listen.rb +33 -19
  14. data/vendor/listen/lib/listen/adapter.rb +193 -82
  15. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  16. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  17. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  18. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  19. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  20. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  21. data/vendor/listen/lib/listen/listener.rb +135 -37
  22. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  23. data/vendor/listen/lib/listen/version.rb +1 -1
  24. data/vendor/listen/listen.gemspec +6 -0
  25. data/vendor/listen/spec/listen/adapter_spec.rb +37 -82
  26. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  27. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  28. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  29. data/vendor/listen/spec/listen_spec.rb +15 -21
  30. data/vendor/listen/spec/spec_helper.rb +4 -0
  31. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  32. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  33. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  34. metadata +3 -23
  35. data/ext/mkrf_conf.rb +0 -27
  36. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  37. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  38. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  39. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -5,19 +5,25 @@ require 'fileutils'
5
5
 
6
6
  module Listen
7
7
  class Adapter
8
- attr_accessor :directories, :latency, :paused
8
+ attr_accessor :directories, :callback, :stopped, :paused,
9
+ :mutex, :changed_directories, :turnstile, :latency,
10
+ :worker, :worker_thread, :poller_thread
11
+
12
+ # The list of existing optimized adapters.
13
+ OPTIMIZED_ADAPTERS = %w[Darwin Linux BSD Windows]
14
+
15
+ # The list of existing fallback adapters.
16
+ FALLBACK_ADAPTERS = %w[Polling]
17
+
18
+ # The list of all existing adapters.
19
+ ADAPTERS = OPTIMIZED_ADAPTERS + FALLBACK_ADAPTERS
9
20
 
10
21
  # The default delay between checking for changes.
11
22
  DEFAULT_LATENCY = 0.25
12
23
 
13
- # The default warning message when there is a missing dependency.
14
- MISSING_DEPENDENCY_MESSAGE = <<-EOS.gsub(/^\s*/, '')
15
- For a better performance, it's recommended that you satisfy the missing dependency.
16
- EOS
17
-
18
24
  # The default warning message when falling back to polling adapter.
19
25
  POLLING_FALLBACK_MESSAGE = <<-EOS.gsub(/^\s*/, '')
20
- Listen will be polling changes. Learn more at https://github.com/guard/listen#polling-fallback.
26
+ Listen will be polling for changes. Learn more at https://github.com/guard/listen#polling-fallback.
21
27
  EOS
22
28
 
23
29
  # Selects the appropriate adapter implementation for the
@@ -29,36 +35,31 @@ module Listen
29
35
  # @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
30
36
  # @option options [Float] latency the delay between checking for changes in seconds
31
37
  #
32
- # @yield [changed_dirs, options] callback Callback called when a change happens
33
- # @yieldparam [Array<String>] changed_dirs the changed directories
34
- # @yieldparam [Hash] options callback options (like :recursive => true)
38
+ # @yield [changed_directories, options] callback the callback called when a change happens
39
+ # @yieldparam [Array<String>] changed_directories the changed directories
40
+ # @yieldparam [Hash] options callback options (like recursive: true)
35
41
  #
36
42
  # @return [Listen::Adapter] the chosen adapter
37
43
  #
38
44
  def self.select_and_initialize(directories, options = {}, &callback)
39
- return Adapters::Polling.new(directories, options, &callback) if options.delete(:force_polling)
40
-
41
- warning = ''
42
-
43
- begin
44
- if Adapters::Darwin.usable_and_works?(directories, options)
45
- return Adapters::Darwin.new(directories, options, &callback)
46
- elsif Adapters::Linux.usable_and_works?(directories, options)
47
- return Adapters::Linux.new(directories, options, &callback)
48
- elsif Adapters::BSD.usable_and_works?(directories, options)
49
- return Adapters::BSD.new(directories, options, &callback)
50
- elsif Adapters::Windows.usable_and_works?(directories, options)
51
- return Adapters::Windows.new(directories, options, &callback)
52
- end
53
- rescue DependencyManager::Error => e
54
- warning += e.message + "\n" + MISSING_DEPENDENCY_MESSAGE
45
+ forced_adapter_class = options.delete(:force_adapter)
46
+ force_polling = options.delete(:force_polling)
47
+
48
+ if forced_adapter_class
49
+ forced_adapter_class.load_dependent_adapter
50
+ return forced_adapter_class.new(directories, options, &callback)
55
51
  end
56
52
 
57
- unless options[:polling_fallback_message] == false
58
- warning += options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
59
- Kernel.warn "[Listen warning]:\n" + warning.gsub(/^(.*)/, ' \1')
53
+ return Adapters::Polling.new(directories, options, &callback) if force_polling
54
+
55
+ OPTIMIZED_ADAPTERS.each do |adapter|
56
+ namespaced_adapter = Adapters.const_get(adapter)
57
+ if namespaced_adapter.send(:usable_and_works?, directories, options)
58
+ return namespaced_adapter.new(directories, options, &callback)
59
+ end
60
60
  end
61
61
 
62
+ self.warn_polling_fallback(options)
62
63
  Adapters::Polling.new(directories, options, &callback)
63
64
  end
64
65
 
@@ -67,97 +68,150 @@ module Listen
67
68
  # @param [String, Array<String>] directories the directories to watch
68
69
  # @param [Hash] options the adapter options
69
70
  # @option options [Float] latency the delay between checking for changes in seconds
70
- # @option options [Boolean] report_changes whether or not to automatically report changes (run the callback)
71
71
  #
72
- # @yield [changed_dirs, options] callback Callback called when a change happens
73
- # @yieldparam [Array<String>] changed_dirs the changed directories
74
- # @yieldparam [Hash] options callback options (like :recursive => true)
72
+ # @yield [changed_directories, options] callback Callback called when a change happens
73
+ # @yieldparam [Array<String>] changed_directories the changed directories
74
+ # @yieldparam [Hash] options callback options (like recursive: true)
75
75
  #
76
76
  # @return [Listen::Adapter] the adapter
77
77
  #
78
78
  def initialize(directories, options = {}, &callback)
79
- @directories = Array(directories)
80
- @callback = callback
81
- @paused = false
82
- @mutex = Mutex.new
83
- @changed_dirs = Set.new
84
- @turnstile = Turnstile.new
85
- @latency ||= DEFAULT_LATENCY
86
- @latency = options[:latency] if options[:latency]
87
- @report_changes = options[:report_changes].nil? ? true : options[:report_changes]
79
+ @directories = Array(directories)
80
+ @callback = callback
81
+ @stopped = true
82
+ @paused = false
83
+ @mutex = Mutex.new
84
+ @changed_directories = Set.new
85
+ @turnstile = Turnstile.new
86
+ @latency = options.fetch(:latency, default_latency)
87
+ @worker = initialize_worker
88
88
  end
89
89
 
90
- # Starts the adapter.
90
+ # Starts the adapter and don't block the current thread.
91
91
  #
92
92
  # @param [Boolean] blocking whether or not to block the current thread after starting
93
93
  #
94
- def start(blocking = true)
95
- @stop = false
94
+ def start
95
+ mutex.synchronize do
96
+ return unless stopped
97
+ @stopped = false
98
+ end
99
+
100
+ start_worker
101
+ start_poller
102
+ end
103
+
104
+ # Starts the adapter and block the current thread.
105
+ #
106
+ # @since 1.0.0
107
+ #
108
+ def start!
109
+ start
110
+ blocking_thread.join
96
111
  end
97
112
 
98
113
  # Stops the adapter.
99
114
  #
100
115
  def stop
101
- @stop = true
102
- @turnstile.signal # ensure no thread is blocked
116
+ mutex.synchronize do
117
+ return if stopped
118
+ @stopped = true
119
+ turnstile.signal # ensure no thread is blocked
120
+ end
121
+
122
+ worker.stop if worker
123
+ Thread.kill(worker_thread) if worker_thread
124
+ if poller_thread
125
+ poller_thread.kill
126
+ poller_thread.join
127
+ end
103
128
  end
104
129
 
105
- # Returns whether the adapter is statred or not
130
+ # Pauses the adapter.
131
+ #
132
+ def pause
133
+ @paused = true
134
+ end
135
+
136
+ # Unpauses the adapter.
137
+ #
138
+ def unpause
139
+ @paused = false
140
+ end
141
+
142
+ # Returns whether the adapter is started or not.
106
143
  #
107
144
  # @return [Boolean] whether the adapter is started or not
108
145
  #
109
146
  def started?
110
- @stop.nil? ? false : !@stop
147
+ !stopped
148
+ end
149
+
150
+ # Returns whether the adapter is paused or not.
151
+ #
152
+ # @return [Boolean] whether the adapter is paused or not
153
+ #
154
+ def paused?
155
+ paused
111
156
  end
112
157
 
113
158
  # Blocks the main thread until the poll thread
114
159
  # runs the callback.
115
160
  #
116
161
  def wait_for_callback
117
- @turnstile.wait unless @paused
162
+ turnstile.wait unless paused
118
163
  end
119
164
 
120
165
  # Blocks the main thread until N changes are
121
166
  # detected.
122
167
  #
123
- def wait_for_changes(goal = 0)
168
+ def wait_for_changes(threshold = 0)
124
169
  changes = 0
125
170
 
126
171
  loop do
127
- @mutex.synchronize { changes = @changed_dirs.size }
172
+ mutex.synchronize { changes = changed_directories.size }
128
173
 
129
- return if @paused || @stop
130
- return if changes >= goal
174
+ return if paused || stopped
175
+ return if changes >= threshold
131
176
 
132
- sleep(@latency)
177
+ sleep(latency)
133
178
  end
134
179
  end
135
180
 
136
- # Checks if the adapter is usable on the current OS.
137
- #
138
- # @return [Boolean] whether usable or not
139
- #
140
- def self.usable?
141
- load_depenencies
142
- dependencies_loaded?
143
- end
144
-
145
181
  # Checks if the adapter is usable and works on the current OS.
146
182
  #
147
183
  # @param [String, Array<String>] directories the directories to watch
148
184
  # @param [Hash] options the adapter options
149
185
  # @option options [Float] latency the delay between checking for changes in seconds
150
186
  #
151
- # @return [Boolean] whether usable and work or not
187
+ # @return [Boolean] whether the adapter is usable and work or not
152
188
  #
153
189
  def self.usable_and_works?(directories, options = {})
154
190
  usable? && Array(directories).all? { |d| works?(d, options) }
155
191
  end
156
192
 
193
+ # Checks if the adapter is usable on target OS.
194
+ #
195
+ # @return [Boolean] whether usable or not
196
+ #
197
+ def self.usable?
198
+ load_dependent_adapter if RbConfig::CONFIG['target_os'] =~ target_os_regex
199
+ end
200
+
201
+ # Load the adapter gem
202
+ #
203
+ # @return [Boolean] whether loaded or not
204
+ #
205
+ def self.load_dependent_adapter
206
+ return true if @loaded
207
+ require adapter_gem
208
+ return @loaded = true
209
+ end
210
+
157
211
  # Runs a tests to determine if the adapter can actually pick up
158
212
  # changes in a given directory and returns the result.
159
213
  #
160
- # @note This test takes some time depending the adapter latency.
214
+ # @note This test takes some time depending on the adapter latency.
161
215
  #
162
216
  # @param [String, Pathname] directory the directory to watch
163
217
  # @param [Hash] options the adapter options
@@ -166,11 +220,11 @@ module Listen
166
220
  # @return [Boolean] whether the adapter works or not
167
221
  #
168
222
  def self.works?(directory, options = {})
169
- work = false
223
+ work = false
170
224
  test_file = "#{directory}/.listen_test"
171
- callback = lambda { |*| work = true }
172
- adapter = self.new(directory, options, &callback)
173
- adapter.start(false)
225
+ callback = lambda { |*| work = true }
226
+ adapter = self.new(directory, options, &callback)
227
+ adapter.start
174
228
 
175
229
  FileUtils.touch(test_file)
176
230
 
@@ -180,7 +234,7 @@ module Listen
180
234
  work
181
235
  ensure
182
236
  Thread.kill(t) if t
183
- FileUtils.rm(test_file) if File.exists?(test_file)
237
+ FileUtils.rm(test_file, :force => true)
184
238
  adapter.stop if adapter && adapter.started?
185
239
  end
186
240
 
@@ -189,24 +243,81 @@ module Listen
189
243
  def report_changes
190
244
  changed_dirs = nil
191
245
 
192
- @mutex.synchronize do
193
- return if @changed_dirs.empty?
194
- changed_dirs = @changed_dirs.to_a
195
- @changed_dirs.clear
246
+ mutex.synchronize do
247
+ return if @changed_directories.empty?
248
+ changed_dirs = @changed_directories.to_a
249
+ @changed_directories.clear
196
250
  end
197
251
 
198
- @callback.call(changed_dirs, {})
199
- @turnstile.signal
252
+ callback.call(changed_dirs, {})
253
+ turnstile.signal
200
254
  end
201
255
 
202
256
  private
203
257
 
204
- # Polls changed directories and reports them back
205
- # when there are changes.
258
+ # The default delay between checking for changes.
259
+ #
260
+ # @note This method can be overriden on a per-adapter basis.
261
+ #
262
+ def default_latency
263
+ DEFAULT_LATENCY
264
+ end
265
+
266
+ # The thread on which the main thread should wait
267
+ # when the adapter has been started in blocking mode.
268
+ #
269
+ # @note This method can be overriden on a per-adapter basis.
270
+ #
271
+ def blocking_thread
272
+ worker_thread
273
+ end
274
+
275
+ # Initialize the adpater' specific worker.
276
+ #
277
+ # @note Each adapter must override this method
278
+ # to initialize its own @worker.
279
+ #
280
+ def initialize_worker
281
+ nil
282
+ end
283
+
284
+ # Should start the worker in a new thread.
285
+ #
286
+ # @note Each adapter must override this method
287
+ # to start its worker on a new @worker_thread thread.
288
+ #
289
+ def start_worker
290
+ raise NotImplementedError, "#{self.class} cannot respond to: #{__method__}"
291
+ end
292
+
293
+ # This method starts a new thread which poll for changes detected by
294
+ # the adapter and report them back to the user.
295
+ #
296
+ def start_poller
297
+ @poller_thread = Thread.new { poll_changed_directories }
298
+ end
299
+
300
+ # Warn of polling fallback unless the :polling_fallback_message
301
+ # has been set to false.
302
+ #
303
+ # @param [String] warning an existing warning message
304
+ # @param [Hash] options the adapter options
305
+ # @option options [Boolean] polling_fallback_message to change polling fallback message or remove it
306
+ #
307
+ def self.warn_polling_fallback(options)
308
+ return if options[:polling_fallback_message] == false
309
+
310
+ warning = options[:polling_fallback_message] || POLLING_FALLBACK_MESSAGE
311
+ Kernel.warn "[Listen warning]:\n#{warning.gsub(/^(.*)/, ' \1')}"
312
+ end
313
+
314
+ # Polls changed directories and reports them back when there are changes.
315
+ #
316
+ # @note This method can be overriden on a per-adapter basis.
206
317
  #
207
- def poll_changed_dirs
208
- until @stop
209
- sleep(@latency)
318
+ def poll_changed_directories
319
+ until stopped
320
+ sleep(latency)
210
321
  report_changes
211
322
  end
212
323
  end
@@ -4,68 +4,15 @@ module Listen
4
4
  # Listener implementation for BSD's `kqueue`.
5
5
  #
6
6
  class BSD < Adapter
7
- extend DependencyManager
8
-
9
- # Declare the adapter's dependencies
10
- dependency 'rb-kqueue', '~> 0.2'
11
-
12
7
  # Watched kqueue events
13
8
  #
14
9
  # @see http://www.freebsd.org/cgi/man.cgi?query=kqueue
15
10
  # @see https://github.com/nex3/rb-kqueue/blob/master/lib/rb-kqueue/queue.rb
16
11
  #
17
- EVENTS = [ :delete, :write, :extend, :attrib, :link, :rename, :revoke ]
18
-
19
- # Initializes the Adapter. See {Listen::Adapter#initialize} for
20
- # more info.
21
- #
22
- def initialize(directories, options = {}, &callback)
23
- super
24
- @kqueue = init_kqueue
25
- end
26
-
27
- # Starts the adapter.
28
- #
29
- # @param [Boolean] blocking whether or not to block the current thread after starting
30
- #
31
- def start(blocking = true)
32
- @mutex.synchronize do
33
- return if @stop == false
34
- super
35
- end
36
-
37
- @kqueue_thread = Thread.new do
38
- until @stop
39
- @kqueue.poll
40
- sleep(@latency)
41
- end
42
- end
43
- @poll_thread = Thread.new { poll_changed_dirs } if @report_changes
44
-
45
- @kqueue_thread.join if blocking
46
- end
47
-
48
- # Stops the adapter.
49
- #
50
- def stop
51
- @mutex.synchronize do
52
- return if @stop == true
53
- super
54
- end
55
-
56
- @kqueue.stop
57
- Thread.kill(@kqueue_thread) if @kqueue_thread
58
- @poll_thread.join if @poll_thread
59
- end
12
+ EVENTS = [:delete, :write, :extend, :attrib, :link, :rename, :revoke]
60
13
 
61
- # Checks if the adapter is usable on the current OS.
62
- #
63
- # @return [Boolean] whether usable or not
64
- #
65
- def self.usable?
66
- return false unless RbConfig::CONFIG['target_os'] =~ /freebsd/i
67
- super
68
- end
14
+ def self.target_os_regex; /freebsd/i; end
15
+ def self.adapter_gem; 'rb-kqueue'; end
69
16
 
70
17
  private
71
18
 
@@ -74,24 +21,26 @@ module Listen
74
21
  #
75
22
  # @return [INotify::Notifier] initialized kqueue
76
23
  #
77
- def init_kqueue
24
+ # @see Listen::Adapter#initialize_worker
25
+ #
26
+ def initialize_worker
78
27
  require 'find'
79
28
 
80
29
  callback = lambda do |event|
81
30
  path = event.watcher.path
82
- @mutex.synchronize do
31
+ mutex.synchronize do
83
32
  # kqueue watches everything, but Listen only needs the
84
33
  # directory where stuffs happens.
85
- @changed_dirs << (File.directory?(path) ? path : File.dirname(path))
34
+ @changed_directories << (File.directory?(path) ? path : File.dirname(path))
86
35
 
87
36
  # If it is a directory, and it has a write flag, it means a
88
37
  # file has been added so find out which and deal with it.
89
- # No need to check for removed file, kqueue will forget them
90
- # when the vfs does..
91
- if File.directory?(path) && !(event.flags & [:write]).empty?
38
+ # No need to check for removed files, kqueue will forget them
39
+ # when the vfs does.
40
+ if File.directory?(path) && event.flags.include?(:write)
92
41
  queue = event.watcher.queue
93
42
  Find.find(path) do |file|
94
- unless queue.watchers.detect {|k,v| v.path == file.to_s}
43
+ unless queue.watchers.detect { |k,v| v.path == file.to_s }
95
44
  queue.watch_file(file, *EVENTS, &callback)
96
45
  end
97
46
  end
@@ -100,13 +49,27 @@ module Listen
100
49
  end
101
50
 
102
51
  KQueue::Queue.new.tap do |queue|
103
- @directories.each do |directory|
52
+ directories.each do |directory|
104
53
  Find.find(directory) do |path|
105
54
  queue.watch_file(path, *EVENTS, &callback)
106
55
  end
107
56
  end
108
57
  end
109
58
  end
59
+
60
+ # Starts the worker in a new thread.
61
+ #
62
+ # @see Listen::Adapter#start_worker
63
+ #
64
+ def start_worker
65
+ @worker_thread = Thread.new do
66
+ until stopped
67
+ worker.poll
68
+ sleep(latency)
69
+ end
70
+ end
71
+ end
110
72
  end
73
+
111
74
  end
112
75
  end