watchr 0.6 → 0.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/README.md CHANGED
@@ -77,11 +77,16 @@ Install
77
77
 
78
78
  gem install watchr
79
79
 
80
- If you're on \*nix and have the [rev][4] gem installed, Watchr will detect it
81
- and use it automatically. This will make Watchr evented.
80
+ If you're on Linux/BSD and have the [rev][4] gem installed, Watchr will detect
81
+ it and use it automatically. This will make Watchr evented.
82
82
 
83
83
  gem install rev
84
84
 
85
+ You can get the same evented behaviour on OS X by installing
86
+ [ruby-fsevent][10].
87
+
88
+ gem install ruby-fsevent
89
+
85
90
  See Also
86
91
  --------
87
92
 
@@ -110,4 +115,5 @@ Links
110
115
  [7]: http://github.com/mynyml/phocus
111
116
  [8]: http://github.com/viking/autowatchr
112
117
  [9]: http://github.com/francois/nestor
118
+ [10]: http://github.com/sandro/ruby-fsevent
113
119
 
data/Rakefile CHANGED
@@ -1,3 +1,12 @@
1
+ def gem_opt
2
+ defined?(Gem) ? "-rubygems" : ""
3
+ end
4
+
5
+ def ruby
6
+ require 'rbconfig'
7
+ File.join([Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']]) << Config::CONFIG['EXEEXT']
8
+ end
9
+
1
10
  # --------------------------------------------------
2
11
  # Tests
3
12
  # --------------------------------------------------
@@ -8,7 +17,7 @@ namespace(:test) do
8
17
  desc "Run all tests"
9
18
  task(:all) do
10
19
  tests = Dir['test/**/test_*.rb'] - ['test/test_helper.rb']
11
- exit system("ruby -rubygems -I.:lib -e'%w( #{tests.join(' ')} ).each {|file| require file }'")
20
+ exit system(%Q{#{ruby} #{gem_opt} -I.:lib -e"%w( #{tests.join(' ')} ).each {|file| require file }"})
12
21
  end
13
22
 
14
23
  desc "Run all tests on multiple ruby versions (requires rvm)"
data/TODO.md CHANGED
@@ -9,6 +9,8 @@ Features
9
9
  * requires new handler(s)
10
10
  * will allow recognizing `:added` events
11
11
 
12
+ * allow setting latency
13
+
12
14
  Bugs
13
15
  ----
14
16
 
data/bin/watchr CHANGED
@@ -4,7 +4,7 @@ require 'pathname'
4
4
  require 'optparse'
5
5
  require 'tempfile'
6
6
 
7
- require 'watchr'
7
+ require File.dirname(__FILE__) + '/../lib/watchr'
8
8
 
9
9
  module Watchr
10
10
  # Namespaced to avoid defining global methods
@@ -12,8 +12,16 @@ require 'rbconfig'
12
12
  # # on command line, from project's root dir
13
13
  # $ watchr path/to/script
14
14
  #
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
16
  module Watchr
16
- VERSION = '0.6'
17
+ VERSION = '0.7'
18
+
19
+ begin
20
+ require 'fsevent'
21
+ HAVE_FSE = true
22
+ rescue LoadError, RuntimeError
23
+ HAVE_FSE = false
24
+ end
17
25
 
18
26
  begin
19
27
  require 'rev'
@@ -27,8 +35,9 @@ module Watchr
27
35
 
28
36
  module EventHandler
29
37
  autoload :Base, 'watchr/event_handlers/base'
30
- autoload :Unix, 'watchr/event_handlers/unix' if ::Watchr::HAVE_REV
31
38
  autoload :Portable, 'watchr/event_handlers/portable'
39
+ autoload :Unix, 'watchr/event_handlers/unix' if ::Watchr::HAVE_REV
40
+ autoload :Darwin, 'watchr/event_handlers/darwin' if ::Watchr::HAVE_FSE
32
41
  end
33
42
 
34
43
  class << self
@@ -100,15 +109,22 @@ module Watchr
100
109
  def handler
101
110
  @handler ||=
102
111
  case ENV['HANDLER'] || Config::CONFIG['host_os']
103
- when /mswin|windows|cygwin/i
104
- Watchr::EventHandler::Portable
105
- when /sunos|solaris|darwin|mach|osx|bsd|linux/i, 'unix'
106
- if ::Watchr::HAVE_REV
112
+ when /darwin|mach|osx|fsevents?/i
113
+ if Watchr::HAVE_FSE
114
+ Watchr::EventHandler::Darwin
115
+ else
116
+ Watchr.debug "fsevent not found. `gem install ruby-fsevent` to get evented handler"
117
+ Watchr::EventHandler::Portable
118
+ end
119
+ when /sunos|solaris|bsd|linux|unix/i
120
+ if Watchr::HAVE_REV
107
121
  Watchr::EventHandler::Unix
108
122
  else
109
123
  Watchr.debug "rev not found. `gem install rev` to get evented handler"
110
124
  Watchr::EventHandler::Portable
111
125
  end
126
+ when /mswin|windows|cygwin/i
127
+ Watchr::EventHandler::Portable
112
128
  else
113
129
  Watchr::EventHandler::Portable
114
130
  end
@@ -58,6 +58,7 @@ module Watchr
58
58
  def update(path, event_type = nil)
59
59
  path = Pathname(path).expand_path
60
60
 
61
+ Watchr.debug("received #{event_type.inspect} event for #{path.relative_path_from(Pathname(Dir.pwd))}")
61
62
  if path == @script.path
62
63
  @script.parse!
63
64
  @handler.refresh(monitored_paths)
@@ -0,0 +1,160 @@
1
+ module Watchr
2
+ module EventHandler
3
+
4
+ class ::FSEvents
5
+ # Same as Watch.debug, but prefixed with [fsevents] instead.
6
+ #
7
+ # @example
8
+ #
9
+ # FSEvents.debug('missfired')
10
+ #
11
+ # @param [String] message
12
+ # debug message to print
13
+ #
14
+ # @return [nil]
15
+ #
16
+ def self.debug(msg)
17
+ puts "[fsevents] #{msg}" if Watchr.options.debug
18
+ end
19
+ end
20
+
21
+ # FSEvents based event handler for Darwin/OSX
22
+ #
23
+ # Uses ruby-fsevents (http://github.com/sandro/ruby-fsevent)
24
+ #
25
+ class Darwin < FSEvent
26
+ include Base
27
+
28
+ def initialize
29
+ super
30
+ self.latency = 0.2
31
+ end
32
+
33
+ # Enter listening loop. Will block control flow until application is
34
+ # explicitly stopped/killed.
35
+ #
36
+ # @return [undefined]
37
+ #
38
+ def listen(monitored_paths)
39
+ register_paths(monitored_paths)
40
+ start
41
+ end
42
+
43
+ # Rebuild file bindings. Will detach all current bindings, and reattach
44
+ # the `monitored_paths`
45
+ #
46
+ # @param [Array<Pathname>] monitored_paths
47
+ # list of paths the application is currently monitoring.
48
+ #
49
+ # @return [undefined]
50
+ #
51
+ def refresh(monitored_paths)
52
+ register_paths(monitored_paths)
53
+ restart
54
+ end
55
+
56
+ private
57
+
58
+ # Callback. Called on file change event. Delegates to
59
+ # {Controller#update}, passing in path and event type
60
+ #
61
+ # @return [undefined]
62
+ #
63
+ def on_change(dirs)
64
+ dirs.each do |dir|
65
+ path, type = detect_change(dir)
66
+ notify(path, type) unless path.nil?
67
+ end
68
+ end
69
+
70
+ # Detected latest updated file within given directory
71
+ #
72
+ # @param [Pathname, String] dir
73
+ # directory reporting event
74
+ #
75
+ # @return [Array(Pathname, Symbol)] path and type
76
+ # path to updated file and event type
77
+ #
78
+ def detect_change(dir)
79
+ paths = monitored_paths_for(dir)
80
+ type = nil
81
+ path = paths.find {|path| type = event_type(path) }
82
+
83
+ FSEvents.debug("event detection error") if type.nil?
84
+
85
+ update_reference_times
86
+ [path, type]
87
+ end
88
+
89
+ # Detect type of event for path, if any
90
+ #
91
+ # Path times (atime, mtime, ctime) are compared to stored references.
92
+ # If any is more recent, the event is reported as a symbol.
93
+ #
94
+ # @param [Pathname] path
95
+ #
96
+ # @return [Symbol, nil] event type
97
+ # Event type if detected, nil otherwise.
98
+ # Symbol is on of :deleted, :modified, :accessed, :changed
99
+ #
100
+ def event_type(path)
101
+ return :deleted if !path.exist?
102
+ return :modified if path.mtime > @reference_times[path][:mtime]
103
+ return :accessed if path.atime > @reference_times[path][:atime]
104
+ return :changed if path.ctime > @reference_times[path][:ctime]
105
+ nil
106
+ end
107
+
108
+ # Monitored paths within given dir
109
+ #
110
+ # @param [Pathname, String] dir
111
+ #
112
+ # @return [Array<Pathname>] monitored_paths
113
+ #
114
+ def monitored_paths_for(dir)
115
+ dir = Pathname(dir).expand_path
116
+ @paths.select {|path| path.dirname.expand_path == dir }
117
+ end
118
+
119
+ # Register watches for paths
120
+ #
121
+ # @param [Array<Pathname>] paths
122
+ #
123
+ # @return [undefined]
124
+ #
125
+ def register_paths(paths)
126
+ @paths = paths
127
+ watch_directories(dirs_for(@paths))
128
+ update_reference_times
129
+ end
130
+
131
+ # Directories for paths
132
+ #
133
+ # A unique list of directories containing given paths
134
+ #
135
+ # @param [Array<Pathname>] paths
136
+ #
137
+ # @return [Array<Pathname>] dirs
138
+ #
139
+ def dirs_for(paths)
140
+ paths.map {|path| path.dirname.to_s }.uniq
141
+ end
142
+
143
+ # Update reference times for registered paths
144
+ #
145
+ # @return [undefined]
146
+ #
147
+ def update_reference_times
148
+ @reference_times = {}
149
+ now = Time.now
150
+ @paths.each do |path|
151
+ @reference_times[path] = {}
152
+ @reference_times[path][:atime] = now
153
+ @reference_times[path][:mtime] = now
154
+ @reference_times[path][:ctime] = now
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+
@@ -0,0 +1,111 @@
1
+ require 'test/test_helper'
2
+
3
+ if Watchr::HAVE_FSE
4
+
5
+ class Watchr::EventHandler::Darwin
6
+ attr_accessor :paths
7
+
8
+ def start() end #noop
9
+ def restart() end #noop
10
+
11
+ public :on_change, :registered_directories
12
+ end
13
+
14
+ class DarwinEventHandlerTest < MiniTest::Unit::TestCase
15
+ include Watchr
16
+
17
+ def tempfile(name)
18
+ file = Tempfile.new(name, @root.to_s)
19
+ Pathname(file.path)
20
+ ensure
21
+ file.close
22
+ end
23
+
24
+ def setup
25
+ @root = Pathname(Dir.mktmpdir("WATCHR_SPECS-"))
26
+
27
+ @now = Time.now
28
+ @handler = EventHandler::Darwin.new
29
+
30
+ @foo = tempfile('foo').expand_path
31
+ @bar = tempfile('bar').expand_path
32
+ end
33
+
34
+ def teardown
35
+ FileUtils.remove_entry_secure(@root.to_s)
36
+ end
37
+
38
+ test "listening triggers listening state" do
39
+ @handler.expects(:start)
40
+ @handler.listen([])
41
+ end
42
+
43
+ test "listens for events on monitored files" do
44
+ @handler.listen [ @foo, @bar ]
45
+ assert_includes @handler.paths, @foo
46
+ assert_includes @handler.paths, @bar
47
+ end
48
+
49
+ test "reattaches to new monitored files" do
50
+ @baz = tempfile('baz').expand_path
51
+ @bax = tempfile('bax').expand_path
52
+
53
+ @handler.listen [ @foo, @bar ]
54
+ assert_includes @handler.paths, @foo
55
+ assert_includes @handler.paths, @bar
56
+
57
+ @handler.refresh [ @baz, @bax ]
58
+ assert_includes @handler.paths, @baz
59
+ assert_includes @handler.paths, @bax
60
+ refute_includes @handler.paths, @foo
61
+ refute_includes @handler.paths, @bar
62
+ end
63
+
64
+ ## event types
65
+
66
+ test "deleted file event" do
67
+ @foo.stubs(:exist?).returns(false)
68
+
69
+ @handler.listen [ @foo, @bar ]
70
+ @handler.expects(:notify).with(@foo, :deleted)
71
+ @handler.on_change [@root]
72
+ end
73
+
74
+ test "modified file event" do
75
+ @foo.stubs(:mtime).returns(@now + 100)
76
+ @handler.expects(:notify).with(@foo, :modified)
77
+
78
+ @handler.listen [ @foo, @bar ]
79
+ @handler.on_change [@root]
80
+ end
81
+
82
+ test "accessed file event" do
83
+ @foo.stubs(:atime).returns(@now + 100)
84
+ @handler.expects(:notify).with(@foo, :accessed)
85
+
86
+ @handler.listen [ @foo, @bar ]
87
+ @handler.on_change [@root]
88
+ end
89
+
90
+ test "changed file event" do
91
+ @foo.stubs(:ctime).returns(@now + 100)
92
+ @handler.expects(:notify).with(@foo, :changed)
93
+
94
+ @handler.listen [ @foo, @bar ]
95
+ @handler.on_change [@root]
96
+ end
97
+
98
+ ## internal
99
+
100
+ test "registers directories" do
101
+ @handler.listen [ @foo, @bar ]
102
+
103
+ assert_equal @foo.dirname, @bar.dirname # make sure all tempfiles are in same dir
104
+ assert_equal 1, @handler.registered_directories.size
105
+ assert_includes @handler.registered_directories, @foo.dirname.to_s
106
+ assert_includes @handler.registered_directories, @bar.dirname.to_s
107
+ end
108
+ end
109
+
110
+ end # if Watchr::HAVE_FSE
111
+
@@ -1,6 +1,7 @@
1
1
  require 'pathname'
2
+ require 'tmpdir'
2
3
  require 'tempfile'
3
- require 'set'
4
+ require 'fileutils'
4
5
 
5
6
  require 'minitest/autorun'
6
7
  require 'mocha'
@@ -30,3 +31,7 @@ unless Watchr::HAVE_REV
30
31
  puts "Skipping Unix handler tests. Install Rev (gem install rev) to properly test full suite"
31
32
  end
32
33
 
34
+ unless Watchr::HAVE_FSE
35
+ puts "Skipping Darwin handler tests. Install FSEvent (gem install ruby-fsevent) to properly test full suite (osx only)"
36
+ end
37
+
@@ -35,12 +35,24 @@ class TestWatchr < MiniTest::Unit::TestCase
35
35
  assert_equal Watchr::EventHandler::Unix, Watchr.handler
36
36
 
37
37
  Watchr.handler = nil
38
- ENV['HANDLER'] = 'darwin'
38
+ ENV['HANDLER'] = 'unix'
39
39
  assert_equal Watchr::EventHandler::Unix, Watchr.handler
40
40
 
41
+ end
42
+
43
+ if Watchr::HAVE_FSE
44
+
41
45
  Watchr.handler = nil
42
- ENV['HANDLER'] = 'unix'
43
- assert_equal Watchr::EventHandler::Unix, Watchr.handler
46
+ ENV['HANDLER'] = 'darwin'
47
+ assert_equal Watchr::EventHandler::Darwin, Watchr.handler
48
+
49
+ Watchr.handler = nil
50
+ ENV['HANDLER'] = 'osx'
51
+ assert_equal Watchr::EventHandler::Darwin, Watchr.handler
52
+
53
+ Watchr.handler = nil
54
+ ENV['HANDLER'] = 'fsevent'
55
+ assert_equal Watchr::EventHandler::Darwin, Watchr.handler
44
56
 
45
57
  end
46
58
 
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.bindir = "bin"
13
13
  s.executables = "watchr"
14
14
  s.version = Watchr::VERSION
15
- s.files = File.read("Manifest").strip.split("\n")
15
+ s.files = `git ls-files`.strip.split("\n")
16
16
 
17
17
  s.add_development_dependency 'minitest'
18
18
  s.add_development_dependency 'mocha'
metadata CHANGED
@@ -1,7 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watchr
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.6"
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 7
8
+ version: "0.7"
5
9
  platform: ruby
6
10
  authors:
7
11
  - mynyml
@@ -9,39 +13,45 @@ autorequire:
9
13
  bindir: bin
10
14
  cert_chain: []
11
15
 
12
- date: 2010-02-10 00:00:00 -05:00
16
+ date: 2010-08-23 00:00:00 -07:00
13
17
  default_executable:
14
18
  dependencies:
15
19
  - !ruby/object:Gem::Dependency
16
20
  name: minitest
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
20
23
  requirements:
21
24
  - - ">="
22
25
  - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
23
28
  version: "0"
24
- version:
29
+ type: :development
30
+ version_requirements: *id001
25
31
  - !ruby/object:Gem::Dependency
26
32
  name: mocha
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
33
+ prerelease: false
34
+ requirement: &id002 !ruby/object:Gem::Requirement
30
35
  requirements:
31
36
  - - ">="
32
37
  - !ruby/object:Gem::Version
38
+ segments:
39
+ - 0
33
40
  version: "0"
34
- version:
41
+ type: :development
42
+ version_requirements: *id002
35
43
  - !ruby/object:Gem::Dependency
36
44
  name: every
37
- type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
45
+ prerelease: false
46
+ requirement: &id003 !ruby/object:Gem::Requirement
40
47
  requirements:
41
48
  - - ">="
42
49
  - !ruby/object:Gem::Version
50
+ segments:
51
+ - 0
43
52
  version: "0"
44
- version:
53
+ type: :development
54
+ version_requirements: *id003
45
55
  description: Modern continious testing (flexible alternative to autotest).
46
56
  email: mynyml@gmail.com
47
57
  executables:
@@ -54,7 +64,6 @@ files:
54
64
  - .gitignore
55
65
  - History.txt
56
66
  - LICENSE
57
- - Manifest
58
67
  - README.md
59
68
  - Rakefile
60
69
  - TODO.md
@@ -65,12 +74,14 @@ files:
65
74
  - lib/watchr.rb
66
75
  - lib/watchr/controller.rb
67
76
  - lib/watchr/event_handlers/base.rb
77
+ - lib/watchr/event_handlers/darwin.rb
68
78
  - lib/watchr/event_handlers/portable.rb
69
79
  - lib/watchr/event_handlers/unix.rb
70
80
  - lib/watchr/script.rb
71
81
  - specs.watchr
72
82
  - test/README
73
83
  - test/event_handlers/test_base.rb
84
+ - test/event_handlers/test_darwin.rb
74
85
  - test/event_handlers/test_portable.rb
75
86
  - test/event_handlers/test_unix.rb
76
87
  - test/test_controller.rb
@@ -91,18 +102,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
102
  requirements:
92
103
  - - ">="
93
104
  - !ruby/object:Gem::Version
105
+ segments:
106
+ - 0
94
107
  version: "0"
95
- version:
96
108
  required_rubygems_version: !ruby/object:Gem::Requirement
97
109
  requirements:
98
110
  - - ">="
99
111
  - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
100
114
  version: "0"
101
- version:
102
115
  requirements: []
103
116
 
104
117
  rubyforge_project: watchr
105
- rubygems_version: 1.3.5
118
+ rubygems_version: 1.3.6
106
119
  signing_key:
107
120
  specification_version: 3
108
121
  summary: Modern continious testing (flexible alternative to autotest)
data/Manifest DELETED
@@ -1,27 +0,0 @@
1
- .gitignore
2
- History.txt
3
- LICENSE
4
- Manifest
5
- README.md
6
- Rakefile
7
- TODO.md
8
- bin/watchr
9
- contributions.txt
10
- docs.watchr
11
- gem.watchr
12
- lib/watchr.rb
13
- lib/watchr/controller.rb
14
- lib/watchr/event_handlers/base.rb
15
- lib/watchr/event_handlers/portable.rb
16
- lib/watchr/event_handlers/unix.rb
17
- lib/watchr/script.rb
18
- specs.watchr
19
- test/README
20
- test/event_handlers/test_base.rb
21
- test/event_handlers/test_portable.rb
22
- test/event_handlers/test_unix.rb
23
- test/test_controller.rb
24
- test/test_helper.rb
25
- test/test_script.rb
26
- test/test_watchr.rb
27
- watchr.gemspec