listen 3.6.0 → 3.9.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 656e49f1b6eca9a31fd9c09b916aa73ed6d3df255e4859c4b77ebdb7a0f4a6bf
4
- data.tar.gz: 98be9697f64242c869fa47211477f84f8b636402fa4e865989e1b54e020a8032
3
+ metadata.gz: b365e353c2a0dc2a64459faa2c30a9b472130637b5fb4f50977c07adb2c6fd0c
4
+ data.tar.gz: 82d72d4f26f25a7fd1e285fbebe66fffcee246999696313a4f19997ce2017ef5
5
5
  SHA512:
6
- metadata.gz: af8bfbe37ce9b791f78ebdee29c32781742f3e58e98eae92381c34169bdf389db38f82228b77a56ba13e73646dbb7d2dae9a275be0c5b75e300010adb4382129
7
- data.tar.gz: f97c76664f9aa893bd89bcf93484701a6bda473ab9b13e2101cacb4f450f5ca0d116362027368fe561a724fb0c55213bbc6944bd58b0ee4cb6812f588d00feeb
6
+ metadata.gz: f52228164dce447a048dea3e04268909004e17f0b40788495f58f9afc9a9a9f3a0207fd0acb541d0cffe0be78836a10f652acf6ff418cea9ea119708eaec0b83
7
+ data.tar.gz: ee91854777075dc80f4cbcff3e507f4ca162aabe37fa11709b145184ada246efd0401ba89a50de8008c2ca7345d0dd08d20bbad7c6d9272004ad3581e74abca5
data/README.md CHANGED
@@ -14,7 +14,7 @@ The `listen` gem listens to file modifications and notifies you about the change
14
14
  * You can watch multiple directories.
15
15
  * Regexp-patterns for ignoring paths for more accuracy and speed
16
16
  * Increased change detection accuracy on OS X HFS and VFAT volumes.
