build-files-monitor 0.3.0 → 0.4.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: 7cf4ab4a7ae074043dc0c40261cf606faaa3679d2b8f79b431b46e11512f3d53
4
- data.tar.gz: e729c5b8c18580d5706bd8b8f68b68a7e151f7ec770bf0974b9b2eeb8696614d
3
+ metadata.gz: 435b84b61738b4e31fed992817a7580797c30f2099e1d3e4188e3ce535f92cf0
4
+ data.tar.gz: ea1f935718b7982f5469a2609603527758b5287f0869058f98d6ba6451fff82b
5
5
  SHA512:
6
- metadata.gz: b877ff6664197406f370cf5b00559dbaaaa23c8fb53b06738f216f0923d26f3c6874694ab6748f0d40e9ac81b55c3d661c1f027073b7767e1cb009bde9614e2c
7
- data.tar.gz: 7a15a46cdb8c1528c1cfe322db0ba7f1028170b86341c86ad9455f8266829325ceb7a121ec2fa6d52cc66b2103d2d42c4ff7312822c8676b57dd88106bf18b90
6
+ metadata.gz: d5efe0b08fd6565f8a9e4b8a6f63839f226b76412854e24b5b65361ce1dc40ae06c63a4da9cdb4fe3fa3bdfdd9378a2de37e78730ff4b20eb095fdddfa5b0343
7
+ data.tar.gz: 9f628a544ac79fad1d0d908e8f9253c4180ec3cfd54d539fb319f53c297d0d5a626978cde1373df708b96f71fa8ce42e539413f9f4e11c0f12579fe01c7ff201
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,30 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
- require 'build/files/state'
6
+ require "build/files/state"
7
7
 
8
8
  module Build
9
9
  module Files
10
10
  module Monitor
11
+ # Represents a tracked set of files with an associated callback.
12
+ #
13
+ # A handle is created when you call {Polling#track_changes} and connects a set of files to a callback block that fires when changes are detected. The handle maintains the state of monitored files and can be removed from the monitor when no longer needed.
11
14
  class Handle
15
+ # Initialize a new handle.
16
+ #
17
+ # @parameter monitor [Polling] The monitor that owns this handle.
18
+ # @parameter files [List] The list of files to track.
19
+ # @parameter block [Proc] The callback to invoke when changes are detected.
12
20
  def initialize(monitor, files, &block)
13
21
  @monitor = monitor
14
22
  @state = State.new(files)
15
23
  @block = block
16
24
  end
17
-
25
+
26
+ # @attribute [Polling] The monitor that owns this handle.
18
27
  attr :monitor
19
-
28
+
29
+ # Update the internal state of tracked files.
30
+ #
31
+ # This method forces an update of the file state without invoking the callback.
20
32
  def commit!
21
33
  @state.update!
22
34
  end
23
-
35
+
36
+ # @returns [Array(Path)] The root directories being monitored by this handle.
24
37
  def directories
25
38
  @state.files.roots
26
39
  end
27
-
40
+
41
+ # Remove this handle from the monitor.
42
+ #
43
+ # After calling this method, the callback will no longer be invoked when changes are detected.
28
44
  def remove!
29
45
  @monitor.delete(self)
30
46
  end
@@ -37,6 +53,7 @@ module Build
37
53
  end
38
54
  end
39
55
 
56
+ # @returns [String] A string representation of the handle.
40
57
  def to_s
41
58
  "\#<#{self.class} @state=#{@state} @block=#{@block}>"
42
59
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
+
6
+ require_relative "polling"
7
+ require "io/watch"
8
+
9
+ module Build
10
+ module Files
11
+ module Monitor
12
+ # A platform-specific filesystem monitor using native OS APIs.
13
+ #
14
+ # This implementation uses platform-specific APIs (FSEvent on macOS, INotify on Linux) for efficient, event-driven file monitoring. It extends {Polling} but replaces the polling mechanism with native filesystem events.
15
+ class Native < Polling
16
+ # Run the monitor using native filesystem events.
17
+ #
18
+ # This method blocks until interrupted via `throw :interrupt`. Unlike {Polling#run}, this uses native OS events rather than polling.
19
+ #
20
+ # @yields After each filesystem event.
21
+ def run(**options, &block)
22
+ catch(:interrupt) do
23
+ while true
24
+ run_roots(self.roots, **options, &block)
25
+ end
26
+ end
27
+ end
28
+
29
+ # Monitor the specified roots for changes using native events.
30
+ #
31
+ # @parameter roots [Array(String)] The root directories to monitor.
32
+ # @yields {...} After each filesystem event.
33
+ # @returns [Boolean] True if the set of monitored directories was updated.
34
+ def run_roots(roots, **options, &block)
35
+ monitor = IO::Watch::Monitor.new(self.roots, **options)
36
+
37
+ monitor.run do |event|
38
+ if root = event[:root]
39
+ self.update([root])
40
+
41
+ yield if block_given?
42
+
43
+ if self.updated
44
+ return true
45
+ end
46
+ end
47
+ end
48
+
49
+ return false
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,17 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
- require 'set'
7
- require 'logger'
6
+ require "set"
7
+ require "logger"
8
8
 
