watchr 0.5.9 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest CHANGED
@@ -2,9 +2,9 @@
2
2
  History.txt
3
3
  LICENSE
4
4
  Manifest
5
- README.rdoc
5
+ README.md
6
6
  Rakefile
7
- TODO.txt
7
+ TODO.md
8
8
  bin/watchr
9
9
  contributions.txt
10
10
  docs.watchr
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ Summary
2
+ -------
3
+
4
+ Agile development tool that monitors a directory tree, and triggers a user
5
+ defined action whenever an observed file is modified. Its most typical use is
6
+ continuous testing, and as such it is a more flexible alternative to autotest.
7
+
8
+ Features
9
+ --------
10
+
11
+ watchr is:
12
+
13
+ * Simple to use
14
+ * Highly flexible
15
+ * Evented ( Listens for filesystem events with native c libs )
16
+ * Portable ( Linux, \*BSD, OSX, Solaris, Windows )
17
+ * Fast ( Immediately reacts to file changes )
18
+
19
+ Most importantly it allows running tests in an environment that is **agnostic** to:
20
+
21
+ * Web frameworks ( rails, merb, sinatra, camping, invisible, ... )
22
+ * Test frameworks ( test/unit, minitest, rspec, test/spec, expectations, ... )
23
+ * Ruby interpreters ( ruby1.8, ruby1.9, MRI, JRuby, Rubinius, ... )
24
+ * Package frameworks ( rubygems, rip, ... )
25
+
26
+ Usage
27
+ -----
28
+
29
+ On the command line,
30
+
31
+ $ watchr path/to/script.file
32
+
33
+ will monitor files in the current directory tree, and react to events on those
34
+ files in accordance with the script.
35
+
36
+ Scripts
37
+ -------
38
+
39
+ The script contains a set of simple rules that map observed files to an action.
40
+ Its DSL is a single method: `watch(pattern, &action)`
41
+
42
+ watch( 'a regexp pattern matching paths to observe' ) {|match_data_object| command_to_run }
43
+
44
+ So for example,
45
+
46
+ watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
47
+
48
+ will match any test file and run it whenever it is saved.
49
+
50
+ A continuous testing script for a basic project could be
51
+
52
+ watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
53
+ watch( 'lib/(.*)\.rb' ) {|md| system("ruby test/test_#{md[1]}.rb") }
54
+
55
+ which, in addition to running any saved test file as above, will also run a
56
+ lib file's associated test. This mimics the equivalent autotest behaviour.
57
+
58
+ It's easy to see why watchr is so flexible, since the whole command is custom.
59
+ The above actions could just as easily call "jruby", "ruby --rubygems", "ruby
60
+ -Ilib", "specrb", "rbx", ... or any combination of these. For the sake of
61
+ comparison, autotest runs with:
62
+
63
+ $ /usr/bin/ruby1.8 -I.:lib:test -rubygems -e "%w[test/unit test/test_helper.rb test/test_watchr.rb].each { |f| require f }"
64
+
65
+ locking the environment into ruby1.8, rubygems and test/unit for all tests.
66
+
67
+ And remember the scripts are pure ruby, so feel free to add methods,
68
+ `Signal#trap` calls, etc. Updates to script files are picked up on the fly (no
69
+ need to restart watchr) so experimenting is painless.
70
+
71
+ The [wiki][5] has more details and examples. You might also want to take a
72
+ look at watchr's own scripts, [specs.watchr][1], [docs.watchr][2] and
73
+ [gem.watchr][3], to get you started.
74
+
75
+ Install
76
+ -------
77
+
78
+ gem install watchr
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.
82
+
83
+ gem install rev
84
+
85
+ See Also
86
+ --------
87
+
88
+ * [redgreen][6]: Standalone redgreen eye candy for test results, ala autotest.
89
+ * [phocus][7]: Run focused tests when running the whole file/suite is unnecessary.
90
+ * [autowatchr][8]: Provides some autotest-like behavior for watchr
91
+ * [nestor][9]: Continuous testing server for Rails
92
+
93
+ Links
94
+ -----
95
+
96
+ * code: <http://github.com/mynyml/watchr>
97
+ * docs: <http://yardoc.org/docs/mynyml-watchr/file:README.rdoc>
98
+ * wiki: <http://wiki.github.com/mynyml/watchr>
99
+ * bugs: <http://github.com/mynyml/watchr/issues>
100
+
101
+
102
+
103
+
104
+ [1]: http://github.com/mynyml/watchr/blob/master/specs.watchr
105
+ [2]: http://github.com/mynyml/watchr/blob/master/docs.watchr
106
+ [3]: http://github.com/mynyml/watchr/blob/master/gem.watchr
107
+ [4]: http://github.com/tarcieri/rev/
108
+ [5]: http://wiki.github.com/mynyml/watchr
109
+ [6]: http://github.com/mynyml/redgreen
110
+ [7]: http://github.com/mynyml/phocus
111
+ [8]: http://github.com/viking/autowatchr
112
+ [9]: http://github.com/francois/nestor
113
+
data/Rakefile CHANGED
@@ -8,9 +8,7 @@ namespace(:test) do
8
8
  desc "Run all tests"
