sass 3.2.0.alpha.101 → 3.2.0.alpha.102
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.
- data/REVISION +1 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/lib/sass/plugin/compiler.rb +25 -32
- data/lib/sass/plugin/listener.rb +59 -0
- data/lib/sass/script/lexer.rb +1 -1
- data/lib/sass/script/list.rb +1 -0
- data/test/sass/conversion_test.rb +10 -0
- data/test/sass/scss/css_test.rb +9 -0
- data/vendor/listen/CHANGELOG.md +72 -0
- data/vendor/listen/Gemfile +35 -0
- data/vendor/listen/Guardfile +8 -0
- data/vendor/listen/LICENSE +20 -0
- data/vendor/listen/README.md +297 -0
- data/vendor/listen/Rakefile +47 -0
- data/vendor/listen/Vagrantfile +96 -0
- data/vendor/listen/lib/listen.rb +38 -0
- data/vendor/listen/lib/listen/adapter.rb +159 -0
- data/vendor/listen/lib/listen/adapters/darwin.rb +84 -0
- data/vendor/listen/lib/listen/adapters/linux.rb +99 -0
- data/vendor/listen/lib/listen/adapters/polling.rb +66 -0
- data/vendor/listen/lib/listen/adapters/windows.rb +82 -0
- data/vendor/listen/lib/listen/directory_record.rb +257 -0
- data/vendor/listen/lib/listen/listener.rb +186 -0
- data/vendor/listen/lib/listen/multi_listener.rb +121 -0
- data/vendor/listen/lib/listen/turnstile.rb +28 -0
- data/vendor/listen/lib/listen/version.rb +3 -0
- data/vendor/listen/listen.gemspec +26 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +142 -0
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +31 -0
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +30 -0
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +24 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +807 -0
- data/vendor/listen/spec/listen/listener_spec.rb +151 -0
- data/vendor/listen/spec/listen/multi_listener_spec.rb +151 -0
- data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
- data/vendor/listen/spec/listen_spec.rb +73 -0
- data/vendor/listen/spec/spec_helper.rb +16 -0
- data/vendor/listen/spec/support/adapter_helper.rb +538 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +35 -0
- data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
- data/vendor/listen/spec/support/listeners_helper.rb +133 -0
- data/vendor/listen/spec/support/platform_helper.rb +11 -0
- metadata +41 -5
@@ -0,0 +1,66 @@
|
|
1
|
+
module Listen
|
2
|
+
module Adapters
|
3
|
+
|
4
|
+
# The default delay between checking for changes.
|
5
|
+
DEFAULT_POLLING_LATENCY = 1.0
|
6
|
+
|
7
|
+
# Polling Adapter that works cross-platform and
|
8
|
+
# has no dependencies. This is the adapter that
|
9
|
+
# uses the most CPU processing power and has higher
|
10
|
+
# file IO that the other implementations.
|
11
|
+
#
|
12
|
+
class Polling < Adapter
|
13
|
+
|
14
|
+
# Initialize the Adapter. See {Listen::Adapter#initialize} for more info.
|
15
|
+
#
|
16
|
+
def initialize(directories, options = {}, &callback)
|
17
|
+
@latency ||= DEFAULT_POLLING_LATENCY
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
# Start the adapter.
|
22
|
+
#
|
23
|
+
# @param [Boolean] blocking whether or not to block the current thread after starting
|
24
|
+
#
|
25
|
+
def start(blocking = true)
|
26
|
+
@mutex.synchronize do
|
27
|
+
return if @stop == false
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
@poll_thread = Thread.new { poll }
|
32
|
+
@poll_thread.join if blocking
|
33
|
+
end
|
34
|
+
|
35
|
+
# Stop the adapter.
|
36
|
+
#
|
37
|
+
def stop
|
38
|
+
@mutex.synchronize do
|
39
|
+
return if @stop == true
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
@poll_thread.join
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# Poll listener directory for file system changes.
|
49
|
+
#
|
50
|
+
def poll
|
51
|
+
until @stop
|
52
|
+
sleep(0.1) && next if @paused
|
53
|
+
|
54
|
+
start = Time.now.to_f
|
55
|
+
@callback.call(@directories.dup, :recursive => true)
|
56
|
+
@turnstile.signal
|
57
|
+
nap_time = @latency - (Time.now.to_f - start)
|
58
|
+
sleep(nap_time) if nap_time > 0
|
59
|
+
end
|
60
|
+
rescue Interrupt
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Listen
|
4
|
+
module Adapters
|
5
|
+
|
6
|
+
# Adapter implementation for Windows `fchange`.
|
7
|
+
#
|
8
|
+
class Windows < Adapter
|
9
|
+
|
10
|
+
# Initializes the Adapter. See {Listen::Adapter#initialize} for more info.
|
11
|
+
#
|
12
|
+
def initialize(directories, options = {}, &callback)
|
13
|
+
super
|
14
|
+
@worker = init_worker
|
15
|
+
end
|
16
|
+
|
17
|
+
# Starts the adapter.
|
18
|
+
#
|
19
|
+
# @param [Boolean] blocking whether or not to block the current thread after starting
|
20
|
+
#
|
21
|
+
def start(blocking = true)
|
22
|
+
@mutex.synchronize do
|
23
|
+
return if @stop == false
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
@worker_thread = Thread.new { @worker.run }
|
28
|
+
@poll_thread = Thread.new { poll_changed_dirs(true) }
|
29
|
+
@poll_thread.join if blocking
|
30
|
+
end
|
31
|
+
|
32
|
+
# Stops the adapter.
|
33
|
+
#
|
34
|
+
def stop
|
35
|
+
@mutex.synchronize do
|
36
|
+
return if @stop == true
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
@worker.stop
|
41
|
+
Thread.kill(@worker_thread) if @worker_thread
|
42
|
+
@poll_thread.join
|
43
|
+
end
|
44
|
+
|
45
|
+
# Checks if the adapter is usable on the current OS.
|
46
|
+
#
|
47
|
+
# @return [Boolean] whether usable or not
|
48
|
+
#
|
49
|
+
def self.usable?
|
50
|
+
return false unless RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
51
|
+
|
52
|
+
require 'rb-fchange'
|
53
|
+
true
|
54
|
+
rescue LoadError
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# Initializes a FChange worker and adds a watcher for
|
61
|
+
# each directory passed to the adapter.
|
62
|
+
#
|
63
|
+
# @return [FChange::Notifier] initialized worker
|
64
|
+
#
|
65
|
+
def init_worker
|
66
|
+
worker = FChange::Notifier.new
|
67
|
+
@directories.each do |directory|
|
68
|
+
watcher = worker.watch(directory, :all_events, :recursive) do |event|
|
69
|
+
next if @paused
|
70
|
+
@mutex.synchronize do
|
71
|
+
@changed_dirs << File.expand_path(event.watcher.path)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
worker.add_watcher(watcher)
|
75
|
+
end
|
76
|
+
worker
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'find'
|
3
|
+
require 'pathname'
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
module Listen
|
7
|
+
|
8
|
+
# The directory record stores information about
|
9
|
+
# a directory and keeps track of changes to
|
10
|
+
# the structure of its childs.
|
11
|
+
#
|
12
|
+
class DirectoryRecord
|
13
|
+
attr_reader :directory, :paths, :sha1_checksums
|
14
|
+
|
15
|
+
# Default paths' beginnings that doesn't get stored in the record
|
16
|
+
DEFAULT_IGNORED_PATHS = %w[.bundle .git .DS_Store log tmp vendor]
|
17
|
+
|
18
|
+
# Initializes a directory record.
|
19
|
+
#
|
20
|
+
# @option [String] directory the directory to keep track of
|
21
|
+
#
|
22
|
+
def initialize(directory)
|
23
|
+
@directory = directory
|
24
|
+
raise ArgumentError, "The path '#{directory}' is not a directory!" unless File.directory?(@directory)
|
25
|
+
|
26
|
+
@ignored_paths = Set.new(DEFAULT_IGNORED_PATHS)
|
27
|
+
@filters = Set.new
|
28
|
+
@sha1_checksums = Hash.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the ignored paths in the record
|
32
|
+
#
|
33
|
+
# @return [Array<String>] the ignored paths
|
34
|
+
#
|
35
|
+
def ignored_paths
|
36
|
+
@ignored_paths.to_a
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the filters used in the record to know
|
40
|
+
# which paths should be stored.
|
41
|
+
#
|
42
|
+
# @return [Array<String>] the used filters
|
43
|
+
#
|
44
|
+
def filters
|
45
|
+
@filters.to_a
|
46
|
+
end
|
47
|
+
|
48
|
+
# Adds ignored path to the record.
|
49
|
+
#
|
50
|
+
# @example Ignore some paths
|
51
|
+
# ignore ".git", ".svn"
|
52
|
+
#
|
53
|
+
# @param [String, Array<String>] paths a path or a list of paths to ignore
|
54
|
+
#
|
55
|
+
def ignore(*paths)
|
56
|
+
@ignored_paths.merge(paths)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Adds file filters to the listener.
|
60
|
+
#
|
61
|
+
# @example Filter some files
|
62
|
+
# ignore /\.txt$/, /.*\.zip/
|
63
|
+
#
|
64
|
+
# @param [Array<Regexp>] regexps a list of regexps file filters
|
65
|
+
#
|
66
|
+
# @return [Listen::Listener] the listener itself
|
67
|
+
#
|
68
|
+
def filter(*regexps)
|
69
|
+
@filters.merge(regexps)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns whether a path should be ignored or not.
|
73
|
+
#
|
74
|
+
# @param [String] path the path to test.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
#
|
78
|
+
def ignored?(path)
|
79
|
+
@ignored_paths.any? { |ignored_path| path =~ /#{ignored_path}$/ }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns whether a path should be filtered or not.
|
83
|
+
#
|
84
|
+
# @param [String] path the path to test.
|
85
|
+
#
|
86
|
+
# @return [Boolean]
|
87
|
+
#
|
88
|
+
def filtered?(path)
|
89
|
+
@filters.empty? || @filters.any? { |filter| path =~ filter }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Finds the paths that should be stored and adds them
|
93
|
+
# to the paths' hash.
|
94
|
+
#
|
95
|
+
def build
|
96
|
+
@paths = Hash.new { |h, k| h[k] = Hash.new }
|
97
|
+
important_paths { |path| insert_path(path) }
|
98
|
+
@updated_at = Time.now.to_i
|
99
|
+
end
|
100
|
+
|
101
|
+
# Detects changes in the passed directories, updates
|
102
|
+
# the record with the new changes and returns the changes
|
103
|
+
#
|
104
|
+
# @param [Array] directories the list of directories scan for changes
|
105
|
+
# @param [Hash] options
|
106
|
+
# @option options [Boolean] recursive scan all sub-directories recursively
|
107
|
+
# @option options [Boolean] relative_paths whether or not to use relative paths for changes
|
108
|
+
#
|
109
|
+
# @return [Hash<Array>] the changes
|
110
|
+
#
|
111
|
+
def fetch_changes(directories, options = {})
|
112
|
+
@changes = { :modified => [], :added => [], :removed => [] }
|
113
|
+
directories = directories.sort_by { |el| el.length }.reverse # diff sub-dir first
|
114
|
+
directories.each do |directory|
|
115
|
+
next unless directory[@directory] # Path is or inside directory
|
116
|
+
detect_modifications_and_removals(directory, options)
|
117
|
+
detect_additions(directory, options)
|
118
|
+
end
|
119
|
+
@updated_at = Time.now.to_i
|
120
|
+
@changes
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Detects modifications and removals recursively in a directory.
|
126
|
+
#
|
127
|
+
# @note Modifications detection begins by checking the modification time (mtime)
|
128
|
+
# of files and then by checking content changes (using SHA1-checksum)
|
129
|
+
# when the mtime of files is not changed.
|
130
|
+
#
|
131
|
+
# @param [String] directory the path to analyze
|
132
|
+
# @param [Hash] options
|
133
|
+
# @option options [Boolean] recursive scan all sub-directories recursively
|
134
|
+
# @option options [Boolean] relative_paths whether or not to use relative paths for changes
|
135
|
+
#
|
136
|
+
def detect_modifications_and_removals(directory, options = {})
|
137
|
+
@paths[directory].each do |basename, type|
|
138
|
+
path = File.join(directory, basename)
|
139
|
+
|
140
|
+
case type
|
141
|
+
when 'Dir'
|
142
|
+
if File.directory?(path)
|
143
|
+
detect_modifications_and_removals(path, options) if options[:recursive]
|
144
|
+
else
|
145
|
+
detect_modifications_and_removals(path, { :recursive => true }.merge(options))
|
146
|
+
@paths[directory].delete(basename)
|
147
|
+
@paths.delete("#{directory}/#{basename}")
|
148
|
+
end
|
149
|
+
when 'File'
|
150
|
+
if File.exist?(path)
|
151
|
+
new_mtime = File.mtime(path).to_i
|
152
|
+
if @updated_at < new_mtime || (@updated_at == new_mtime && content_modified?(path))
|
153
|
+
@changes[:modified] << (options[:relative_paths] ? relative_to_base(path) : path)
|
154
|
+
end
|
155
|
+
else
|
156
|
+
@paths[directory].delete(basename)
|
157
|
+
@sha1_checksums.delete(path)
|
158
|
+
@changes[:removed] << (options[:relative_paths] ? relative_to_base(path) : path)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Detects additions in a directory.
|
165
|
+
#
|
166
|
+
# @param [String] directory the path to analyze
|
167
|
+
# @param [Hash] options
|
168
|
+
# @option options [Boolean] recursive scan all sub-directories recursively
|
169
|
+
# @option options [Boolean] relative_paths whether or not to use relative paths for changes
|
170
|
+
#
|
171
|
+
def detect_additions(directory, options = {})
|
172
|
+
# Don't process removed directories
|
173
|
+
return unless File.exist?(directory)
|
174
|
+
|
175
|
+
Find.find(directory) do |path|
|
176
|
+
next if path == @directory
|
177
|
+
|
178
|
+
if File.directory?(path)
|
179
|
+
if ignored?(path) || (directory != path && (!options[:recursive] && existing_path?(path)))
|
180
|
+
Find.prune # Don't look any further into this directory.
|
181
|
+
else
|
182
|
+
insert_path(path)
|
183
|
+
end
|
184
|
+
elsif !ignored?(path) && filtered?(path) && !existing_path?(path)
|
185
|
+
if File.file?(path)
|
186
|
+
@changes[:added] << (options[:relative_paths] ? relative_to_base(path) : path)
|
187
|
+
end
|
188
|
+
insert_path(path)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Returns whether or not a file's content has been modified by
|
194
|
+
# comparing the SHA1-checksum to a stored one.
|
195
|
+
#
|
196
|
+
# @param [String] path the file path
|
197
|
+
#
|
198
|
+
def content_modified?(path)
|
199
|
+
sha1_checksum = Digest::SHA1.file(path).to_s
|
200
|
+
if @sha1_checksums[path] != sha1_checksum
|
201
|
+
@sha1_checksums[path] = sha1_checksum
|
202
|
+
true
|
203
|
+
else
|
204
|
+
false
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Traverses the base directory looking for paths that should
|
209
|
+
# be stored; thus paths that are filters or not ignored.
|
210
|
+
#
|
211
|
+
# @yield [path] an important path
|
212
|
+
#
|
213
|
+
def important_paths
|
214
|
+
Find.find(@directory) do |path|
|
215
|
+
next if path == @directory
|
216
|
+
|
217
|
+
if File.directory?(path)
|
218
|
+
if ignored?(path)
|
219
|
+
Find.prune # Don't look any further into this directory.
|
220
|
+
else
|
221
|
+
yield(path)
|
222
|
+
end
|
223
|
+
elsif !ignored?(path) && filtered?(path)
|
224
|
+
yield(path)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Inserts a path with its type (Dir or File) in paths hash.
|
230
|
+
#
|
231
|
+
# @param [String] path the path to insert in @paths.
|
232
|
+
#
|
233
|
+
def insert_path(path)
|
234
|
+
@paths[File.dirname(path)][File.basename(path)] = File.directory?(path) ? 'Dir' : 'File'
|
235
|
+
end
|
236
|
+
|
237
|
+
# Returns whether or not a path exists in the paths hash.
|
238
|
+
#
|
239
|
+
# @param [String] path the path to check
|
240
|
+
#
|
241
|
+
# @return [Boolean]
|
242
|
+
#
|
243
|
+
def existing_path?(path)
|
244
|
+
@paths[File.dirname(path)][File.basename(path)] != nil
|
245
|
+
end
|
246
|
+
|
247
|
+
# Converts an absolute path to a path that's relative to the base directory.
|
248
|
+
#
|
249
|
+
# @param [String] path the path to convert
|
250
|
+
#
|
251
|
+
# @return [String] the relative path
|
252
|
+
#
|
253
|
+
def relative_to_base(path)
|
254
|
+
path.sub(%r(^#{@directory}/?/), '')
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
module Listen
|
2
|
+
class Listener
|
3
|
+
attr_reader :directory, :directory_record, :adapter
|
4
|
+
|
5
|
+
# The default value for using relative paths in the callback.
|
6
|
+
DEFAULT_TO_RELATIVE_PATHS = false
|
7
|
+
|
8
|
+
# Initializes the directory listener.
|
9
|
+
#
|
10
|
+
# @param [String] directory the directory to listen to
|
11
|
+
# @param [Hash] options the listen options
|
12
|
+
# @option options [String] ignore a list of paths to ignore
|
13
|
+
# @option options [Regexp] filter a list of regexps file filters
|
14
|
+
# @option options [Float] latency the delay between checking for changes in seconds
|
15
|
+
# @option options [Boolean] relative_paths whether or not to use relative-paths in the callback
|
16
|
+
# @option options [Boolean] force_polling whether to force the polling adapter or not
|
17
|
+
# @option options [String, Boolean] polling_fallback_message to change polling fallback message or remove it
|
18
|
+
#
|
19
|
+
# @yield [modified, added, removed] the changed files
|
20
|
+
# @yieldparam [Array<String>] modified the list of modified files
|
21
|
+
# @yieldparam [Array<String>] added the list of added files
|
22
|
+
# @yieldparam [Array<String>] removed the list of removed files
|
23
|
+
#
|
24
|
+
def initialize(directory, options = {}, &block)
|
25
|
+
@block = block
|
26
|
+
@directory = directory
|
27
|
+
@directory_record = DirectoryRecord.new(directory)
|
28
|
+
@use_relative_paths = DEFAULT_TO_RELATIVE_PATHS
|
29
|
+
|
30
|
+
@use_relative_paths = options.delete(:relative_paths) if options[:relative_paths]
|
31
|
+
@directory_record.ignore(*options.delete(:ignore)) if options[:ignore]
|
32
|
+
@directory_record.filter(*options.delete(:filter)) if options[:filter]
|
33
|
+
|
34
|
+
@adapter_options = options
|
35
|
+
end
|
36
|
+
|
37
|
+
# Starts the listener by initializing the adapter and building
|
38
|
+
# the directory record concurrently, then it starts the adapter to watch
|
39
|
+
# for changes.
|
40
|
+
#
|
41
|
+
# @param [Boolean] blocking whether or not to block the current thread after starting
|
42
|
+
#
|
43
|
+
def start(blocking = true)
|
44
|
+
t = Thread.new { @adapter = initialize_adapter }
|
45
|
+
@directory_record.build
|
46
|
+
t.join
|
47
|
+
@adapter.start(blocking)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Stops the listener.
|
51
|
+
#
|
52
|
+
def stop
|
53
|
+
@adapter.stop
|
54
|
+
end
|
55
|
+
|
56
|
+
# Pauses the listener.
|
57
|
+
#
|
58
|
+
# @return [Listen::Listener] the listener
|
59
|
+
#
|
60
|
+
def pause
|
61
|
+
@adapter.paused = true
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
# Unpauses the listener.
|
66
|
+
#
|
67
|
+
# @return [Listen::Listener] the listener
|
68
|
+
#
|
69
|
+
def unpause
|
70
|
+
@directory_record.build
|
71
|
+
@adapter.paused = false
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns whether the listener is paused or not.
|
76
|
+
#
|
77
|
+
# @return [Boolean] adapter paused status
|
78
|
+
#
|
79
|
+
def paused?
|
80
|
+
!!@adapter && @adapter.paused == true
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds ignored paths to the listener.
|
84
|
+
#
|
85
|
+
# @param (see Listen::DirectoryRecord#ignore)
|
86
|
+
#
|
87
|
+
# @return [Listen::Listener] the listener
|
88
|
+
#
|
89
|
+
def ignore(*paths)
|
90
|
+
@directory_record.ignore(*paths)
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Adds file filters to the listener.
|
95
|
+
#
|
96
|
+
# @param (see Listen::DirectoryRecord#filter)
|
97
|
+
#
|
98
|
+
# @return [Listen::Listener] the listener
|
99
|
+
#
|
100
|
+
def filter(*regexps)
|
101
|
+
@directory_record.filter(*regexps)
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# Sets the latency for the adapter. This is a helper method
|
106
|
+
# to simplify changing the latency directly from the listener.
|
107
|
+
#
|
108
|
+
# @example Wait 0.5 seconds each time before checking changes
|
109
|
+
# latency 0.5
|
110
|
+
#
|
111
|
+
# @param [Float] seconds the amount of delay, in seconds
|
112
|
+
#
|
113
|
+
# @return [Listen::Listener] the listener
|
114
|
+
#
|
115
|
+
def latency(seconds)
|
116
|
+
@adapter_options[:latency] = seconds
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
# Defines whether the use of the polling adapter
|
121
|
+
# should be forced or not.
|
122
|
+
#
|
123
|
+
# @example Forcing the use of the polling adapter
|
124
|
+
# force_polling true
|
125
|
+
#
|
126
|
+
# @param [Boolean] value whether to force the polling adapter or not
|
127
|
+
#
|
128
|
+
# @return [Listen::Listener] the listener
|
129
|
+
#
|
130
|
+
def force_polling(value)
|
131
|
+
@adapter_options[:force_polling] = value
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
# Defines a custom polling fallback message of disable it.
|
136
|
+
#
|
137
|
+
# @example Disabling the polling fallback message
|
138
|
+
# polling_fallback_message false
|
139
|
+
#
|
140
|
+
# @param [String, Boolean] value to change polling fallback message or remove it
|
141
|
+
#
|
142
|
+
# @return [Listen::Listener] the listener
|
143
|
+
#
|
144
|
+
def polling_fallback_message(value)
|
145
|
+
@adapter_options[:polling_fallback_message] = value
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
# Sets the callback that gets called on changes.
|
150
|
+
#
|
151
|
+
# @example Assign a callback to be called on changes
|
152
|
+
# callback = lambda { |modified, added, removed| ... }
|
153
|
+
# change &callback
|
154
|
+
#
|
155
|
+
# @param [Proc] block the callback proc
|
156
|
+
#
|
157
|
+
# @return [Listen::Listener] the listener
|
158
|
+
#
|
159
|
+
def change(&block) # modified, added, removed
|
160
|
+
@block = block
|
161
|
+
self
|
162
|
+
end
|
163
|
+
|
164
|
+
# Runs the callback passing it the changes if there are any.
|
165
|
+
#
|
166
|
+
# @param (see Listen::DirectoryRecord#fetch_changes)
|
167
|
+
#
|
168
|
+
def on_change(directories, options = {})
|
169
|
+
changes = @directory_record.fetch_changes(directories, options.merge(
|
170
|
+
:relative_paths => @use_relative_paths
|
171
|
+
))
|
172
|
+
unless changes.values.all? { |paths| paths.empty? }
|
173
|
+
@block.call(changes[:modified],changes[:added],changes[:removed])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
# Initializes an adapter passing it the callback and adapters' options.
|
180
|
+
#
|
181
|
+
def initialize_adapter
|
182
|
+
callback = lambda { |changed_dirs, options| self.on_change(changed_dirs, options) }
|
183
|
+
Adapter.select_and_initialize(@directory, @adapter_options, &callback)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|