class Core::Watch::Snapshot

public

Snapshot of a watched system that can generate diffs.

Public Class Methods

default_strategy() click to toggle source
# File lib/core/watch/snapshot.rb, line 13
def default_strategy
  require_relative "strategies/digest"

  Strategies::Digest
end
new(*paths, ignore: [], strategy: self.class.default_strategy) click to toggle source
# File lib/core/watch/snapshot.rb, line 22
def initialize(*paths, ignore: [], strategy: self.class.default_strategy)
  @ignore = ignore
  @watched = {}
  @strategy = strategy.new

  track(*paths)
end

Public Instance Methods

diff() click to toggle source
public

Detect changes, update the snapshot, and return a diff.

# File lib/core/watch/snapshot.rb, line 40
def diff
  trackable = []
  untrackable = []
  diff = Diff.new

  @watched.each do |path, object|
    case object[:type]
    when :directory
      # The mtime of the parent directory changes when its contents have changed (e.g. a file is added or removed).
      # So, do the minimum amount of work necessary to detect added/removed files, then detect file changes below.
      #
      if @strategy.identify(path) != object[:identity]
        path.glob("*") do |each_path|
          unless @watched.include?(each_path)
            next if ignore?(each_path)

            diff.added(each_path)
            trackable << each_path
          end
        end

        trackable << path
      end
    when :file
      if @strategy.identify(path) != object[:identity]
        diff.changed(path)
        trackable << path
      end
    end
  rescue Errno::ENOENT
    diff.removed(path)
    untrackable << path
  end

  track(*trackable)
  untrack(*untrackable)

  diff
end
ignore?(path) click to toggle source
public

Return `true` if `path` is ignored.

# File lib/core/watch/snapshot.rb, line 32
def ignore?(path)
  @ignore.any? do |ignore|
    path.fnmatch?(ignore)
  end
end

Private Instance Methods

track(*paths) click to toggle source
public
# File lib/core/watch/snapshot.rb, line 82
        def track(*paths)
  paths.each do |path|
    next if ignore?(path)

    type = if path.file?
      :file
    elsif path.directory?
      :directory
    end

    if type
      object = {
        type: type,
        identity: @strategy.identify(path)
      }

      existed = @watched.include?(path)
      @watched[path] = object

      if type == :directory && !existed
        track(*path.glob("*"))
      end
    else
      track(*Dir.glob(path).map { |string| Pathname(string) })
    end
  end
end
untrack(*paths) click to toggle source
public
# File lib/core/watch/snapshot.rb, line 112
        def untrack(*paths)
  paths.each do |path|
    @watched.delete(path)
  end
end