9
9
  task(:all) do
10
10
  tests = Dir['test/**/test_*.rb'] - ['test/test_helper.rb']
11
- cmd = "ruby -rubygems -I.:lib -e'%w( #{tests.join(' ')} ).each {|file| require file }'"
12
- puts cmd if ENV['VERBOSE']
13
- system cmd
11
+ exit system("ruby -rubygems -I.:lib -e'%w( #{tests.join(' ')} ).each {|file| require file }'")
14
12
  end
15
13
 
16
14
  desc "Run all tests on multiple ruby versions (requires rvm)"
@@ -25,29 +23,3 @@ namespace(:test) do
25
23
  end
26
24
  end
27
25
  end
28
-
29
- # --------------------------------------------------
30
- # Docs
31
- # --------------------------------------------------
32
- require 'rake/rdoctask'
33
- desc "Generate rdoc documentation."
34
- Rake::RDocTask.new(:rdoc => 'rdoc', :clobber_rdoc => 'rdoc:clean', :rerdoc => 'rdoc:force') do |rdoc|
35
- rdoc.rdoc_dir = 'doc/rdoc'
36
- rdoc.title = "Watchr"
37
- rdoc.options << '--line-numbers' << '--inline-source'
38
- rdoc.options << '--charset' << 'utf-8'
39
- rdoc.main = 'README.rdoc'
40
- rdoc.rdoc_files.include('README.rdoc')
41
- rdoc.rdoc_files.include('TODO.txt')
42
- rdoc.rdoc_files.include('LICENSE')
43
- rdoc.rdoc_files.include('lib/**/*.rb')
44
- end
45
-
46
- desc "Generate YARD Documentation"
47
- task(:yardoc) do
48
- require 'yard'
49
- files = %w( lib/**/*.rb )
50
- options = %w( -o doc/yard --readme README.rdoc --files LICENSE )
51
- YARD::CLI::Yardoc.run *(options + files)
52
- end
53
-
data/TODO.md ADDED
@@ -0,0 +1,29 @@
1
+ Features
2
+ --------
3
+
4
+ * watchr -e ( `$ watchr -e "watch('foo.gemspec') { system('gem build foo.gemspec') }"` )
5
+ * watchr --auto
6
+ * watchr --fetch
7
+
8
+ * enable ability to watch dirs
9
+ * requires new handler(s)
10
+ * will allow recognizing `:added` events
11
+
12
+ Bugs
13
+ ----
14
+
15
+ * sometimes an action is fired without a file being saved
16
+ * buffer flushing issue?
17
+ * libev issue?
18
+ * probably fixed with event type handling update, which ignores atime
19
+ updates by defaults
20
+
21
+ * when a file is saved twice quickly, subsequent events are ignored.
22
+ * seems like rev/libev drops the file watch
23
+
24
+ Other
25
+ -----
26
+
27
+ * add tests for executable
28
+ * memory profiling / benchmarks
29
+
data/bin/watchr CHANGED
@@ -2,14 +2,21 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'optparse'
5
+ require 'tempfile'
5
6
 
