Class: Rerun::Watcher

Inherits:
Object
  • Object
show all
Defined in:
lib/rerun/watcher.rb

Constant Summary collapse

InvalidDirectoryError =
Class.new(RuntimeError)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}, &client_callback) ⇒ Watcher

Create a file system watcher. Start it by calling #start.

Parameters:

  • options (:directory) (defaults to: {})

    the directory to watch (default “.”)

  • options (:pattern) (defaults to: {})

    the glob pattern to search under the watched directory (default “*/”)

  • options (:priority) (defaults to: {})

    the priority of the watcher thread (default 0)



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rerun/watcher.rb', line 29

def initialize(options = {}, &client_callback)
  @client_callback = client_callback

  options = {
      :directory => ".",
      :pattern => "**/*",
      :priority => 0,
      :ignore_dotfiles => true,
  }.merge(options)

  @pattern = options[:pattern]
  @directories = options[:directory]
  @directories = sanitize_dirs(@directories)
  @priority = options[:priority]
  @force_polling = options[:force_polling]
  @ignore = [options[:ignore]].flatten.compact
  @ignore_dotfiles = options[:ignore_dotfiles]
  @thread = nil
end

Instance Attribute Details

#directoryObject (readonly)

def self.default_ignore

Listen::Silencer.new(Listen::Listener.new).send :_default_ignore_patterns

end



21
22
23
# File 'lib/rerun/watcher.rb', line 21

def directory
  @directory
end

#ignore_dotfilesObject (readonly)

def self.default_ignore

Listen::Silencer.new(Listen::Listener.new).send :_default_ignore_patterns

end



21
22
23
# File 'lib/rerun/watcher.rb', line 21

def ignore_dotfiles
  @ignore_dotfiles
end

#patternObject (readonly)

def self.default_ignore

Listen::Silencer.new(Listen::Listener.new).send :_default_ignore_patterns

end



21
22
23
# File 'lib/rerun/watcher.rb', line 21

def pattern
  @pattern
end

#priorityObject (readonly)

def self.default_ignore

Listen::Silencer.new(Listen::Listener.new).send :_default_ignore_patterns

end



21
22
23
# File 'lib/rerun/watcher.rb', line 21

def priority
  @priority
end

Instance Method Details

#adapterObject



124
125
126
127
128
# File 'lib/rerun/watcher.rb', line 124

def adapter
  @listener &&
      (backend = @listener.instance_variable_get(:@backend)) &&
      backend.instance_variable_get(:@adapter)
end

#adapter_nameObject



130
131
132
# File 'lib/rerun/watcher.rb', line 130

def adapter_name
  adapter && adapter.class.name.split('::').last
end

#ignoringObject



86
87
88
89
90
91
92
# File 'lib/rerun/watcher.rb', line 86

def ignoring
  patterns = []
  if ignore_dotfiles
    patterns << /^\.[^.]/ # at beginning of string, a real dot followed by any other character
  end
  patterns + @ignore.map { |x| Rerun::Glob.new(x).to_regexp }
end

#joinObject

wait for the file watcher to finish



106
107
108
109
110
# File 'lib/rerun/watcher.rb', line 106

def join
  @thread.join if @thread
rescue Interrupt
  # don't care
end

#pauseObject



112
113
114
# File 'lib/rerun/watcher.rb', line 112

def pause
  @listener.pause if @listener
end

#running?Boolean

Returns:

  • (Boolean)


120
121
122
# File 'lib/rerun/watcher.rb', line 120

def running?
  @listener && @listener.processing?
end

#sanitize_dirs(dirs) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/rerun/watcher.rb', line 49

def sanitize_dirs(dirs)
  dirs = [*dirs]
  dirs.map do |d|
    d.chomp!("/")
    unless FileTest.exist?(d) && FileTest.readable?(d) && FileTest.directory?(d)
      raise InvalidDirectoryError, "Directory '#{d}' either doesnt exist or isn't readable"
    end
    File.expand_path(d)
  end
end

#startObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rerun/watcher.rb', line 60

def start
  if @thread then
    raise RuntimeError, "already started"
  end

  @thread = Thread.new do
    @listener = Listen.to(*@directories, only: watching, ignore: ignoring, wait_for_delay: 1, force_polling: @force_polling) do |modified, added, removed|
      count = modified.size + added.size + removed.size
      if count > 0
        @client_callback.call(:modified => modified, :added => added, :removed => removed)
      end
    end
    @listener.start
  end

  @thread.priority = @priority

  sleep 0.1 until @listener

  at_exit { stop } # try really hard to clean up after ourselves
end

#stopObject

kill the file watcher thread



95
96
97
98
99
100
101
102
103
# File 'lib/rerun/watcher.rb', line 95

def stop
  @thread.wakeup rescue ThreadError
  begin
    @listener.stop
  rescue Exception => e
    puts "#{e.class}: #{e.message} stopping listener"
  end
  @thread.kill rescue ThreadError
end

#unpauseObject



116
117
118
# File 'lib/rerun/watcher.rb', line 116

def unpause
  @listener.start if @listener
end

#watchingObject



82
83
84
# File 'lib/rerun/watcher.rb', line 82

def watching
  Rerun::Glob.new(@pattern).to_regexp
end