observr 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OGYwNDY2YjY5OWRmYjBiYjFhMDM2ZmYxYTYyZWFiYTVmODY2MWQ1Yg==
5
+ data.tar.gz: !binary |-
6
+ ZTUzMzdkYzM0NDBjZTAwOTA3ZTkzYmYwNGEwMDU5MjM3NWQ5ODViYw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZjViMjA2YmVjMGE5OWRiZjY1ZWMzOTYxNzc0NWYyZmQxZTgxNTNmYjFmYThj
10
+ YWMyOTRjYzJlYzM5ODc1M2NlZjE5ODM3YjE2M2Y3NTIyMjRkMGJjNThkYTkw
11
+ NDY2OTZiMTIzYTI4NjRiNGJmMWM5ZTdlMmViNTg5ZDBiMjhhYmE=
12
+ data.tar.gz: !binary |-
13
+ NmExZGIzMjRmMjk5MDdjOWUwOTk0ODZlYzhkMjFmZjZiOTY0NWIxOGY4NGNj
14
+ YzgzMzE4MmNlYTM4NzY2NGIzMmNmNzIxNmE1MmM2NTIxZTA0OTcxZGRiZjU0
15
+ NjRiYTIzZWQwNGQzYjhlZGMxMWRmM2Y5ZGNhN2IyYzc0NGY3ZjU=
@@ -0,0 +1,6 @@
1
+ doc/
2
+ pkg/
3
+ bk/
4
+ .wiki
5
+ .yardoc
6
+ *.gem
@@ -0,0 +1,32 @@
1
+
2
+ === v0.5.7
3
+
4
+ * Added manifest.watchr script
5
+ * Unix handler supports :deleted event type
6
+ * Unix handler supports :accessed (atime), :modified (mtime) and :changed
7
+ (ctime) event types (thanks gzuki[http://github.com/gzuki] for initial work)
8
+
9
+
10
+ === v0.5.6
11
+
12
+ * Rev gem optional in development (thanks TwP[http://github.com/TwP])
13
+ * Allow gems to bundle .watchr scripts (thanks foca[http://github.com/foca])
14
+
15
+ gemname/lib/gemname.watchr
16
+
17
+ is now automatically picked up with
18
+
19
+ $ watchr gemname.watchr
20
+
21
+ * Look for script in path
22
+ * debug msg when rev not found on *nix
23
+ * rake task for cross interpreter testing
24
+
25
+
26
+ === v0.5.5
27
+
28
+ * Rev gem is optional. Fixes issue #1
29
+ Install Rev to automatically get evented handler on *nix
30
+
31
+ gem install rev
32
+
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright © 2013 Martin Aumont (mynyml)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,119 @@
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
+ observr 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
+ $ observr 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 observr 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_observr.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 observr) so experimenting is painless.
70
+
71
+ The [wiki][5] has more details and examples. You might also want to take a
72
+ look at observr's own scripts, [specs.observr][1], [docs.observr][2] and
73
+ [gem.observr][3], to get you started.
74
+
75
+ Install
76
+ -------
77
+
78
+ gem install observr
79
+
80
+ If you're on Linux/BSD and have the [rev][4] gem installed, Observr will detect
81
+ it and use it automatically. This will make Observr evented.
82
+
83
+ gem install rev
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
+
90
+ See Also
91
+ --------
92
+
93
+ * [redgreen][6]: Standalone redgreen eye candy for test results, ala autotest.
94
+ * [phocus][7]: Run focused tests when running the whole file/suite is unnecessary.
95
+ * [autoobservr][8]: Provides some autotest-like behavior for observr
96
+ * [nestor][9]: Continuous testing server for Rails
97
+
98
+ Links
99
+ -----
100
+
101
+ * code: <http://github.com/kevinburke/observr>
102
+ * docs: <http://yardoc.org/docs/mynyml-observr/file:README.rdoc>
103
+ * wiki: <http://wiki.github.com/mynyml/observr>
104
+ * bugs: <http://github.com/kevinburke/observr/issues>
105
+
106
+
107
+
108
+
109
+ [1]: http://github.com/kevinburke/observr/blob/master/specs.observr
110
+ [2]: http://github.com/kevinburke/observr/blob/master/docs.observr
111
+ [3]: http://github.com/kevinburke/observr/blob/master/gem.observr
112
+ [4]: http://github.com/tarcieri/rev/
113
+ [5]: http://wiki.github.com/mynyml/observr
114
+ [6]: http://github.com/mynyml/redgreen
115
+ [7]: http://github.com/mynyml/phocus
116
+ [8]: http://github.com/viking/autoobservr
117
+ [9]: http://github.com/francois/nestor
118
+ [10]: http://github.com/sandro/ruby-fsevent
119
+
@@ -0,0 +1,34 @@
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
+
10
+ # --------------------------------------------------
11
+ # Tests
12
+ # --------------------------------------------------
13
+ task(:default => "test:all")
14
+
15
+ namespace(:test) do
16
+
17
+ desc "Run all tests"
18
+ task(:all) do
19
+ tests = Dir['test/**/test_*.rb'] - ['test/test_helper.rb']
20
+ exit system(%Q{#{ruby} #{gem_opt} -I.:lib -e"%w( #{tests.join(' ')} ).each {|file| require file }"})
21
+ end
22
+
23
+ desc "Run all tests on multiple ruby versions (requires rvm)"
24
+ task(:portability) do
25
+ %w( 1.8.6 1.8.7 1.9.1 1.9.2 ).each do |version|
26
+ system <<-BASH
27
+ bash -c 'source ~/.rvm/scripts/rvm;
28
+ rvm #{version};
29
+ echo "--------- v#{version} ----------\n";
30
+ rake -s test:all'
31
+ BASH
32
+ end
33
+ end
34
+ end
data/TODO.md ADDED
@@ -0,0 +1,31 @@
1
+ Features
2
+ --------
3
+
4
+ * observr -e ( `$ observr -e "watch('foo.gemspec') { system('gem build foo.gemspec') }"` )
5
+ * observr --auto
6
+ * observr --fetch
7
+
8
+ * enable ability to watch dirs
9
+ * requires new handler(s)
10
+ * will allow recognizing `:added` events
11
+
12
+ * allow setting latency
13
+
14
+ Bugs
15
+ ----
16
+
17
+ * sometimes an action is fired without a file being saved
18
+ * buffer flushing issue?
19
+ * libev issue?
20
+ * probably fixed with event type handling update, which ignores atime
21
+ updates by defaults
22
+
23
+ * when a file is saved twice quickly, subsequent events are ignored.
24
+ * seems like rev/libev drops the file watch
25
+
26
+ Other
27
+ -----
28
+
29
+ * add tests for executable
30
+ * memory profiling / benchmarks
31
+
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+ require 'optparse'
5
+ require 'tempfile'
6
+
7
+ require File.dirname(__FILE__) + '/../lib/observr'
8
+
9
+ module Observr
10
+ # Namespaced to avoid defining global methods
11
+ #
12
+ # @private
13
+ module Bin
14
+ extend self
15
+
16
+ DEFAULT_SCRIPT_PATH = Pathname.new('specs.observr')
17
+
18
+ attr_accessor :path
19
+
20
+ def usage
21
+ "Usage: observr [opts] path/to/script"
22
+ end
23
+
24
+ def version
25
+ "observr version: %s" % Observr::VERSION
26
+ end
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
+
43
+ # Find a partial path name in load path
44
+ #
45
+ # @param [Pathname] path
46
+ # partial pathname
47
+ #
48
+ # @return [Pathname]
49
+ # absolute path of first occurence of partial path in load path, or nil if not found
50
+ #
51
+ def find_in_load_path(path)
52
+ # Adds '.' for ruby1.9.2
53
+ dir = (['.'] + $LOAD_PATH).uniq.detect {|p| Pathname(p).join(path).exist? }
54
+ dir ? path.expand_path(dir) : nil
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
63
+ end
64
+ end
65
+
66
+ opts = OptionParser.new do |opts|
67
+ opts.banner = Observr::Bin.usage
68
+
69
+ opts.on('-d', '--debug', "Print extra debug info while program runs") {
70
+ Observr.options.debug = true
71
+ begin
72
+ require 'ruby-debug'
73
+ rescue LoadError, RuntimeError
74
+ end
75
+ }
76
+ opts.on('-l', '--list', "Display list of files monitored by script and exit") {
77
+ script = Observr::Script.new(Observr::Bin.path!)
78
+ controller = Observr::Controller.new(script, Observr.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 ($ observr -e "watch('foo') { puts 'bar' }")|) {|code|
92
+ assert_syntax(code)
93
+
94
+ Tempfile.open('foo') {|f| f << code; @__path = f.path }
95
+ Observr::Bin.path = Pathname(@__path)
96
+ }
97
+
98
+ opts.on_tail('-h', '--help', "Print inline help") { puts opts; exit }
99
+ opts.on_tail('-v', '--version', "Print version" ) { puts Observr::Bin.version; exit }
100
+
101
+ opts.parse! ARGV
102
+ end
103
+
104
+ Observr::Controller.new(Observr::Script.new(Observr::Bin.path!), Observr.handler.new).run
105
+
@@ -0,0 +1,7 @@
1
+
2
+ Suggestions:
3
+ macournoyer, foca
4
+
5
+ Patches:
6
+ TwP, gzuki, spraints, francois
7
+
@@ -0,0 +1,26 @@
1
+ # Run me with:
2
+ # $ observr docs.observr
3
+
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 }
12
+
13
+ # --------------------------------------------------
14
+ # Signal Handling
15
+ # --------------------------------------------------
16
+ Signal.trap('QUIT') { yard } # Ctrl-\
17
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
18
+
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"
26
+ end
@@ -0,0 +1,22 @@
1
+ # Run me with:
2
+ # $ observr gem.observr
3
+
4
+ def gemspec() Dir['*.gemspec'].first end
5
+ # --------------------------------------------------
6
+ # Rules
7
+ # --------------------------------------------------
8
+ watch( gemspec ) { build }
9
+
10
+ # --------------------------------------------------
11
+ # Signal Handling
12
+ # --------------------------------------------------
13
+ Signal.trap('QUIT') { build } # Ctrl-\
14
+ Signal.trap('INT' ) { abort("\n") } # Ctrl-C
15
+
16
+ # --------------------------------------------------
17
+ # Helpers
18
+ # --------------------------------------------------
19
+ def build
20
+ puts; system "gem build #{gemspec}"
21
+ FileUtils.mv( Dir['*.gem'], 'pkg/' )
22
+ end
@@ -0,0 +1,133 @@
1
+ require 'pathname'
2
+ require 'rbconfig'
3
+
4
+ # Agile development tool that monitors a directory recursively, and triggers a
5
+ # user defined action whenever an observed file is modified. Its most typical
6
+ # use is continuous testing.
7
+ #
8
+ # See README for more details
9
+ #
10
+ # @example
11
+ #
12
+ # # on command line, from project's root dir
13
+ # $ observr path/to/script
14
+ #
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ module Observr
17
+ VERSION = '1.0'
18
+
19
+ begin
20
+ #require 'fsevent'
21
+ #HAVE_FSE = true
22
+ #rescue LoadError, RuntimeError
23
+ HAVE_FSE = false
24
+ end
25
+
26
+ begin
27
+ require 'rev'
28
+ HAVE_REV = true
29
+ rescue LoadError, RuntimeError
30
+ HAVE_REV = false
31
+ end
32
+
33
+ autoload :Script, 'observr/script'
34
+ autoload :Controller, 'observr/controller'
35
+
36
+ module EventHandler
37
+ autoload :Base, 'observr/event_handlers/base'
38
+ autoload :Portable, 'observr/event_handlers/portable'
39
+ autoload :Unix, 'observr/event_handlers/unix' if ::Observr::HAVE_REV
40
+ autoload :Darwin, 'observr/event_handlers/darwin' if ::Observr::HAVE_FSE
41
+ end
42
+
43
+ class << self
44
+ attr_accessor :options
45
+ attr_accessor :handler
46
+
47
+ # @deprecated
48
+ def version #:nodoc:
49
+ Observr::VERSION
50
+ end
51
+
52
+ # Options proxy.
53
+ #
54
+ # Currently supported options:
55
+ #
56
+ # * debug[Boolean] Debugging state. More verbose.
57
+ #
58
+ # @example
59
+ #
60
+ # Observr.options.debug #=> false
61
+ # Observr.options.debug = true
62
+ #
63
+ # @return [Struct]
64
+ # options proxy.
65
+ #
66
+ def options
67
+ @options ||= Struct.new(:debug).new
68
+ @options.debug ||= false
69
+ @options
70
+ end
71
+
72
+ # Outputs formatted debug statement to stdout, only if `::options.debug` is true
73
+ #
74
+ # @example
75
+ #
76
+ # Observr.options.debug = true
77
+ # Observr.debug('im in ur codes, notifayinin u')
78
+ #
79
+ # #outputs: "[observr debug] im in ur codes, notifayinin u"
80
+ #
81
+ # @param [String] message
82
+ # debug message to print
83
+ #
84
+ # @return [nil]
85
+ #
86
+ def debug(msg)
87
+ puts "[observr debug] #{msg}" if options.debug
88
+ end
89
+
90
+ # Detect current OS and return appropriate handler.
91
+ #
92
+ # @example
93
+ #
94
+ # Config::CONFIG['host_os'] #=> 'linux-gnu'
95
+ # Observr.handler #=> Observr::EventHandler::Unix
96
+ #
97
+ # Config::CONFIG['host_os'] #=> 'cygwin'
98
+ # Observr.handler #=> Observr::EventHandler::Portable
99
+ #
100
+ # ENV['HANDLER'] #=> 'unix'
101
+ # Observr.handler #=> Observr::EventHandler::Unix
102
+ #
103
+ # ENV['HANDLER'] #=> 'portable'
104
+ # Observr.handler #=> Observr::EventHandler::Portable
105
+ #
106
+ # @return [Class]
107
+ # handler class for current architecture
108
+ #
109
+ def handler
110
+ @handler ||=
111
+ case ENV['HANDLER'] || Config::CONFIG['host_os']
112
+ when /darwin|mach|osx|fsevents?/i
113
+ if Observr::HAVE_FSE
114
+ Observr::EventHandler::Darwin
115
+ else
116
+ Observr.debug "fsevent not found. `gem install ruby-fsevent` to get evented handler"
117
+ Observr::EventHandler::Portable
118
+ end
119
+ when /sunos|solaris|bsd|linux|unix/i
120
+ if Observr::HAVE_REV
121
+ Observr::EventHandler::Unix
122
+ else
123
+ Observr.debug "rev not found. `gem install rev` to get evented handler"
124
+ Observr::EventHandler::Portable
125
+ end
126
+ when /mswin|windows|cygwin/i
127
+ Observr::EventHandler::Portable
128
+ else
129
+ Observr::EventHandler::Portable
130
+ end
131
+ end
132
+ end
133
+ end