6
7
  require 'watchr'
7
8
 
8
9
  module Watchr
9
10
  # Namespaced to avoid defining global methods
10
- module Bin #:nodoc:
11
+ #
12
+ # @private
13
+ module Bin
11
14
  extend self
12
15
 
16
+ DEFAULT_SCRIPT_PATH = Pathname.new('specs.watchr')
17
+
18
+ attr_accessor :path
19
+
13
20
  def usage
14
21
  "Usage: watchr [opts] path/to/script"
15
22
  end
@@ -18,20 +25,41 @@ module Watchr
18
25
  "watchr version: %s" % Watchr::VERSION
19
26
  end
20
27
 
28
+ # Absolute path to script file
29
+ #
30
+ # Unless set manually, the script's path is either first arg or
31
+ # `DEFAULT_SCRIPT_PATH`. If neither exists, the script immediatly aborts
32
+ # with an appropriate error message.
33
+ #
34
+ # @return [Pathname]
35
+ # absolute path to script
36
+ #
37
+ def path!
38
+ return @path unless @path.nil?
39
+ rel = relative_path or abort( usage )
40
+ find_in_load_path(rel) or abort("no script found: file #{rel.to_s.inspect} is not in path.")
41
+ end
42
+
21
43
  # Find a partial path name in load path
22
44
  #
23
- # ===== Params
24
- # path<Pathname>:: partial pathname
45
+ # @param [Pathname] path
46
+ # partial pathname
25
47
  #
26
- # ===== Returns
27
- # <Pathname>::
48
+ # @return [Pathname]
28
49
  # absolute path of first occurence of partial path in load path, or nil if not found
29
- #--
30
- # Adds '.' for ruby1.9.2
50
+ #
31
51
  def find_in_load_path(path)
52
+ # Adds '.' for ruby1.9.2
32
53
  dir = (['.'] + $LOAD_PATH).uniq.detect {|p| Pathname(p).join(path).exist? }
33
54
  dir ? path.expand_path(dir) : nil
34
55
  end
56
+
57
+ private
58
+
59
+ def relative_path
60
+ return Pathname.new(ARGV.first) if ARGV.first
61
+ return DEFAULT_SCRIPT_PATH if DEFAULT_SCRIPT_PATH.exist?
62
+ end
35
63
  end
36
64
  end
37
65
 
@@ -45,6 +73,27 @@ opts = OptionParser.new do |opts|
45
73
  rescue LoadError, RuntimeError
46
74
  end
47
75
  }
76
+ opts.on('-l', '--list', "Display list of files monitored by script and exit") {
77
+ script = Watchr::Script.new(Watchr::Bin.path!)
78
+ controller = Watchr::Controller.new(script, Watchr.handler.new)
79
+ script.parse!
80
+ puts controller.monitored_paths
81
+ exit
82
+ }
83
+
84
+ def assert_syntax(code)
85
+ catch(:ok) { Object.new.instance_eval("BEGIN { throw :ok }; #{code}", %|-e "#{code}"|, 0) }
86
+ rescue SyntaxError => e
87
+ puts e.message.split("\n")[1]
88
+ exit
89
+ end
90
+
91
+ opts.on('-e', '--eval INLINE_SCRIPT', %|Evaluate script inline ($ watchr -e "watch('foo') { puts 'bar' }")|) {|code|
92
+ assert_syntax(code)
93
+
94
+ Tempfile.open('foo') {|f| f << code; @__path = f.path }
95
+ Watchr::Bin.path = Pathname(@__path)
96
+ }
48
97
 
49
98
  opts.on_tail('-h', '--help', "Print inline help") { puts opts; exit }
50
99
  opts.on_tail('-v', '--version', "Print version" ) { puts Watchr::Bin.version; exit }
@@ -52,8 +101,5 @@ opts = OptionParser.new do |opts|
52
101
  opts.parse! ARGV
53
102
  end
54
103
 