9
- require_relative 'handle'
9
+ require_relative "handle"
10
10
 
11
11
  module Build
12
12
  module Files
13
13
  module Monitor
14
+ # A cross-platform filesystem monitor that uses polling to detect changes.
15
+ #
16
+ # This implementation works on all platforms by periodically checking file modification times. While less efficient than platform-specific native implementations, it provides a reliable fallback for platforms without native filesystem event support.
14
17
  class Polling
18
+ # Initialize a new polling monitor.
19
+ #
20
+ # @parameter logger [Logger] Optional logger for debugging monitor activity.
15
21
  def initialize(logger: nil)
16
22
  @directories = Hash.new do |hash, key|
17
23
  hash[key] = Set.new
@@ -24,6 +30,7 @@ module Build
24
30
  @logger = logger || Logger.new(nil)
25
31
  end
26
32
 
33
+ # @attribute [Boolean] Whether the set of monitored directories has been updated.
27
34
  attr :updated
28
35
 
29
36
  # Notify the monitor that files in these directories have changed.
@@ -44,10 +51,14 @@ module Build
44
51
  end
45
52
  end
46
53
 
54
+ # @returns [Array(String)] The root directories currently being monitored.
47
55
  def roots
48
56
  @directories.keys
49
57
  end
50
58
 
59
+ # Delete a handle from the monitor.
60
+ #
61
+ # @parameter handle [Handle] The handle to remove.
51
62
  def delete(handle)
52
63
  if @deletions
53
64
  @logger.debug{"Delayed delete handle: #{handle}"}
@@ -57,12 +68,22 @@ module Build
57
68
  end
58
69
  end
59
70
 
71
+ # Track changes to a set of files.
72
+ #
73
+ # @parameter files [List] The list of files to monitor.
74
+ # @yields {|state| ...} When changes are detected.
75
+ # @parameter state [State] The current state with information about added, changed, and removed files.
76
+ # @returns [Handle] A handle that can be used to stop tracking these files.
60
77
  def track_changes(files, &block)
61
78
  handle = Handle.new(self, files, &block)
62
79
 
63
80
  add(handle)
64
81
  end
65
82
 
83
+ # Add a handle to the monitor.
84
+ #
85
+ # @parameter handle [Handle] The handle to add.
86
+ # @returns [Handle] The added handle.
66
87
  def add(handle)
67
88
  @logger.debug{"Adding handle: #{handle}"}
68
89
 
@@ -82,9 +103,13 @@ module Build
82
103
  handle
83
104
  end
84
105
 
85
- def run(**options, &block)
86
- latency = options.fetch(:latency, 1.0)
87
-
106
+ # Run the monitor loop, checking for changes at regular intervals.
107
+ #
108
+ # This method blocks until interrupted via `throw :interrupt`. It continuously polls the filesystem for changes and invokes registered callbacks.
109
+ #
110
+ # @parameter latency [Numeric] The time in seconds to wait between checks (default: 0.1).
111
+ # @yields After each check cycle.
112
+ def run(latency: 0.1, **options, &block)
88
113
  catch(:interrupt) do
89
114
  while true
90
115
  self.update(self.roots)
@@ -6,7 +6,7 @@
6
6
  module Build
7
7
  module Files
8
8
  module Monitor
9
- VERSION = "0.3.0"
9
+ VERSION = "0.4.0"
10
10
  end
11
11
  end
12
12
  end
@@ -1,27 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
4
+ # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
+ require_relative "monitor/native"
7
+
8
+ # @namespace
6
9
  module Build
10
+ # @namespace
7
11
  module Files
12
+ # @namespace
8
13
  module Monitor
9
- case RUBY_PLATFORM
10
- when /linux/i
11
- require_relative 'monitor/inotify'
12
- Native = INotify
13
- Default = Native
14
- when /darwin/i
15
- require_relative 'monitor/fsevent'
16
- Native = FSEvent
17
- Default = Native
18
- else
19
- require_relative 'monitor/polling'
20
- Default = Polling
21
- end
22
-
14
+ # Create a new monitor instance.
15
+ #
16
+ # This factory method creates a monitor that uses platform-specific native filesystem event APIs (FSEvent on macOS, INotify on Linux, etc.) via the `io-watch` gem for efficient, event-driven file monitoring.
17
+ #
18
+ # @returns [Native] A new native monitor instance.
23
19
  def self.new(*arguments, **options)
24
- Default.new(*arguments, **options)
20
+ Native.new(*arguments, **options)
25
21
  end
26
22
  end
27
23
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2021-2024, by Samuel Williams.
3
+ Copyright, 2021-2025, by Samuel Williams.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/readme.md CHANGED
@@ -6,22 +6,35 @@ Efficiently monitor the filesystem for changes.
6
6
 
7
7
  ## Usage
8
8
 
9
- ``` ruby
10
- require 'build/files/path'
11
- require 'build/files/directory'
12
- require 'build/files/monitor'
9
+ Please see the [project documentation](https://ioquatix.github.io/build-files-monitor/) for more details.
13
10
 
14
- root = Build::Files::Path.current
11
+ - [Getting Started](https://ioquatix.github.io/build-files-monitor/guides/getting-started/index) - This guide explains how to use `build-files-monitor` to efficiently monitor the filesystem for changes.
15
12
 
16
- # Monitor everything within this directory, recursively.
17
- directory = Build::Files::Directory.new(root)
13
+ ## Releases
18
14
 
19
- monitor.track_changes(directory) do |state|
20
- pp state.added
21
- end
15
+ Please see the [project releases](https://ioquatix.github.io/build-files-monitor/releases/index) for all releases.
22
16
 
23
- monitor.run # Blocking.
24
- ```
17
+ ### v0.4.0
18
+
19
+ - Use `io-watch` for filesystem monitoring.
20
+
21
+ ### v0.3.0
22
+
23
+ - Internal refactoring.
24
+
25
+ ### v0.2.1
26
+
27
+ - Fixed compatibility of keyword arguments in `Monitor.new` to properly forward both positional and keyword arguments.
28
+
29
+ ### v0.2.0
30
+
31
+ - Moved `State` class to `build-files` gem. Users should now `require 'build/files/state'` instead of `require 'build/files/monitor/state'`.
32
+
33
+ ### v0.1.0
34
+
35
+ - Initial release.
36
+ - Support for filesystem monitoring with platform-specific implementations (`Build::Files::Monitor::Native` using FSEvent/INotify).
37
+ - Fallback polling implementation (`Build::Files::Monitor::Polling`).
25
38
 
26
39
  ## Contributing
27
40
 
@@ -35,8 +48,8 @@ We welcome contributions to this project.
35
48
 
36
49
  ### Developer Certificate of Origin
37
50
 
38
- This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
51
+ In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
39
52
 
40
- ### Contributor Covenant
53
+ ### Community Guidelines
41
54
 
