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
# File 'lib/rerun/watcher.rb', line 29

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

  options = {
      :directory => ".",
      :pattern => "**/*",
      :priority => 0,
  }.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
  @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

#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


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

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

#adapter_nameObject


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

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

#ignoringObject


84
85
86
87
88
# File 'lib/rerun/watcher.rb', line 84

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

#joinObject

wait for the file watcher to finish


102
103
104
105
106
# File 'lib/rerun/watcher.rb', line 102

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

#pauseObject


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

def pause
  @listener.pause if @listener
end

#running?Boolean

Returns:

  • (Boolean)

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

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

#sanitize_dirs(dirs) ⇒ Object


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

def sanitize_dirs(dirs)
  dirs = [*dirs]
  dirs.map do |d|
    d.chomp!("/")
    unless FileTest.exists?(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


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

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


91
92
93
94
95
96
97
98
99
# File 'lib/rerun/watcher.rb', line 91

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


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

def unpause
  @listener.start if @listener
end

#watchingObject


80
81
82
# File 'lib/rerun/watcher.rb', line 80

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