Class: FileWatcher
- Inherits:
-
Object
- Object
- FileWatcher
- Defined in:
- lib/filewatcher.rb
Overview
Simple file watcher. Detect changes in files and directories.
Issues: Currently doesn’t monitor changes in directorynames
Instance Attribute Summary collapse
-
#filenames ⇒ Object
Returns the value of attribute filenames.
Class Method Summary collapse
Instance Method Summary collapse
- #expand_directories(patterns) ⇒ Object
- #filesystem_updated?(snapshot_to_use = nil) ⇒ Boolean
-
#finalize(&on_update) ⇒ Object
Calls the update block repeatedly until all changes in the current snapshot are dealt with.
-
#initialize(unexpanded_filenames, print_filelist = false, dontwait = false, show_spinner = false) ⇒ FileWatcher
constructor
A new instance of FileWatcher.
-
#mtime_snapshot ⇒ Object
Takes a snapshot of the current status of watched files.
- #pause ⇒ Object
- #resume ⇒ Object
-
#stop ⇒ Object
Ends the watch, allowing any remaining changes to be finalized.
- #update_spinner(label) ⇒ Object
- #watch(sleep = 0.5, &on_update) ⇒ Object
Constructor Details
#initialize(unexpanded_filenames, print_filelist = false, dontwait = false, show_spinner = false) ⇒ FileWatcher
Returns a new instance of FileWatcher.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/filewatcher.rb', line 18 def initialize(, print_filelist=false, dontwait=false, show_spinner=false) = @filenames = nil @stored_update = nil @keep_watching = false @pausing = false @last_snapshot = mtime_snapshot @end_snapshot = nil @dontwait = dontwait @show_spinner = show_spinner puts 'Watching:' if print_filelist @filenames.each do |filename| raise 'File does not exist' unless File.exist?(filename) puts filename if print_filelist end end |
Instance Attribute Details
#filenames ⇒ Object
Returns the value of attribute filenames.
6 7 8 |
# File 'lib/filewatcher.rb', line 6 def filenames @filenames end |
Class Method Details
.VERSION ⇒ Object
8 9 10 |
# File 'lib/filewatcher.rb', line 8 def self.VERSION return '0.5.1' end |
Instance Method Details
#expand_directories(patterns) ⇒ Object
141 142 143 144 145 146 |
# File 'lib/filewatcher.rb', line 141 def (patterns) if(!patterns.kind_of?Array) patterns = [patterns] end patterns.map { |it| Dir[fulldepth(it)] }.flatten.uniq end |
#filesystem_updated?(snapshot_to_use = nil) ⇒ Boolean
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/filewatcher.rb', line 112 def filesystem_updated?(snapshot_to_use = nil) snapshot = snapshot_to_use ? snapshot_to_use : mtime_snapshot forward_changes = snapshot.to_a - @last_snapshot.to_a forward_changes.each do |file,mtime| @updated_file = file unless @last_snapshot.fetch(@updated_file,false) @last_snapshot[file] = mtime @event = :new return true else @last_snapshot[file] = mtime @event = :changed return true end end backward_changes = @last_snapshot.to_a - snapshot.to_a forward_names = forward_changes.map{|change| change.first} backward_changes.reject!{|f,m| forward_names.include?(f)} backward_changes.each do |file,mtime| @updated_file = file @last_snapshot.delete(file) @event = :delete return true end return false end |
#finalize(&on_update) ⇒ Object
Calls the update block repeatedly until all changes in the current snapshot are dealt with
89 90 91 92 93 94 95 96 97 98 |
# File 'lib/filewatcher.rb', line 89 def finalize(&on_update) on_update = @stored_update if !block_given? snapshot = @end_snapshot ? @end_snapshot : mtime_snapshot while filesystem_updated?(snapshot) update_spinner('Finalizing') on_update.call(@updated_file, @event) end @end_snapshot =nil return nil end |
#mtime_snapshot ⇒ Object
Takes a snapshot of the current status of watched files. (Allows avoidance of potential race condition during #finalize)
102 103 104 105 106 107 108 109 110 |
# File 'lib/filewatcher.rb', line 102 def mtime_snapshot snapshot = {} @filenames = () @filenames.each do |filename| mtime = File.exist?(filename) ? File.stat(filename).mtime : Time.new(0) snapshot[filename] = mtime end return snapshot end |
#pause ⇒ Object
62 63 64 65 66 67 |
# File 'lib/filewatcher.rb', line 62 def pause @pausing = true update_spinner('Initiating pause') Kernel.sleep @sleep # Ensure we wait long enough to enter pause loop # in #watch end |
#resume ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/filewatcher.rb', line 69 def resume if !@keep_watching || !@pausing raise "Can't resume unless #watch and #pause were first called" end @last_snapshot = mtime_snapshot # resume with fresh snapshot @pausing = false update_spinner('Resuming') Kernel.sleep @sleep # Wait long enough to exit pause loop in #watch end |
#stop ⇒ Object
Ends the watch, allowing any remaining changes to be finalized. Used mainly in multi-threaded situations.
81 82 83 84 85 |
# File 'lib/filewatcher.rb', line 81 def stop @keep_watching = false update_spinner('Stopping') return nil end |
#update_spinner(label) ⇒ Object
12 13 14 15 16 |
# File 'lib/filewatcher.rb', line 12 def update_spinner(label) return nil unless @show_spinner @spinner ||= %w(\\ | / -) print "#{' ' * 30}\r#{label} #{@spinner.rotate!.first}\r" end |
#watch(sleep = 0.5, &on_update) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/filewatcher.rb', line 35 def watch(sleep=0.5, &on_update) trap("SIGINT") {return } @sleep = sleep @stored_update = on_update @keep_watching = true if(@dontwait) yield '','' end while @keep_watching @end_snapshot = mtime_snapshot if @pausing while @keep_watching && @pausing update_spinner('Pausing') Kernel.sleep sleep end while @keep_watching && !filesystem_updated? && !@pausing update_spinner('Watching') Kernel.sleep sleep end # test and null @updated_file to prevent yielding the last # file twice if @keep_watching has just been set to false yield @updated_file, @event if @updated_file @updated_file = nil end @end_snapshot = mtime_snapshot finalize(&on_update) end |