42
- This project is governed by the [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
55
+ This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
data/releases.md ADDED
@@ -0,0 +1,23 @@
1
+ # Releases
2
+
3
+ ## v0.4.0
4
+
5
+ - Use `io-watch` for filesystem monitoring.
6
+
7
+ ## v0.3.0
8
+
9
+ - Internal refactoring.
10
+
11
+ ## v0.2.1
12
+
13
+ - Fixed compatibility of keyword arguments in `Monitor.new` to properly forward both positional and keyword arguments.
14
+
15
+ ## v0.2.0
16
+
17
+ - Moved `State` class to `build-files` gem. Users should now `require 'build/files/state'` instead of `require 'build/files/monitor/state'`.
18
+
19
+ ## v0.1.0
20
+
21
+ - Initial release.
22
+ - Support for filesystem monitoring with platform-specific implementations (`Build::Files::Monitor::Native` using FSEvent/INotify).
23
+ - Fallback polling implementation (`Build::Files::Monitor::Polling`).
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build-files-monitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain:
11
10
  - |
@@ -37,7 +36,7 @@ cert_chain:
37
36
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
38
37
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
39
38
  -----END CERTIFICATE-----
40
- date: 2024-06-18 00:00:00.000000000 Z
39
+ date: 1980-01-02 00:00:00.000000000 Z
41
40
  dependencies:
42
41
  - !ruby/object:Gem::Dependency
43
42
  name: build-files
@@ -54,54 +53,38 @@ dependencies:
54
53
  - !ruby/object:Gem::Version
55
54
  version: '1.8'
56
55
  - !ruby/object:Gem::Dependency
57
- name: rb-fsevent
56
+ name: io-watch
58
57
  requirement: !ruby/object:Gem::Requirement
59
58
  requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- - !ruby/object:Gem::Dependency
71
- name: rb-inotify
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
59
+ - - "~>"
75
60
  - !ruby/object:Gem::Version
76
- version: '0'
61
+ version: '0.2'
77
62
  type: :runtime
78
63
  prerelease: false
79
64
  version_requirements: !ruby/object:Gem::Requirement
80
65
  requirements:
81
- - - ">="
66
+ - - "~>"
82
67
  - !ruby/object:Gem::Version
83
- version: '0'
84
- description:
85
- email:
68
+ version: '0.2'
86
69
  executables: []
87
70
  extensions: []
88
71
  extra_rdoc_files: []
89
72
  files:
90
73
  - lib/build/files/monitor.rb
91
- - lib/build/files/monitor/fsevent.rb
92
74
  - lib/build/files/monitor/handle.rb
93
- - lib/build/files/monitor/inotify.rb
75
+ - lib/build/files/monitor/native.rb
94
76
  - lib/build/files/monitor/polling.rb
95
77
  - lib/build/files/monitor/version.rb
96
78
  - license.md
97
79
  - readme.md
80
+ - releases.md
98
81
  homepage: https://github.com/ioquatix/build-files-monitor
99
82
  licenses:
100
83
  - MIT
101
84
  metadata:
85
+ documentation_uri: https://ioquatix.github.io/build-files-monitor/
102
86
  funding_uri: https://github.com/sponsors/ioquatix/
103
87
  source_code_uri: https://github.com/ioquatix/build-files-monitor.git
104
- post_install_message:
105
88
  rdoc_options: []
106
89
  require_paths:
107
90
  - lib
@@ -109,15 +92,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
92
  requirements:
110
93
  - - ">="
111
94
  - !ruby/object:Gem::Version
112
- version: '3.1'
95
+ version: '3.2'
113
96
  required_rubygems_version: !ruby/object:Gem::Requirement
114
97
  requirements:
115
98
  - - ">="
116
99
  - !ruby/object:Gem::Version
117
100
  version: '0'
118
101
  requirements: []
119
- rubygems_version: 3.5.9
120
- signing_key:
102
+ rubygems_version: 3.6.9
121
103
  specification_version: 4
122
104
  summary: Efficiently monitor changes to the file system.
123
105
  test_files: []
metadata.gz.sig CHANGED
Binary file
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
5
-
6
- require_relative 'polling'
7
-
8
- require 'rb-fsevent'
9
-
10
- module Build
11
- module Files
12
- module Monitor
13
- class FSEvent < Polling
14
- def run(**options, &block)
15
- notifier = ::FSEvent.new
16
-
17
- catch(:interrupt) do
18
- while true
19
- notifier.watch(self.roots) do |directories|
20
- directories.collect! do |directory|
21
- File.expand_path(directory)
22
- end
23
-
24
- self.update(directories)
25
-
26
- yield if block_given?
27
-
28
- if self.updated
29
- notifier.stop
30
- end
31
- end
32
-
33
- notifier.run
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Released under the MIT License.
4
- # Copyright, 2021-2024, by Samuel Williams.
5
-
6
- require_relative 'polling'
7
-
8
- require 'rb-inotify'
9
-
10
- module Build
11
- module Files
12
- module Monitor
13
- class INotify < Polling
14
- def run(**options, &block)
15
- notifier = ::INotify::Notifier.new
16
-
17
- catch(:interrupt) do
18
- while true
19
- self.roots.each do |root|
20
- notifier.watch root, :create, :modify, :attrib, :delete do |event|
21
- self.update([root])
22
-
23
- yield if block_given?
24
-
25
- if self.updated
26
- notifier.stop
27
- end
28
- end
29
- end
30
-
31
- notifier.run
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end