Class: ActiveSupport::EventedFileUpdateChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/active_support/evented_file_update_checker.rb

Overview

Allows you to “listen” to changes in a file system. The evented file updater does not hit disk when checking for updates instead it uses platform specific file system events to trigger a change in state.

The file checker takes an array of files to watch or a hash specifying directories and file extensions to watch. It also takes a block that is called when EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated is run and there have been changes to the file system.

Note: Forking will cause the first call to ‘updated?` to return `true`.

Example:

checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
checker.updated?
# => false
checker.execute_if_updated
# => nil

FileUtils.touch("/tmp/foo")

checker.updated?
# => true
checker.execute_if_updated
# => "changed"

Defined Under Namespace

Classes: PathHelper

Instance Method Summary collapse

Constructor Details

#initialize(files, dirs = {}, &block) ⇒ EventedFileUpdateChecker

:nodoc: all



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
61
62
63
64
65
66
67
68
# File 'lib/active_support/evented_file_update_checker.rb', line 36

def initialize(files, dirs = {}, &block)
  unless block
    raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
  end

  @ph    = PathHelper.new
  @files = files.map { |f| @ph.xpath(f) }.to_set

  @dirs = {}
  dirs.each do |dir, exts|
    @dirs[@ph.xpath(dir)] = Array(exts).map { |ext| @ph.normalize_extension(ext) }
  end

  @block      = block
  @updated    = Concurrent::AtomicBoolean.new(false)
  @lcsp       = @ph.longest_common_subpath(@dirs.keys)
  @pid        = Process.pid
  @boot_mutex = Mutex.new

  if (@dtw = directories_to_watch).any?
    # Loading listen triggers warnings. These are originated by a legit
    # usage of attr_* macros for private attributes, but adds a lot of noise
    # to our test suite. Thus, we lazy load it and disable warnings locally.
    silence_warnings do
      begin
        require "listen"
      rescue LoadError => e
        raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
      end
    end
  end
  boot!
end

Instance Method Details

#executeObject



81
82
83
84
# File 'lib/active_support/evented_file_update_checker.rb', line 81

def execute
  @updated.make_false
  @block.call
end

#execute_if_updatedObject



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

def execute_if_updated
  if updated?
    yield if block_given?
    execute
    true
  end
end

#updated?Boolean

Returns:

  • (Boolean)


70
71
72
73
74
75
76
77
78
79
# File 'lib/active_support/evented_file_update_checker.rb', line 70

def updated?
  @boot_mutex.synchronize do
    if @pid != Process.pid
      boot!
      @pid = Process.pid
      @updated.make_true
    end
  end
  @updated.true?
end