sass 3.3.0 → 3.3.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 (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