17
- * Continuous Integration: tested on selected Ruby environments via [Github Workflows](https:///github.com/guard/listen/master/.github/workflows).
17
+ * Continuous Integration: tested on selected Ruby environments via [Github Workflows](https://github.com/guard/listen/tree/master/.github/workflows).
18
18
 
19
19
  ## Issues / limitations
20
20
 
@@ -97,23 +97,23 @@ The callback receives **three** array parameters: `modified`, `added` and `remov
97
97
  Each of these three is always an array with 0 or more entries.
98
98
  Each array entry is an absolute path.
99
99
 
100
- ### Pause / unpause / stop
100
+ ### Pause / start / stop
101
101
 
102
- Listeners can also be easily paused/unpaused:
102
+ Listeners can also be easily paused and later un-paused with start:
103
103
 
104
104
  ``` ruby
105
105
  listener = Listen.to('dir/path/to/listen') { |modified, added, removed| puts 'handle changes here...' }
106
106
 
107
107
  listener.start
108
- listener.paused? # => false
108
+ listener.paused? # => false
109
109
  listener.processing? # => true
110
110
 
111
- listener.pause # stops processing changes (but keeps on collecting them)
112
- listener.paused? # => true
111
+ listener.pause # stops processing changes (but keeps on collecting them)
112
+ listener.paused? # => true
113
113
  listener.processing? # => false
114
114
 
115
- listener.unpause # resumes processing changes ("start" would do the same)
116
- listener.stop # stop both listening to changes and processing them
115
+ listener.start # resumes processing changes
116
+ listener.stop # stop both listening to changes and processing them
117
117
  ```
118
118
 
119
119
  Note: While paused, `listen` keeps on collecting changes in the background - to clear them, call `stop`.
@@ -122,7 +122,7 @@ listener.stop # stop both listening to changes and processing them
122
122
 
123
123
  ### Ignore / ignore!
124
124
 
125
- `Listen` ignores some directories and extensions by default (See DEFAULT_IGNORED_DIRECTORIES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer).
125
+ `Listen` ignores some directories and extensions by default (See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer).
126
126
  You can add ignoring patterns with the `ignore` option/method or overwrite default with `ignore!` option/method.
127
127
 
128
128
  ``` ruby
@@ -155,9 +155,9 @@ Note: `:only` regexp patterns are evaluated only against relative **file** paths
155
155
 
156
156
  All the following options can be set through the `Listen.to` after the directory path(s) params.
157
157
 
158
- ```ruby
158
+ ``` ruby
159
159
  ignore: [%r{/foo/bar}, /\.pid$/, /\.coffee$/] # Ignore a list of paths
160
- # default: See DEFAULT_IGNORED_DIRECTORIES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer
160
+ # default: See DEFAULT_IGNORED_FILES and DEFAULT_IGNORED_EXTENSIONS in Listen::Silencer
161
161
 
162
162
  ignore!: %r{/foo/bar} # Same as ignore options, but overwrite default ignored paths.
163
163
 
@@ -187,7 +187,7 @@ This is the primary method of debugging.
187
187
 
188
188
  ### Custom Logger
189
189
  You can call `Listen.logger =` to set a custom `listen` logger for the process. For example:
190
- ```
190
+ ``` ruby
191
191
  Listen.logger = Rails.logger
192
192
  ```
193
193
 
@@ -197,7 +197,7 @@ If no custom logger is set, a default `listen` logger which logs to to `STDERR`
197
197
  The default logger defaults to the `error` logging level (severity).
198
198
  You can override the logging level by setting the environment variable `LISTEN_GEM_DEBUGGING=<level>`.
199
199
  For `<level>`, all standard `::Logger` levels are supported, with any mix of upper-/lower-case:
200
- ```
200
+ ``` ruby
201
201
  export LISTEN_GEM_DEBUGGING=debug # or 2 [deprecated]
202
202
  export LISTEN_GEM_DEBUGGING=info # or 1 or true or yes [deprecated]
203
203
  export LISTEN_GEM_DEBUGGING=warn
@@ -210,9 +210,38 @@ Note: The alternate values `1`, `2`, `true` and `yes` shown above are deprecated
210
210
 
211
211
  ### Disabling Logging
212
212
  If you want to disable `listen` logging, set
213
- ```
213
+ ``` ruby
214
214
  Listen.logger = ::Logger.new('/dev/null')
215
215
  ```
216
+
217
+ ### Adapter Warnings
218
+ If listen is having trouble with the underlying adapter, it will display warnings with `Kernel#warn` by default,
219
+ which in turn writes to STDERR.
220
+ Sometimes this is not desirable, for example in an environment where STDERR is ignored.
221
+ For these reasons, the behavior can be configured using `Listen.adapter_warn_behavior =`:
222
+ ``` ruby
223
+ Listen.adapter_warn_behavior = :warn # default (true means the same)
224
+ Listen.adapter_warn_behavior = :log # send to logger.warn
225
+ Listen.adapter_warn_behavior = :silent # suppress all adapter warnings (nil or false mean the same)
226
+ ```
227
+ Also there are some cases where specific warnings are not helpful.
228
+ For example, if you are using the polling adapter--and expect to--you can suppress the warning about it
229
+ by providing a callable object like a lambda or proc that determines the behavior based on the `message`:
230
+ ``` ruby
231
+ Listen.adapter_warn_behavior = ->(message) do
232
+ case message
233
+ when /Listen will be polling for changes/
234
+ :silent
235
+ when /directory is already being watched/
236
+ :log
237
+ else
238
+ :warn
239
+ end
240
+ end
241
+ ```
242
+ In cases where the `Listen` gem is embedded inside another service--such as `guard`--the above configuration
243
+ can be set in the environment variable `LISTEN_GEM_ADAPTER_WARN_BEHAVIOR=warn|log|silent`.
244
+
216
245
  ## Listen Adapters
217
246
 
218
247
  The `Listen` gem has a set of adapters to notify it when there are changes.
@@ -51,7 +51,7 @@ module Listen
51
51
  # TODO: separate config per directory (some day maybe)
52
52
  change_config = Change::Config.new(config.queue, config.silencer)
53
53
  config.directories.each do |dir|
54
- record = Record.new(dir)
54
+ record = Record.new(dir, config.silencer)
55
55
  snapshot = Change.new(change_config, record)
56
56
  @snapshots[dir] = snapshot
57
57
  end
@@ -34,7 +34,7 @@ module Listen
34
34
  require 'find'
35
35
  true
36
36
  rescue LoadError
37
- Kernel.warn BUNDLER_DECLARE_GEM
37
+ Listen.adapter_warn(BUNDLER_DECLARE_GEM)
38
38
  false
39
39
  end
40
40
 
@@ -16,6 +16,12 @@ module Listen
16
16
  Pathname.new(directory.to_s).realpath
17
17
  end
18
18
 
19
+ @directories.each do |pathname|
20
+ unless pathname.directory?
21
+ fail ArgumentError, "must be a directory: #{pathname}"
22
+ end
23
+ end
24
+
19
25
  @silencer = silencer
20
26
  @queue = queue
21
27
  @adapter_options = adapter_options
@@ -30,7 +30,7 @@ module Listen
30
30
  require 'rb-fsevent'
31
31
  fsevent_version = Gem::Version.new(FSEvent::VERSION)
32
32
  return true if fsevent_version <= Gem::Version.new('0.9.4')
33
- Kernel.warn INCOMPATIBLE_GEM_VERSION
33
+ Listen.adapter_warn(INCOMPATIBLE_GEM_VERSION)
34
34
  false
35
35
  end
36
36
 
@@ -24,17 +24,14 @@ module Listen
24
24
  README_URL = 'https://github.com/guard/listen'\
25
25
  '/blob/master/README.md#increasing-the-amount-of-inotify-watchers'
26
26
 
27
- INOTIFY_LIMIT_MESSAGE = <<-EOS
28
- FATAL: Listen error: unable to monitor directories for changes.
29
- Visit #{README_URL} for info on how to fix this.
30
- EOS
31
-
32
27
  def _configure(directory, &callback)
33
28
  require 'rb-inotify'
34
29
  @worker ||= ::INotify::Notifier.new
35
30
  @worker.watch(directory.to_s, *options.events, &callback)
36
31
  rescue Errno::ENOSPC
37
- abort(INOTIFY_LIMIT_MESSAGE)
32
+ raise ::Listen::Error::INotifyMaxWatchesExceeded, <<~EOS
33
+ Unable to monitor directories for changes because iNotify max watches exceeded. See #{README_URL} .
34
+ EOS
38
35
  end
39
36
 
40
37
  def _run
@@ -20,7 +20,7 @@ module Listen
20
20
  Listen.logger.debug format('wdm - load failed: %s:%s', $ERROR_INFO,
21
21
  $ERROR_POSITION * "\n")
22
22
 
23
- Kernel.warn BUNDLER_DECLARE_GEM
23
+ Listen.adapter_warn(BUNDLER_DECLARE_GEM)
24
24
  false
25
25
  end
26
26
 
@@ -36,7 +36,7 @@ module Listen
36
36
 
37
37
  def _warn_polling_fallback(options)
38
38
  msg = options.fetch(:polling_fallback_message, POLLING_FALLBACK_MESSAGE)
39
- Kernel.warn "[Listen warning]:\n #{msg}" if msg
39
+ Listen.adapter_warn("[Listen warning]:\n #{msg}") if msg
40
40
  end
41
41
  end
42
42
  end
data/lib/listen/cli.rb CHANGED
@@ -18,9 +18,9 @@ module Listen
18
18
 
19
19
  class_option :directory,
20
20
  type: :array,
21
- default: '.',
21
+ default: ['.'],
22
22
  aliases: '-d',
23
- banner: 'The directory to listen to'
23
+ banner: 'One or more directories to listen to'
24
24
 
25
25
  class_option :relative,
26
26
  type: :boolean,
@@ -55,7 +55,7 @@ module Listen
55
55
  end
56
56
  end
57
57
 
58
- listener = Listen.to(directory, relative: relative, &callback)
58
+ listener = Listen.to(*directory, relative: relative, &callback)
59
59
 
60
60
  listener.start
61
61
 
@@ -36,7 +36,7 @@ module Listen
36
36
  end
37
37
 
38
38
  # TODO: this is not tested properly
39
- previous = previous.reject { |entry, _| current.include? path + entry }
39
+ previous = previous.reject { |entry, _| current.include?(path + entry) }
40
40
 
41
41
  _async_changes(snapshot, Pathname.new(rel_path), previous, options)
42
42
  rescue Errno::ENOENT, Errno::EHOSTDOWN
data/lib/listen/error.rb CHANGED
@@ -6,5 +6,6 @@ module Listen
6
6
  class Error < RuntimeError
7
7
  class NotStarted < Error; end
8
8
  class SymlinkLoop < Error; end
9
+ class INotifyMaxWatchesExceeded < Error; end
9
10
  end
10
11
  end
data/lib/listen/logger.rb CHANGED
@@ -6,13 +6,27 @@ module Listen
6
6
  # Listen.logger will always be present.
7
7
  # If you don't want logging, set Listen.logger = ::Logger.new('/dev/null', level: ::Logger::UNKNOWN)
8
8
 
9
+ @adapter_warn_behavior = :warn
10
+
9
11
  class << self
10
12
  attr_writer :logger
13
+ attr_accessor :adapter_warn_behavior
11
14
 
12
15
  def logger
13
16
  @logger ||= default_logger
14
17
  end
15
18
 
19
+ def adapter_warn(message)
20
+ case ENV['LISTEN_GEM_ADAPTER_WARN_BEHAVIOR']&.to_sym || adapter_warn_behavior_callback(message)
21
+ when :log
22
+ logger.warn(message)
23
+ when :silent, nil, false
24
+ # do nothing
25
+ else # :warn
26
+ warn(message)
27
+ end
28
+ end
29
+
16
30
  private
17
31
 
18
32
  def default_logger
@@ -32,5 +46,20 @@ module Listen
32
46
 
33
47
  ::Logger.new(STDERR, level: level)
34
48
  end
49
+
50
+ def adapter_warn_behavior_callback(message)
51
+ if adapter_warn_behavior.respond_to?(:call)
52
+ case behavior = adapter_warn_behavior.call(message)
53
+ when Symbol
54
+ behavior
55
+ when false, nil
56
+ :silent
57
+ else
58
+ :warn
59
+ end
60
+ else
61
+ adapter_warn_behavior
62
+ end
63
+ end
35
64
  end
36
65
  end
@@ -30,6 +30,12 @@ module Listen
30
30
  @real_dirs.add?(real_path) or _fail(entry.sys_path, real_path)
31
31
  end
32
32
 
33
+ # Leaving this stub here since some warning work-arounds were referring to it.
34
+ # Deprecated. Will be removed in Listen v4.0.
35
+ def warn(message)
36
+ Listen.adapter_warn(message)
37
+ end
38
+
33
39
  private
34
40
 
35
41
  def _fail(symlinked, real_path)
data/lib/listen/record.rb CHANGED
@@ -11,14 +11,15 @@ module Listen
11
11
 
12
12
  attr_reader :root
13
13
 
14
- def initialize(directory)
15
- @tree = _auto_hash
14
+ def initialize(directory, silencer)
15
+ reset_tree
16
16
  @root = directory.to_s
17
+ @silencer = silencer
17
18
  end
18
19
 
19
20
  def add_dir(rel_path)
20
- if ![nil, '', '.'].include?(rel_path)
21
- @tree[rel_path] ||= {}
21
+ if !empty_dirname?(rel_path.to_s)
22
+ @tree[rel_path.to_s]
22
23
  end
23
24
  end
24
25
 
@@ -34,32 +35,32 @@ module Listen
34
35
 
35
36
  def file_data(rel_path)
36
37
  dirname, basename = Pathname(rel_path).split.map(&:to_s)
37
- if [nil, '', '.'].include? dirname
38
- @tree[basename] ||= {}
38
+ if empty_dirname?(dirname)
39
39
  @tree[basename].dup
40
40
  else
41
- @tree[dirname] ||= {}
42
41
  @tree[dirname][basename] ||= {}
43
42
  @tree[dirname][basename].dup
44
43
  end
45
44
  end
46
45
 
47
46
  def dir_entries(rel_path)
48
- subtree = if ['', '.'].include? rel_path.to_s
47
+ rel_path_s = rel_path.to_s
48
+ subtree = if empty_dirname?(rel_path_s)
49
49
  @tree
50
50
  else
51
- @tree[rel_path.to_s] ||= _auto_hash
52
- @tree[rel_path.to_s]
51
+ @tree[rel_path_s]
53
52
  end
54
53
 
55
- subtree.transform_values do |values|
56
- # only get data for file entries
57
- values.key?(:mtime) ? values : {}
54
+ subtree.each_with_object({}) do |(key, values), result|
55
+ # only return data for file entries inside the dir (which will each be sub-hashes)
56
+ if values.is_a?(Hash)
57
+ result[key] = values.has_key?(:mtime) ? values : {}
58
+ end
58
59
  end
59
60
  end
60
61
 
61
62
  def build
62
- @tree = _auto_hash
63
+ reset_tree
63
64
  # TODO: test with a file name given
64
65
  # TODO: test other permissions
65
66
  # TODO: test with mixed encoding
@@ -71,15 +72,18 @@ module Listen
71
72
 
72
73
  private
73
74
 
74
- def _auto_hash
75
- Hash.new { |h, k| h[k] = {} }
75
+ def empty_dirname?(dirname)
76
+ dirname == '.' || dirname == ''
77
+ end
78
+
79
+ def reset_tree
80
+ @tree = Hash.new { |h, k| h[k] = {} }
76
81
  end
77
82
 
78
83
  def _fast_update_file(dirname, basename, data)
79
- if [nil, '', '.'].include?(dirname)
80
- @tree[basename] = (@tree[basename] || {}).merge(data)
84
+ if empty_dirname?(dirname.to_s)
85
+ @tree[basename] = @tree[basename].merge(data)
81
86
  else
82
- @tree[dirname] ||= {}
83
87
  @tree[dirname][basename] = (@tree[dirname][basename] || {}).merge(data)
84
88
  end
85
89
  end
@@ -87,7 +91,7 @@ module Listen
87
91
  def _fast_unset_path(dirname, basename)
88
92
  # this may need to be reworked to properly remove
89
93
  # entries from a tree, without adding non-existing dirs to the record
90
- if [nil, '', '.'].include?(dirname)
94
+ if empty_dirname?(dirname.to_s)
91
95
  if @tree.key?(basename)
92
96
  @tree.delete(basename)
93
97
  end
@@ -98,6 +102,8 @@ module Listen
98
102
 
99
103
  def _fast_build_dir(remaining, symlink_detector)
100
104
  entry = remaining.pop
105
+ return if @silencer.silenced?(entry.record_dir_key, :dir)
106
+
101
107
  children = entry.children # NOTE: children() implicitly tests if dir
102
108
  symlink_detector.verify_unwatched!(entry)
103
109
  children.each { |child| remaining << child }
@@ -3,8 +3,8 @@
3
3
  module Listen
4
4
  class Silencer
5
5
  # The default list of directories that get ignored.
6
- DEFAULT_IGNORED_DIRECTORIES = %r{^(?:
7
- \.git
6
+ DEFAULT_IGNORED_FILES = %r{\A(?:
7
+ \.git
8
8
  | \.svn
9
9
  | \.hg
10
10
  | \.rbx
@@ -13,8 +13,12 @@ module Listen
13
13
  | vendor/bundle
14
14
  | log
15
15
  | tmp
16
- |vendor/ruby
17
- )(/|$)}x.freeze
16
+ | vendor/ruby
17
+
18
+ # emacs temp files
19
+ | \#.+\#
20
+ | \.\#.+
21
+ )(/|\z)}x.freeze
18
22
 
19
23
  # The default list of files that get ignored.
20
24
  DEFAULT_IGNORED_EXTENSIONS = %r{(?:
@@ -35,7 +39,7 @@ module Listen
35
39
  | ^4913
36
40
 
37
41
  # Sed temporary files - but without actual words, like 'sedatives'
38
- | (?:^
42
+ | (?:\A
39
43
  sed
40
44
 
41
45
  (?:
@@ -55,25 +59,23 @@ module Listen
55
59
  | \.DS_Store
56
60
  | \.tmp
57
61
  | ~
58
- )$}x.freeze
62
+ )\z}x.freeze
59
63
 
64
+ # TODO: deprecate these mutators; use attr_reader instead
60
65
  attr_accessor :only_patterns, :ignore_patterns
61
66
 
62
- def initialize
63
- configure({})
67
+ def initialize(**options)
68
+ configure(options)
64
69
  end
65
70
 
71
+ # TODO: deprecate this mutator
66
72
  def configure(options)
67
73
  @only_patterns = options[:only] ? Array(options[:only]) : nil
68
74
  @ignore_patterns = _init_ignores(options[:ignore], options[:ignore!])
69
75
  end
70
76
 
71
- # Note: relative_path is temporarily expected to be a relative Pathname to
72
- # make refactoring easier (ideally, it would take a string)
73
-
74
- # TODO: switch type and path places - and verify
75
77
  def silenced?(relative_path, type)
76
- path = relative_path.to_s
78
+ path = relative_path.to_s # in case it is a Pathname
77
79
 
78
80
  _ignore?(path) || (only_patterns && type == :file && !_only?(path))
79
81
  end
@@ -91,7 +93,7 @@ module Listen
91
93
  def _init_ignores(ignores, overrides)
92
94
  patterns = []
93
95
  unless overrides
94
- patterns << DEFAULT_IGNORED_DIRECTORIES
96
+ patterns << DEFAULT_IGNORED_FILES
95
97
  patterns << DEFAULT_IGNORED_EXTENSIONS
96
98
  end
97
99
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Listen
4
- VERSION = '3.6.0'
4
+ VERSION = '3.9.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listen
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thibaud Guillaume-Gentil
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-20 00:00:00.000000000 Z
11
+ date: 2024-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb-fsevent
@@ -103,10 +103,10 @@ metadata:
103
103
  allowed_push_host: https://rubygems.org
104
104
  bug_tracker_uri: https://github.com/guard/listen/issues
105
105
  changelog_uri: https://github.com/guard/listen/releases
106
- documentation_uri: https://www.rubydoc.info/gems/listen/3.6.0
106
+ documentation_uri: https://www.rubydoc.info/gems/listen/3.9.0
107
107
  homepage_uri: https://github.com/guard/listen
108
- source_code_uri: https://github.com/guard/listen/tree/v3.6.0
109
- post_install_message:
108
+ source_code_uri: https://github.com/guard/listen/tree/v3.9.0
109
+ post_install_message:
110
110
  rdoc_options: []
111
111
  require_paths:
112
112
  - lib
@@ -121,8 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  requirements: []
124
- rubygems_version: 3.0.1
125
- signing_key:
124
+ rubygems_version: 3.4.6
125
+ signing_key:
126
126
  specification_version: 4
127
127
  summary: Listen to file modifications
128
128
  test_files: []