Created
August 3, 2026 02:14
-
-
Save KonnorRogers/9c2532d07795bb3fb72cc25c0b7eb4e9 to your computer and use it in GitHub Desktop.
File watching (polling) in DragonRuby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class FileWatcher | |
| # This can get potentially deep if you have a lot of files or directories. Consider a fiber if its taking up too much time. | |
| def self.list_files_recursive(directory, max_iterations_for_fiber: 100, fiber: false) | |
| idx = 0 | |
| files = [] | |
| all_files = [] | |
| # Seed with full paths so we never lose directory context. `.reverse_each` makes `.pop()` yield entries in listing order. This is like the old "list_files_recursive" which actually used recursion, but by using a loop we can yield to a fiber on potentially large directories. | |
| DR.list_files(directory).reverse_each do |f| | |
| files << File.join(directory, f) | |
| Fiber.yield if fiber && idx % max_iterations_for_fiber == 0 | |
| end | |
| while file_path = files.pop | |
| idx += 1 | |
| # file_path is a full path now, so check the basename for the hidden rule. | |
| next if File.basename(file_path).start_with?(".") | |
| stat = DR.stat_file(file_path) | |
| next if !stat | |
| stat.path = file_path | |
| if stat[:file_type] == :directory | |
| # Directories aren't part of the result; just descend. | |
| DR.list_files(file_path).reverse_each do |f| | |
| idx += 1 | |
| files << File.join(file_path, f) | |
| Fiber.yield if fiber && idx % max_iterations_for_fiber == 0 | |
| end | |
| next | |
| end | |
| all_files << stat | |
| Fiber.yield if fiber && idx % max_iterations_for_fiber == 0 | |
| end | |
| all_files | |
| end | |
| attr_accessor :cache, :files_per_tick | |
| def initialize(&block) | |
| @cache = {} | |
| @modified_files = [] | |
| @callback = block || proc {} | |
| @files_per_tick = 100 | |
| end | |
| def tick_watch(*directories) | |
| if @fiber_watch && @fiber_watch.alive? | |
| @fiber_watch.resume | |
| else | |
| @fiber_watch = Fiber.new { watch(*directories, fiber: true) } | |
| end | |
| end | |
| def watch(*directories, fiber: false) | |
| directories.flatten.each do |directory| | |
| FileWatcher.list_files_recursive(directory, fiber: fiber, max_iterations_for_fiber: @files_per_tick).each do |stat| | |
| add(stat) | |
| end | |
| end | |
| end | |
| def watched_files | |
| @cache.values | |
| end | |
| # Flushes any modified files and calls your block on it. | |
| def flush | |
| while stat = @modified_files.pop() | |
| @callback.call(stat) | |
| end | |
| end | |
| # Will add a stat to the cache. | |
| def add(stat) | |
| if !stat | |
| return | |
| end | |
| existing_stat = @cache[stat.path] | |
| if !existing_stat || existing_stat.mod_time != stat.mod_time || existing_stat.file_size != stat.file_size | |
| @cache[stat.path] = stat | |
| @modified_files << stat | |
| end | |
| end | |
| def delete(stat) | |
| @cache.delete(stat.path) | |
| end | |
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Usage | |
| require "./file_watcher.rb" | |
| module Main | |
| attr_accessor :game | |
| def tick(args) | |
| if !$game | |
| $game = App::Game.new | |
| end | |
| if !@file_watcher | |
| # Watch the sprites directory and register the callback to reset the sprite if its been modified | |
| @file_watcher = FileWatcher.new("sprites") { |stat| DR.reset_sprite(stat.path) } | |
| end | |
| $game.tick(args) | |
| @file_watcher.tick_watch("sprites") # iterates through 100 files | |
| @file_watcher.flush # calls your callback on any modified files. | |
| end | |
| def reset(args) | |
| $game = nil | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment