1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Add initial FileWatcher implementation. The Backend is just an abstract implementation, which will be inherited by backends that do the heavy lifting.

This commit is contained in:
wycats 2011-02-06 13:41:56 -08:00
parent 3026843dc1
commit 1fd9d978a7
3 changed files with 107 additions and 0 deletions

View file

@ -42,6 +42,7 @@ module ActiveSupport
autoload :DescendantsTracker
autoload :FileUpdateChecker
autoload :FileWatcher
autoload :LogSubscriber
autoload :Notifications

View file

@ -0,0 +1,41 @@
module ActiveSupport
class FileWatcher
class Backend
def initialize(path, watcher)
@watcher = watcher
@path = path
end
def trigger(files)
@watcher.trigger(files)
end
end
def initialize
@regex_matchers = {}
end
def watch(path, &block)
return watch_regex(path, &block) if path.is_a?(Regexp)
raise "Paths must be regular expressions. #{path.inspect} is a #{path.class}"
end
def watch_regex(regex, &block)
@regex_matchers[regex] = block
end
def trigger(files)
trigger_files = Hash.new { |h,k| h[k] = Hash.new { |h2,k2| h2[k2] = [] } }
files.each do |file, state|
@regex_matchers.each do |regex, block|
trigger_files[block][state] << file if file =~ regex
end
end
trigger_files.each do |block, payload|
block.call payload
end
end
end
end

View file

@ -0,0 +1,65 @@
require 'abstract_unit'
class FileWatcherTest < ActiveSupport::TestCase
class DumbBackend < ActiveSupport::FileWatcher::Backend
end
def setup
@watcher = ActiveSupport::FileWatcher.new
# In real life, the backend would take the path and use it to observe the file
# system. In our case, we will manually trigger the events for unit testing,
# so we can pass any path.
@backend = DumbBackend.new("RAILS_WOOT", @watcher)
@payload = []
@watcher.watch %r{^app/assets/.*\.scss$} do |pay|
pay.each do |status, files|
files.sort!
end
@payload << pay
end
end
def test_one_change
@backend.trigger("app/assets/main.scss" => :changed)
assert_equal({:changed => ["app/assets/main.scss"]}, @payload.first)
end
def test_multiple_changes
@backend.trigger("app/assets/main.scss" => :changed, "app/assets/javascripts/foo.coffee" => :changed)
assert_equal([{:changed => ["app/assets/main.scss"]}], @payload)
end
def test_multiple_changes_match
@backend.trigger("app/assets/main.scss" => :changed, "app/assets/print.scss" => :changed, "app/assets/javascripts/foo.coffee" => :changed)
assert_equal([{:changed => ["app/assets/main.scss", "app/assets/print.scss"]}], @payload)
end
def test_multiple_state_changes
@backend.trigger("app/assets/main.scss" => :created, "app/assets/print.scss" => :changed)
assert_equal([{:changed => ["app/assets/print.scss"], :created => ["app/assets/main.scss"]}], @payload)
end
def test_more_blocks
payload = []
@watcher.watch %r{^config/routes\.rb$} do |pay|
payload << pay
end
@backend.trigger "config/routes.rb" => :changed
assert_equal [:changed => ["config/routes.rb"]], payload
assert_equal [], @payload
end
def test_overlapping_watchers
payload = []
@watcher.watch %r{^app/assets/main\.scss$} do |pay|
payload << pay
end
@backend.trigger "app/assets/print.scss" => :changed, "app/assets/main.scss" => :changed
assert_equal [:changed => ["app/assets/main.scss"]], payload
assert_equal [:changed => ["app/assets/main.scss", "app/assets/print.scss"]], @payload
end
end