Class: Sinotify::Notifier

Inherits:
Object
  • Object
show all
Includes:
Cosell
Defined in:
lib/sinotify/notifier.rb

Overview

Watch a directory or file for events like create, modify, delete, etc.

(See Sinotify::Event for full list). 

See the synopsis section in the README.txt for example usage.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_or_dir_name, opts = {}) ⇒ Notifier

Required Args

  file_or_dir_name: the file/directory to watch

Options:
  :recurse => (true|false)
    whether to automatically create watches on sub directories
    default: true if file_or_dir_name is a directory, else false
    raises if true and file_or_dir_name is not a directory

  :recurse_throttle => 
    When recursing, a background thread drills down into all the child directories
    creating notifiers on them. The recurse_throttle tells the notifier how far
    to recurse before sleeping for 0.1 seconds, so that drilling down does not hog
    the system on large directorie hierarchies.
    default is 10

  :etypes => 
    which inotify file system event types to listen for (eg :create, :delete, etc)
    See docs for Sinotify::Event for list of event types.
    default is [:create, :modify, :delete]
    Use :all_events to trace everything (although this may be more than you bargained for).

  :logger => 
    Where to log errors to. Default is Logger.new(STDOUT).

  :announcement_throttle =>
    How many events can be announced at a time before the queue goes back to sleep for a cycle.
    (ie. Cosell's 'announcements_per_cycle')

  :announcements_sleep_time =>
    How long the queue should sleep for before announcing the next batch of queued up 
    Sinotify::Events (ie. Cosell's 'sleep_time')


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/sinotify/notifier.rb', line 49

def initialize(file_or_dir_name, opts = {})

  initialize_cosell!  # init the announcements framework

  raise "Could not find #{file_or_dir_name}" unless File.exist?(file_or_dir_name)
  self.file_or_dir_name = file_or_dir_name

  # by default, recurse if directory?. If opts[:recurse] was true and passed in,
  # make sure the watch is on a directory
  self.recurse = opts[:recurse].nil?? self.on_directory? : opts[:recurse] 
  raise "Cannot recurse, #{file_or_dir_name} is not a directory" if self.recurse? && !self.on_directory?

  # how many directories at a time to register. 
  self.recurse_throttle = opts[:recurse_throttle] || 10 

  self.etypes = Array( opts[:etypes] || [:create, :modify, :delete] )
  validate_etypes!

  self.prim_notifier = Sinotify::PrimNotifier.new

  # setup async announcements queue (part of the Cosell mixin)
  @logger = opts[:logger] || Logger.new(STDOUT)
  sleep_time = opts[:announcements_sleep_time] || 0.05 
  announcement_throttle = opts[:announcement_throttle] || 50 
  self.queue_announcements!(:sleep_time => sleep_time, 
                            :logger => @logger,
                            :announcements_per_cycle => announcement_throttle)

  self.closed = false

  # initialize a few variables just to shut up the ruby warnings
  # Apparently the lazy init idiom using ||= is no longer approved of. Shame that.
  @spy_logger = nil
  @spy_logger_level = nil
  @watch_thread = nil
end

Instance Attribute Details

#etypesObject

Returns the value of attribute etypes.



13
14
15
# File 'lib/sinotify/notifier.rb', line 13

def etypes
  @etypes
end

#file_or_dir_nameObject

Returns the value of attribute file_or_dir_name.



13
14
15
# File 'lib/sinotify/notifier.rb', line 13

def file_or_dir_name
  @file_or_dir_name
end

#loggerObject

Returns the value of attribute logger.



13
14
15
# File 'lib/sinotify/notifier.rb', line 13

def logger
  @logger
end

#recurseObject

Returns the value of attribute recurse.



13
14
15
# File 'lib/sinotify/notifier.rb', line 13

def recurse
  @recurse
end

#recurse_throttleObject

Returns the value of attribute recurse_throttle.



13
14
15
# File 'lib/sinotify/notifier.rb', line 13

def recurse_throttle
  @recurse_throttle
end

Instance Method Details

#all_directories_being_watchedObject

Return a list of files/directories currently being watched. Will only contain one entry unless this notifier was setup on a directory with the option :recurse => true.



144
145
146
# File 'lib/sinotify/notifier.rb', line 144

def all_directories_being_watched
  self.watches.values.collect{|w| w.path }.sort
end

#close!Object

Close this notifier. Notifiers cannot be reopened after close!.



118
119
120
121
122
# File 'lib/sinotify/notifier.rb', line 118

def close!
  @closed = true
  self.remove_all_watches
  self.kill_queue! # cosell
end

#on_directory?Boolean

whether this watch is on a directory

Returns:

  • (Boolean)


105
106
107
# File 'lib/sinotify/notifier.rb', line 105

def on_directory?
  File.directory?(self.file_or_dir_name)
end

#on_event(&block) ⇒ Object

Sugar.

Equivalent of calling cosell’s

self.when_announcing(Sinotify::Event) do |event| 
  do_something_with_event(event) 
end

becomes

self.on_event { |event| do_something_with_event(event) }

Since this class only announces one kind of event, it made sense to provide a more terse version of that statement.



100
101
102
# File 'lib/sinotify/notifier.rb', line 100

def on_event &block
  self.when_announcing(Sinotify::Event, &block)
end

#recurse?Boolean

Whether this notifier watches all the files in all of the subdirectories of the directory being watched.

Returns:

  • (Boolean)


154
155
156
# File 'lib/sinotify/notifier.rb', line 154

def recurse?
  self.recurse
end

#spy!(opts = {}) ⇒ Object

Log a message every time a prim_event comes in (will be logged even if it is considered ‘noise’), and log a message whenever an event is announced. Overrides Cosell’s spy! method (and uses cosell’s spy! to log announced events).

Options:

:logger => The log to log to. Default is a logger on STDOUT
:level => The log level to log with. Default is :info
:spy_on_prim_events => Spy on PrimEvents (raw inotify events) too


133
134
135
136
137
138
139
140
# File 'lib/sinotify/notifier.rb', line 133

def spy!(opts = {})
  self.spy_on_prim_events = opts[:spy_on_prim_events].eql?(true)
  self.spy_logger = opts[:logger] || Logger.new(STDOUT)
  self.spy_logger_level = opts[:level] || :info
  opts[:on] = Sinotify::Event
  opts[:preface_with] = "Sinotify::Notifier Event Spy"
  super(opts)
end

#to_sObject



158
159
160
# File 'lib/sinotify/notifier.rb', line 158

def to_s
  "Sinotify::Notifier[#{self.file_or_dir_name}, :watches => #{self.watches.size}]"
end

#watch!Object

Start watching for inotify file system events.



110
111
112
113
114
115
# File 'lib/sinotify/notifier.rb', line 110

def watch!
  raise "Cannot reopen an inotifier. Create a new one instead" if self.closed?
  self.add_all_directories_in_background
  self.start_prim_event_loop_thread
  return self
end

#watchesObject



148
149
150
# File 'lib/sinotify/notifier.rb', line 148

def watches
  @watches ||= {}
end