55
- relative_path = Pathname( ARGV.first ) rescue abort(Watchr::Bin.usage)
56
- absolute_path = Watchr::Bin.find_in_load_path(relative_path) or abort("no script found; file #{relative_path.to_s.inspect} is not in path.")
57
-
58
- Watchr::Controller.new(Watchr::Script.new(absolute_path), Watchr.handler.new).run
104
+ Watchr::Controller.new(Watchr::Script.new(Watchr::Bin.path!), Watchr.handler.new).run
59
105
 
data/docs.watchr CHANGED
@@ -1,26 +1,26 @@
1
1
  # Run me with:
2
- #
3
2
  # $ watchr docs.watchr
4
3
 
5
- def run_rdoc
6
- system('rake --silent rdoc')
7
- end
4
+ require 'yard'
5
+ # --------------------------------------------------
6
+ # Rules
7
+ # --------------------------------------------------
8
+ watch( 'lib/.*\.rb' ) { yard }
9
+ watch( 'README.md' ) { yard }
10
+ watch( 'TODO.md' ) { yard }
11
+ watch( 'LICENSE' ) { yard }
8
12
 
9
- def run_yard
10
- print "\nUpdating yardocs... "
11
- system('rake --silent yardoc')
12
- print "done.\n"
13
- end
13
+ # --------------------------------------------------
14
+ # Signal Handling
15
+ # --------------------------------------------------
16
+ Signal.trap('QUIT') { yard } # Ctrl-\
17
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
14
18
 
15
- def document
16
- run_rdoc
17
- run_yard
19
+ # --------------------------------------------------
20
+ # Helpers
21
+ # --------------------------------------------------
22
+ def yard
23
+ print "Updating yardocs... "; STDOUT.flush
24
+ YARD::CLI::Yardoc.run *%w( -o doc/yard --readme README.md --markup markdown - LICENSE TODO.md )
25
+ print "done\n"
18
26
  end
19
-
20
- watch( 'lib/.*\.rb' ) { document }
21
- watch( 'README.rdoc' ) { document }
22
- watch( 'TODO.txt' ) { document }
23
- watch( 'LICENSE' ) { document }
24
-
25
-
26
- # vim:ft=ruby
data/gem.watchr CHANGED
@@ -1,32 +1,22 @@
1
1
  # Run me with:
2
- #
3
2
  # $ watchr gem.watchr
4
3
 
4
+ def gemspec() Dir['*.gemspec'].first end
5
5
  # --------------------------------------------------
6
- # Convenience Methods
6
+ # Rules
7
7
  # --------------------------------------------------
8
- def build(gemspec)
9
- system "gem build %s" % gemspec
10
- FileUtils.mv Dir['watchr-*.gem'], 'pkg/'
11
- puts
12
- end
8
+ watch( gemspec ) { build }
13
9
 
14
10
  # --------------------------------------------------
15
- # Watchr Rules
11
+ # Signal Handling
16
12
  # --------------------------------------------------
17
- watch( '^watchr.gemspec$' ) { |m| build m[0] }
13
+ Signal.trap('QUIT') { build } # Ctrl-\
14
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
18
15
 
19
16
  # --------------------------------------------------
20
- # Signal Handling
17
+ # Helpers
21
18
  # --------------------------------------------------
22
- # Ctrl-\
23
- Signal.trap('QUIT') do
24
- puts " --- Building Gem ---\n\n"
25
- build 'watchr.gemspec'
19
+ def build
20
+ puts; system "gem build #{gemspec}"
21
+ FileUtils.mv( Dir['*.gem'], 'pkg/' )
26
22
  end
27
-
28
- # Ctrl-C
29
- Signal.trap('INT') { abort("\n") }
30
-
31
-
32
- # vim:ft=ruby
data/lib/watchr.rb CHANGED
@@ -5,15 +5,15 @@ require 'rbconfig'
5
5
  # user defined action whenever an observed file is modified. Its most typical
6
6
  # use is continuous testing.
7
7
  #
8
- # Usage:
8
+ # See README for more details
9
9
  #
10
- # # on command line, from project's root dir
11
- # $ watchr path/to/script
10
+ # @example
12
11
  #
