smparkes-watchr 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/History.txt +32 -0
- data/LICENSE +19 -0
- data/Manifest +30 -0
- data/README.rdoc +82 -0
- data/Rakefile +51 -0
- data/TODO.txt +40 -0
- data/bin/watchr +77 -0
- data/docs.watchr +26 -0
- data/gem.watchr +32 -0
- data/lib/watchr.rb +101 -0
- data/lib/watchr/controller.rb +93 -0
- data/lib/watchr/event_handlers/base.rb +48 -0
- data/lib/watchr/event_handlers/em.rb +147 -0
- data/lib/watchr/event_handlers/portable.rb +60 -0
- data/lib/watchr/event_handlers/rev.rb +104 -0
- data/lib/watchr/event_handlers/unix.rb +25 -0
- data/lib/watchr/script.rb +230 -0
- data/manifest.watchr +70 -0
- data/specs.watchr +38 -0
- data/test/README +11 -0
- data/test/event_handlers/test_base.rb +24 -0
- data/test/event_handlers/test_em.rb +162 -0
- data/test/event_handlers/test_portable.rb +142 -0
- data/test/event_handlers/test_rev.rb +162 -0
- data/test/test_controller.rb +130 -0
- data/test/test_helper.rb +60 -0
- data/test/test_script.rb +124 -0
- data/test/test_watchr.rb +60 -0
- data/watchr.gemspec +64 -0
- metadata +141 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Watchr
|
2
|
+
module EventHandler
|
3
|
+
module Unix
|
4
|
+
|
5
|
+
@defaults = []
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :defaults
|
9
|
+
|
10
|
+
def default
|
11
|
+
defaults.empty? &&
|
12
|
+
begin; require( 'watchr/event_handlers/rev' );
|
13
|
+
rescue LoadError => e; end
|
14
|
+
defaults.empty? &&
|
15
|
+
begin require( 'watchr/event_handlers/portable' );
|
16
|
+
defaults << Watchr::EventHandler::Portable;
|
17
|
+
end
|
18
|
+
defaults[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
module Watchr
|
2
|
+
|
3
|
+
# A script object wraps a script file, and is used by a controller.
|
4
|
+
#
|
5
|
+
# ===== Examples
|
6
|
+
#
|
7
|
+
# path = Pathname.new('specs.watchr')
|
8
|
+
# script = Watchr::Script.new(path)
|
9
|
+
#
|
10
|
+
class Script
|
11
|
+
DEFAULT_EVENT_TYPE = :modified
|
12
|
+
|
13
|
+
# Convenience type. Provides clearer and simpler access to rule properties.
|
14
|
+
#
|
15
|
+
# ===== Examples
|
16
|
+
#
|
17
|
+
# rule = script.watch('lib/.*\.rb') { 'ohaie' }
|
18
|
+
# rule.pattern #=> 'lib/.*\.rb'
|
19
|
+
# rule.action.call #=> 'ohaie'
|
20
|
+
#
|
21
|
+
Rule = Struct.new(:pattern, :event_types, :predicate, :action)
|
22
|
+
|
23
|
+
class Rule
|
24
|
+
def match path
|
25
|
+
( md = self.pattern.match(path) ) &&
|
26
|
+
( self.predicate == nil || self.predicate.call(md) )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO eval context
|
31
|
+
class API #:nodoc:
|
32
|
+
end
|
33
|
+
|
34
|
+
# Creates a script object for <tt>path</tt>.
|
35
|
+
#
|
36
|
+
# Does not parse the script. The controller knows when to parse the script.
|
37
|
+
#
|
38
|
+
# ===== Parameters
|
39
|
+
# path<Pathname>:: the path to the script
|
40
|
+
#
|
41
|
+
def initialize(path)
|
42
|
+
@path = path
|
43
|
+
@rules = []
|
44
|
+
@default_action = lambda {}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Main script API method. Builds a new rule, binding a pattern to an action.
|
48
|
+
#
|
49
|
+
# Whenever a file is saved that matches a rule's <tt>pattern</tt>, its
|
50
|
+
# corresponding <tt>action</tt> is triggered.
|
51
|
+
#
|
52
|
+
# Patterns can be either a Regexp or a string. Because they always
|
53
|
+
# represent paths however, it's simpler to use strings. But remember to use
|
54
|
+
# single quotes (not double quotes), otherwise escape sequences will be
|
55
|
+
# parsed (for example "foo/bar\.rb" #=> "foo/bar.rb", notice "\." becomes
|
56
|
+
# "."), and won't be interpreted as the regexp you expect.
|
57
|
+
#
|
58
|
+
# Also note that patterns will be matched against relative paths (relative
|
59
|
+
# from current working directory).
|
60
|
+
#
|
61
|
+
# Actions, the blocks passed to <tt>watch</tt>, receive a MatchData object
|
62
|
+
# as argument. It will be populated with the whole matched string (md[0])
|
63
|
+
# as well as individual backreferences (md[1..n]). See MatchData#[]
|
64
|
+
# documentation for more details.
|
65
|
+
#
|
66
|
+
# ===== Examples
|
67
|
+
#
|
68
|
+
# # in script file
|
69
|
+
# watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
|
70
|
+
# watch( 'lib/(.*)\.rb' ) {|md| system("ruby test/test_#{md[1]}.rb") }
|
71
|
+
#
|
72
|
+
# With these two rules, watchr will run any test file whenever it is itself
|
73
|
+
# changed (first rule), and will also run a corresponding test file
|
74
|
+
# whenever a lib file is changed (second rule).
|
75
|
+
#
|
76
|
+
# ===== Parameters
|
77
|
+
# pattern<~#match>:: pattern to match targetted paths
|
78
|
+
# event_types<Symbol|Array<Symbol>>::
|
79
|
+
# Rule will only match events of one of these type. Accepted types are :accessed,
|
80
|
+
# :modified, :changed, :delete and nil (any), where the first three
|
81
|
+
# correspond to atime, mtime and ctime respectively. Defaults to
|
82
|
+
# :modified.
|
83
|
+
# action<Block>:: action to trigger
|
84
|
+
#
|
85
|
+
# ===== Returns
|
86
|
+
# rule<Rule>:: rule created by the method
|
87
|
+
#
|
88
|
+
def watch(pattern, event_type = DEFAULT_EVENT_TYPE, predicate = nil, &action)
|
89
|
+
event_types = Array(event_type)
|
90
|
+
@rules << Rule.new(pattern, event_types, predicate, action || @default_action)
|
91
|
+
@rules.last
|
92
|
+
end
|
93
|
+
|
94
|
+
# Convenience method. Define a default action to be triggered when a rule
|
95
|
+
# has none specified.
|
96
|
+
#
|
97
|
+
# ===== Examples
|
98
|
+
#
|
99
|
+
# # in script file
|
100
|
+
#
|
101
|
+
# default_action { system('rake --silent rdoc') }
|
102
|
+
#
|
103
|
+
# watch( 'lib/.*\.rb' )
|
104
|
+
# watch( 'README.rdoc' )
|
105
|
+
# watch( 'TODO.txt' )
|
106
|
+
# watch( 'LICENSE' )
|
107
|
+
#
|
108
|
+
# # equivalent to:
|
109
|
+
#
|
110
|
+
# watch( 'lib/.*\.rb' ) { system('rake --silent rdoc') }
|
111
|
+
# watch( 'README.rdoc' ) { system('rake --silent rdoc') }
|
112
|
+
# watch( 'TODO.txt' ) { system('rake --silent rdoc') }
|
113
|
+
# watch( 'LICENSE' ) { system('rake --silent rdoc') }
|
114
|
+
#
|
115
|
+
def default_action(&action)
|
116
|
+
@default_action = action
|
117
|
+
end
|
118
|
+
|
119
|
+
# Eval content of script file.
|
120
|
+
#--
|
121
|
+
# TODO fix script file not found error
|
122
|
+
def parse!
|
123
|
+
Watchr.debug('loading script file %s' % @path.to_s.inspect)
|
124
|
+
|
125
|
+
reset
|
126
|
+
|
127
|
+
# Some editors do delete/rename. Even when they don't some events come very fast ...
|
128
|
+
# and editor could do a trunc/write. If you look after the trunc, before the write, well,
|
129
|
+
# things aren't pretty.
|
130
|
+
|
131
|
+
# Should probably use a watchdog timer that gets reset on every change and then only fire actions
|
132
|
+
# after the watchdog timer fires without get reset ..
|
133
|
+
|
134
|
+
sleep(0.1)
|
135
|
+
|
136
|
+
instance_eval(@path.read)
|
137
|
+
|
138
|
+
rescue Errno::ENOENT
|
139
|
+
# TODO figure out why this is happening. still can't reproduce
|
140
|
+
Watchr.debug('script file "not found". wth')
|
141
|
+
sleep(0.3) #enough?
|
142
|
+
instance_eval(@path.read)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Find an action corresponding to a path and event type. The returned
|
146
|
+
# action is actually a wrapper around the rule's action, with the
|
147
|
+
# match_data prepopulated.
|
148
|
+
#
|
149
|
+
# ===== Params
|
150
|
+
# path<Pathnane,String>:: Find action that correspond to this path.
|
151
|
+
# event_type<Symbol>:: Find action only if rule's event if of this type.
|
152
|
+
#
|
153
|
+
# ===== Examples
|
154
|
+
#
|
155
|
+
# script.watch( 'test/test_.*\.rb' ) {|md| "ruby #{md[0]}" }
|
156
|
+
# script.action_for('test/test_watchr.rb').call #=> "ruby test/test_watchr.rb"
|
157
|
+
#
|
158
|
+
def call_action_for(path, event_type = DEFAULT_EVENT_TYPE)
|
159
|
+
path = rel_path(path).to_s
|
160
|
+
# p path
|
161
|
+
rules_for(path).each do |rule|
|
162
|
+
# p rule
|
163
|
+
rule.event_types.each do |rule_event_type|
|
164
|
+
# p rule_event_type
|
165
|
+
if ( rule_event_type.nil? && ( event_type != :load ) ) || ( rule_event_type == event_type )
|
166
|
+
data = path.match(rule.pattern)
|
167
|
+
return rule.action.call(data)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
# Collection of all patterns defined in script.
|
175
|
+
#
|
176
|
+
# ===== Returns
|
177
|
+
# patterns<String, Regexp>:: all patterns
|
178
|
+
#
|
179
|
+
def patterns
|
180
|
+
#@rules.every.pattern
|
181
|
+
@rules.map {|r| r.pattern }
|
182
|
+
end
|
183
|
+
|
184
|
+
def rules
|
185
|
+
@rules
|
186
|
+
end
|
187
|
+
|
188
|
+
# Path to the script file
|
189
|
+
#
|
190
|
+
# ===== Returns
|
191
|
+
# path<Pathname>:: path to script file
|
192
|
+
#
|
193
|
+
def path
|
194
|
+
Pathname(@path.respond_to?(:to_path) ? @path.to_path : @path.to_s).expand_path
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
# Rules corresponding to a given path, in reversed order of precedence
|
200
|
+
# (latest one is most inportant).
|
201
|
+
#
|
202
|
+
# ===== Parameters
|
203
|
+
# path<Pathname, String>:: path to look up rule for
|
204
|
+
#
|
205
|
+
# ===== Returns
|
206
|
+
# rules<Array(Rule)>:: rules corresponding to <tt>path</tt>
|
207
|
+
#
|
208
|
+
def rules_for(path)
|
209
|
+
@rules.reverse.select {|rule| path.match(rule.pattern) }
|
210
|
+
end
|
211
|
+
|
212
|
+
# Make a path relative to current working directory.
|
213
|
+
#
|
214
|
+
# ===== Parameters
|
215
|
+
# path<Pathname, String>:: absolute or relative path
|
216
|
+
#
|
217
|
+
# ===== Returns
|
218
|
+
# path<Pathname>:: relative path, from current working directory.
|
219
|
+
#
|
220
|
+
def rel_path(path)
|
221
|
+
Pathname(path).expand_path.relative_path_from(Pathname(Dir.pwd))
|
222
|
+
end
|
223
|
+
|
224
|
+
# Reset script state
|
225
|
+
def reset
|
226
|
+
@default_action = lambda {}
|
227
|
+
@rules.clear
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
data/manifest.watchr
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Run me with:
|
2
|
+
#
|
3
|
+
# $ watchr manifest.watchr
|
4
|
+
#
|
5
|
+
# This script will remove a file from from the Manifest when it gets deleted,
|
6
|
+
# and will rebuild the Manifest on Ctrl-\
|
7
|
+
#
|
8
|
+
# Mostly serves as a demo for the :delete event type (and eventually for the
|
9
|
+
# :added event type). In reality this is much better implemented as a git
|
10
|
+
# post-commit script.
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'pathname'
|
14
|
+
# --------------------------------------------------
|
15
|
+
# Helpers
|
16
|
+
# --------------------------------------------------
|
17
|
+
module Project
|
18
|
+
extend self
|
19
|
+
def files
|
20
|
+
`git ls-files --full-name`.strip.split($/).sort
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Manifest
|
25
|
+
attr_accessor :path
|
26
|
+
|
27
|
+
def initialize(path)
|
28
|
+
@path = Pathname(path).expand_path
|
29
|
+
create!
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove(path)
|
33
|
+
paths = @path.read.strip.split($/)
|
34
|
+
@path.open('w') {|f| f << (paths - [path]).join("\n") }
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(path)
|
38
|
+
paths = @path.read.strip.split($/)
|
39
|
+
@path.open('w') {|f| f << paths.push(path).sort.join("\n") }
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def create!
|
44
|
+
File.open(@path.to_s, 'w') {} unless @path.exist?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
@manifest = Manifest.new('Manifest')
|
50
|
+
|
51
|
+
# --------------------------------------------------
|
52
|
+
# Watchr Rules
|
53
|
+
# --------------------------------------------------
|
54
|
+
watch('.*', :deleted ) do |md|
|
55
|
+
@manifest.remove(md[0])
|
56
|
+
puts "removed #{md[0].inspect} from Manifest"
|
57
|
+
end
|
58
|
+
|
59
|
+
# --------------------------------------------------
|
60
|
+
# Signal Handling
|
61
|
+
# --------------------------------------------------
|
62
|
+
# Ctrl-\
|
63
|
+
Signal.trap('QUIT') do
|
64
|
+
puts " --- Updated Manifest ---\n"
|
65
|
+
@manifest.path.open('w') {|m| m << Project.files.join("\n").strip }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Ctrl-C
|
69
|
+
Signal.trap('INT') { abort("\n") }
|
70
|
+
|
data/specs.watchr
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Run me with:
|
2
|
+
#
|
3
|
+
# $ watchr specs.watchr
|
4
|
+
|
5
|
+
# --------------------------------------------------
|
6
|
+
# Convenience Methods
|
7
|
+
# --------------------------------------------------
|
8
|
+
def run(cmd)
|
9
|
+
puts(cmd)
|
10
|
+
system(cmd)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_all_tests
|
14
|
+
# see Rakefile for the definition of the test:all task
|
15
|
+
system( "rake -s test:all VERBOSE=true" )
|
16
|
+
end
|
17
|
+
|
18
|
+
# --------------------------------------------------
|
19
|
+
# Watchr Rules
|
20
|
+
# --------------------------------------------------
|
21
|
+
watch( '^test.*/test_.*\.rb' ) { |m| run( "ruby -rubygems %s" % m[0] ) }
|
22
|
+
watch( '^lib/(.*)\.rb' ) { |m| run( "ruby -rubygems test/test_%s.rb" % m[1] ) }
|
23
|
+
watch( '^lib/watchr/(.*)\.rb' ) { |m| run( "ruby -rubygems test/test_%s.rb" % m[1] ) }
|
24
|
+
watch( '^lib/watchr/event_handlers/(.*)\.rb' ) { |m| run( "ruby -rubygems test/event_handlers/test_%s.rb" % m[1] ) }
|
25
|
+
watch( '^test/test_helper\.rb' ) { run_all_tests }
|
26
|
+
|
27
|
+
# --------------------------------------------------
|
28
|
+
# Signal Handling
|
29
|
+
# --------------------------------------------------
|
30
|
+
# Ctrl-\
|
31
|
+
Signal.trap('QUIT') do
|
32
|
+
puts " --- Running all tests ---\n\n"
|
33
|
+
run_all_tests
|
34
|
+
end
|
35
|
+
|
36
|
+
# Ctrl-C
|
37
|
+
Signal.trap('INT') { abort("\n") }
|
38
|
+
|
data/test/README
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class BaseEventHandlerTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class Handler
|
6
|
+
include Watchr::EventHandler::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@handler = Handler.new
|
11
|
+
end
|
12
|
+
|
13
|
+
test "api" do
|
14
|
+
@handler.should respond_to(:notify)
|
15
|
+
@handler.should respond_to(:listen)
|
16
|
+
@handler.should respond_to(:refresh)
|
17
|
+
@handler.class.ancestors.should include(Observable)
|
18
|
+
end
|
19
|
+
|
20
|
+
test "notifies observers" do
|
21
|
+
@handler.expects(:notify_observers).with('foo/bar', nil)
|
22
|
+
@handler.notify('foo/bar', nil)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
if false && HAVE_EM
|
4
|
+
|
5
|
+
class Watchr::EventHandler::Unix::SingleFileWatcher
|
6
|
+
public :type
|
7
|
+
end
|
8
|
+
|
9
|
+
class UnixEventHandlerTest < Test::Unit::TestCase
|
10
|
+
include Watchr
|
11
|
+
|
12
|
+
SingleFileWatcher = EventHandler::Unix::SingleFileWatcher
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@now = Time.now
|
16
|
+
pathname = Pathname.new('foo/bar')
|
17
|
+
pathname.stubs(:atime ).returns(@now)
|
18
|
+
pathname.stubs(:mtime ).returns(@now)
|
19
|
+
pathname.stubs(:ctime ).returns(@now)
|
20
|
+
pathname.stubs(:exist?).returns(true)
|
21
|
+
SingleFileWatcher.any_instance.stubs(:pathname).returns(pathname)
|
22
|
+
|
23
|
+
@loop = Rev::Loop.default
|
24
|
+
@handler = EventHandler::Unix.new
|
25
|
+
@watcher = SingleFileWatcher.new('foo/bar')
|
26
|
+
@loop.stubs(:run)
|
27
|
+
end
|
28
|
+
|
29
|
+
def teardown
|
30
|
+
SingleFileWatcher.handler = nil
|
31
|
+
Rev::Loop.default.watchers.every.detach
|
32
|
+
end
|
33
|
+
|
34
|
+
test "triggers listening state" do
|
35
|
+
@loop.expects(:run)
|
36
|
+
@handler.listen([])
|
37
|
+
end
|
38
|
+
|
39
|
+
## SingleFileWatcher
|
40
|
+
|
41
|
+
test "watcher pathname" do
|
42
|
+
@watcher.pathname.should be_kind_of(Pathname)
|
43
|
+
@watcher.pathname.to_s.should be(@watcher.path)
|
44
|
+
end
|
45
|
+
|
46
|
+
test "stores reference times" do
|
47
|
+
@watcher.pathname.stubs(:atime).returns(:time)
|
48
|
+
@watcher.pathname.stubs(:mtime).returns(:time)
|
49
|
+
@watcher.pathname.stubs(:ctime).returns(:time)
|
50
|
+
|
51
|
+
@watcher.send(:update_reference_times)
|
52
|
+
@watcher.instance_variable_get(:@reference_atime).should be(:time)
|
53
|
+
@watcher.instance_variable_get(:@reference_mtime).should be(:time)
|
54
|
+
@watcher.instance_variable_get(:@reference_ctime).should be(:time)
|
55
|
+
end
|
56
|
+
|
57
|
+
test "stores initial reference times" do
|
58
|
+
SingleFileWatcher.any_instance.expects(:update_reference_times)
|
59
|
+
SingleFileWatcher.new('foo')
|
60
|
+
end
|
61
|
+
|
62
|
+
test "updates reference times on change" do
|
63
|
+
@watcher.expects(:update_reference_times)
|
64
|
+
@watcher.on_change
|
65
|
+
end
|
66
|
+
|
67
|
+
test "detects event type" do
|
68
|
+
trigger_event @watcher, @now, :atime
|
69
|
+
@watcher.type.should be(:accessed)
|
70
|
+
|
71
|
+
trigger_event @watcher, @now, :mtime
|
72
|
+
@watcher.type.should be(:modified)
|
73
|
+
|
74
|
+
trigger_event @watcher, @now, :ctime
|
75
|
+
@watcher.type.should be(:changed)
|
76
|
+
|
77
|
+
trigger_event @watcher, @now, :atime, :mtime
|
78
|
+
@watcher.type.should be(:modified)
|
79
|
+
|
80
|
+
trigger_event @watcher, @now, :mtime, :ctime
|
81
|
+
@watcher.type.should be(:modified)
|
82
|
+
|
83
|
+
trigger_event @watcher, @now, :atime, :ctime
|
84
|
+
@watcher.type.should be(:accessed)
|
85
|
+
|
86
|
+
trigger_event @watcher, @now, :atime, :mtime, :ctime
|
87
|
+
@watcher.type.should be(:modified)
|
88
|
+
|
89
|
+
@watcher.pathname.stubs(:exist?).returns(false)
|
90
|
+
@watcher.type.should be(:deleted)
|
91
|
+
end
|
92
|
+
|
93
|
+
## monitoring file events
|
94
|
+
|
95
|
+
test "listens for events on monitored files" do
|
96
|
+
@handler.listen %w( foo bar )
|
97
|
+
@loop.watchers.size.should be(2)
|
98
|
+
@loop.watchers.every.path.should include('foo', 'bar')
|
99
|
+
@loop.watchers.every.class.uniq.should be([SingleFileWatcher])
|
100
|
+
end
|
101
|
+
|
102
|
+
test "notifies observers on file event" do
|
103
|
+
@watcher.stubs(:path).returns('foo')
|
104
|
+
@handler.expects(:notify).with('foo', anything)
|
105
|
+
@watcher.on_change
|
106
|
+
end
|
107
|
+
|
108
|
+
test "notifies observers of event type" do
|
109
|
+
trigger_event @watcher, @now, :atime
|
110
|
+
@handler.expects(:notify).with('foo/bar', :accessed)
|
111
|
+
@watcher.on_change
|
112
|
+
|
113
|
+
trigger_event @watcher, @now, :mtime
|
114
|
+
@handler.expects(:notify).with('foo/bar', :modified)
|
115
|
+
@watcher.on_change
|
116
|
+
|
117
|
+
trigger_event @watcher, @now, :ctime
|
118
|
+
@handler.expects(:notify).with('foo/bar', :changed)
|
119
|
+
@watcher.on_change
|
120
|
+
|
121
|
+
trigger_event @watcher, @now, :atime, :mtime, :ctime
|
122
|
+
@handler.expects(:notify).with('foo/bar', :modified)
|
123
|
+
@watcher.on_change
|
124
|
+
|
125
|
+
@watcher.pathname.stubs(:exist?).returns(false)
|
126
|
+
@handler.expects(:notify).with('foo/bar', :deleted)
|
127
|
+
@watcher.on_change
|
128
|
+
end
|
129
|
+
|
130
|
+
## on the fly updates of monitored files list
|
131
|
+
|
132
|
+
test "reattaches to new monitored files" do
|
133
|
+
@handler.listen %w( foo bar )
|
134
|
+
@loop.watchers.size.should be(2)
|
135
|
+
@loop.watchers.every.path.should include('foo')
|
136
|
+
@loop.watchers.every.path.should include('bar')
|
137
|
+
|
138
|
+
@handler.refresh %w( baz bax )
|
139
|
+
@loop.watchers.size.should be(2)
|
140
|
+
@loop.watchers.every.path.should include('baz')
|
141
|
+
@loop.watchers.every.path.should include('bax')
|
142
|
+
@loop.watchers.every.path.should exclude('foo')
|
143
|
+
@loop.watchers.every.path.should exclude('bar')
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def trigger_event(watcher, now, *types)
|
149
|
+
watcher.pathname.stubs(:atime).returns(now)
|
150
|
+
watcher.pathname.stubs(:mtime).returns(now)
|
151
|
+
watcher.pathname.stubs(:ctime).returns(now)
|
152
|
+
watcher.instance_variable_set(:@reference_atime, now)
|
153
|
+
watcher.instance_variable_set(:@reference_mtime, now)
|
154
|
+
watcher.instance_variable_set(:@reference_ctime, now)
|
155
|
+
|
156
|
+
types.each do |type|
|
157
|
+
watcher.pathname.stubs(type).returns(now+10)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end # if Watchr::HAVE_EM
|