Class: ActiveSupport::EventedFileUpdateChecker

Inherits:
Object
  • Object
show all
Defined in:
activesupport/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 = 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

Returns a new instance of EventedFileUpdateChecker.


34
35
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
# File 'activesupport/lib/active_support/evented_file_update_checker.rb', line 34

def initialize(files, dirs = {}, &block)
  @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


75
76
77
78
# File 'activesupport/lib/active_support/evented_file_update_checker.rb', line 75

def execute
  @updated.make_false
  @block.call
end

#execute_if_updatedObject


80
81
82
83
84
85
86
# File 'activesupport/lib/active_support/evented_file_update_checker.rb', line 80

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

#updated?Boolean

Returns:

  • (Boolean)

64
65
66
67
68
69
70
71
72
73
# File 'activesupport/lib/active_support/evented_file_update_checker.rb', line 64

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