watchr 0.5.9 → 0.6

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/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 ||=