13
- # See README for more details
12
+ # # on command line, from project's root dir
13
+ # $ watchr path/to/script
14
14
  #
15
15
  module Watchr
16
- VERSION = '0.5.9'
16
+ VERSION = '0.6'
17
17
 
18
18
  begin
19
19
  require 'rev'
@@ -35,7 +35,7 @@ module Watchr
35
35
  attr_accessor :options
36
36
  attr_accessor :handler
37
37
 
38
- # backwards compatibility
38
+ # @deprecated
39
39
  def version #:nodoc:
40
40
  Watchr::VERSION
41
41
  end
@@ -43,55 +43,59 @@ module Watchr
43
43
  # Options proxy.
44
44
  #
45
45
  # Currently supported options:
46
- # * debug<Boolean> Debugging state. More verbose.
47
46
  #
48
- # ===== Examples
47
+ # * debug[Boolean] Debugging state. More verbose.
48
+ #
49
+ # @example
49
50
  #
50
- # Watchr.options.debug #=> false
51
- # Watchr.options.debug = true
51
+ # Watchr.options.debug #=> false
52
+ # Watchr.options.debug = true
52
53
  #
53
- # ===== Returns
54
- # options<Struct>:: options proxy.
54
+ # @return [Struct]
55
+ # options proxy.
55
56
  #
56
- #--
57
- # On first use, initialize the options struct and default option values.
58
57
  def options
59
58
  @options ||= Struct.new(:debug).new
60
59
  @options.debug ||= false
61
60
  @options
62
61
  end
63
62
 
64
- # Outputs formatted debug statement to stdout, only if ::options.debug is true
63
+ # Outputs formatted debug statement to stdout, only if `::options.debug` is true
64
+ #
65
+ # @example
66
+ #
67
+ # Watchr.options.debug = true
68
+ # Watchr.debug('im in ur codes, notifayinin u')
65
69
  #
66
- # ===== Examples
70
+ # #outputs: "[watchr debug] im in ur codes, notifayinin u"
67
71
  #
68
- # Watchr.options.debug = true
69
- # Watchr.debug('im in ur codes, notifayinin u')
72
+ # @param [String] message
73
+ # debug message to print
70
74
  #
71
- # outputs: "[watchr debug] im in ur codes, notifayinin u"
75
+ # @return [nil]
72
76
  #
73
- def debug(str)
74
- puts "[watchr debug] #{str}" if options.debug
77
+ def debug(msg)
78
+ puts "[watchr debug] #{msg}" if options.debug
75
79
  end
76
80
 
77
81
  # Detect current OS and return appropriate handler.
78
82
  #
79
- # ===== Examples
83
+ # @example
80
84
  #
81
- # Config::CONFIG['host_os'] #=> 'linux-gnu'
82
- # Watchr.handler #=> Watchr::EventHandler::Unix
85
+ # Config::CONFIG['host_os'] #=> 'linux-gnu'
86
+ # Watchr.handler #=> Watchr::EventHandler::Unix
83
87
  #
84
- # Config::CONFIG['host_os'] #=> 'cygwin'
85
- # Watchr.handler #=> Watchr::EventHandler::Portable
88
+ # Config::CONFIG['host_os'] #=> 'cygwin'
89
+ # Watchr.handler #=> Watchr::EventHandler::Portable
86
90
  #
87
- # ENV['HANDLER'] #=> 'unix'
88
- # Watchr.handler #=> Watchr::EventHandler::Unix
91
+ # ENV['HANDLER'] #=> 'unix'
92
+ # Watchr.handler #=> Watchr::EventHandler::Unix
89
93
  #
90
- # ENV['HANDLER'] #=> 'portable'
91
- # Watchr.handler #=> Watchr::EventHandler::Portable
94
+ # ENV['HANDLER'] #=> 'portable'
95
+ # Watchr.handler #=> Watchr::EventHandler::Portable
92
96
  #
93
- # ===== Returns
94
- # handler<Class>:: handler class for current architecture
97
+ # @return [Class]
98
+ # handler class for current architecture
95
99
  #
96
100
  def handler
97
101
  @handler ||=