lather 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ === 1.4.0 / 2009-06-22
2
+
3
+ * Release as a Gem.
4
+ * Switch to MiniTest.
5
+ * Switch to new Hoe.
@@ -0,0 +1,11 @@
1
+ CHANGELOG.rdoc
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ bin/lather
6
+ lib/lather.rb
7
+ lib/lather/cli.rb
8
+ lib/lather/watcher.rb
9
+ lib/rake/lathertask.rb
10
+ test/test_cli.rb
11
+ test/test_watcher.rb
@@ -0,0 +1,117 @@
1
+ = Lather
2
+
3
+ * http://github.com/jbarnette/lather
4
+
5
+ == Description
6
+
7
+ Lather is an easy way to watch files and do something when they
8
+ change. By default, it checks for changes every second.
9
+
10
+ == Examples
11
+
12
+ === From the Command Line
13
+
14
+ The <tt>lather</tt> command-line tool lets you quickly track changes
15
+ to a set of files.
16
+
17
+ $ lather 'test/**/*_test.rb'
18
+
19
+ By default, <tt>lather</tt> will print a message each time a file
20
+ matching your spec changes. <tt>**</tt> is supported for recursive
21
+ globbing, but make sure to escape/quote the glob so your shell doesn't
22
+ expand it.
23
+
24
+ You can also run a command every time something changes:
25
+
26
+ $ lather -r 'rake test' '{lib,test}/**/*.rb'
27
+
28
+ === From Code
29
+
30
+ require "lather"
31
+
32
+ watcher = Lather::Watcher.new "**/*.rb" do |changed|
33
+ puts "Files changed: #{changed.join(' ')}"
34
+ end
35
+
36
+ watcher.go!
37
+
38
+ If you want to mess with the polling interval:
39
+
40
+ # :sleep is in seconds
41
+ Lather::Watcher.new "*.rb", :sleep => 5
42
+
43
+ === From a Rakefile
44
+
45
+ require "rake/lathertask"
46
+
47
+ Rake::LatherTask.new "lib/**/*.rb" do |l|
48
+ l.target = :something
49
+ l.globs << "ext/**/*.{c,h}"
50
+ end
51
+
52
+ This creates a <tt>lather</tt> task, which will call the
53
+ <tt>target</tt> task any time the <tt>globs</tt> change. The block is
54
+ optional: <tt>target</tt> defaults to <tt>:test</tt>.
55
+
56
+ If <tt>target</tt> is set to an *instance* of <tt>Rake::TestTask</tt>,
57
+ some special behavior is enabled: Lather will add the test task's file
58
+ list to <tt>globs</tt>, and will set the <tt>TEST</tt> environment
59
+ variable to the list of tests that need to be run.
60
+
61
+ require "rake/testtask"
62
+ require "rake/lathertask"
63
+
64
+ test = Rake::TestTask.new do |t|
65
+ t.libs << "test"
66
+ t.pattern = "test/**/*_test.rb"
67
+ end
68
+
69
+ Rake::LatherTask.new "lib/**/*.rb", :target => test
70
+
71
+ The heuristic is really simple: If <tt>lib/foo.rb</tt> changes, any
72
+ test whose path contains `foo` will be run. There's no tracking of
73
+ failures or single test runs. If you want more than this, you should
74
+ be using Autotest.
75
+
76
+ == Installation
77
+
78
+ $ gem install lather
79
+
80
+ == TODO
81
+
82
+ * A way to get at the list of changed files in a <tt>-r</tt> command.
83
+
84
+ * Some default exclude (like backup/editor files, <tt>.svn</tt>,
85
+ <tt>.git</tt>) patterns, and an easy way to add new ones.
86
+
87
+ * A <tt>--sleep <secs></tt> switch for the command-line tool.
88
+
89
+ == Thanks
90
+
91
+ Lather owes a huge debt to Ryan Davis' ZenTest library, specifically
92
+ <tt>autotest</tt>. Use it. See also Mike Clark and Geoffrey
93
+ Grosenbach's <tt>rstakeout</tt>, and a bunch of similar I've
94
+ forgotten.
95
+
96
+ == License
97
+
98
+ Copyright 2009 John Barnette (jbarnette@rubyforge.org)
99
+
100
+ Permission is hereby granted, free of charge, to any person obtaining
101
+ a copy of this software and associated documentation files (the
102
+ 'Software'), to deal in the Software without restriction, including
103
+ without limitation the rights to use, copy, modify, merge, publish,
104
+ distribute, sublicense, and/or sell copies of the Software, and to
105
+ permit persons to whom the Software is furnished to do so, subject to
106
+ the following conditions:
107
+
108
+ The above copyright notice and this permission notice shall be
109
+ included in all copies or substantial portions of the Software.
110
+
111
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
112
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
113
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
114
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
115
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
116
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
117
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,65 @@
1
+ require "rubygems"
2
+ require "hoe"
3
+
4
+ Hoe.spec "lather" do
5
+ developer "John Barnette", "jbarnette@rubyforge.org"
6
+
7
+ self.extra_rdoc_files = FileList["*.rdoc"]
8
+ self.history_file = "CHANGELOG.rdoc"
9
+ self.readme_file = "README.rdoc"
10
+ self.testlib = :minitest
11
+ end
12
+
13
+ # require "rubygems/specification"
14
+ # require "rake/testtask"
15
+
16
+ # require "./lib/lather"
17
+ # require "./lib/rake/lathertask"
18
+
19
+ # desc "Straighten up"
20
+ # task :clean do
21
+ # rm_rf "*.gem"
22
+ # end
23
+
24
+ # namespace :gem do
25
+ # LATHER = Gem::Specification.new do |s|
26
+ # s.name = "lather"
27
+ # s.version = Lather::VERSION
28
+ # s.platform = Gem::Platform::RUBY
29
+ # s.has_rdoc = false
30
+ # s.summary = "Lather rinses and repeats."
31
+ # s.description = s.summary
32
+ # s.author = "John Barnette"
33
+ # s.email = "jbarnette@gmail.com"
34
+ # s.homepage = "http://github.com/jbarnette/lather"
35
+ # s.require_path = "lib"
36
+ # s.bindir = "bin"
37
+ # s.executables = %w(lather)
38
+
39
+ # s.files = %w(Rakefile README.markdown) + Dir["{bin,lib,test}/**/*"]
40
+ # end
41
+
42
+ # gemspec = file "#{LATHER.name}.gemspec" => LATHER.files do |file|
43
+ # File.open(file.name, "w") do |f|
44
+ # f.puts LATHER.to_ruby
45
+ # end
46
+ # end
47
+
48
+ # gemfile = file "#{LATHER.name}-#{LATHER.version}.gem" => gemspec do |file|
49
+ # sh "gem build #{file.prerequisites.first}"
50
+ # end
51
+
52
+ # desc "Build and install the gem"
53
+ # task :install => [gemfile, :clean] do
54
+ # sh "sudo gem install #{LATHER.name}-#{LATHER.version}.gem"
55
+ # end
56
+ # end
57
+
58
+ # test = Rake::TestTask.new do |t|
59
+ # t.libs << "test"
60
+ # t.ruby_opts << "-rhelper"
61
+ # t.pattern = "test/**/*_test.rb"
62
+ # end
63
+
64
+ # task :default => :test
65
+ # Rake::LatherTask.new "lib/**/*.rb", :target => test
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require "lather/cli"
4
+
5
+ trap("INT") { puts; exit 1 }
6
+ Lather::Cli.new.go! ARGV
@@ -0,0 +1,5 @@
1
+ require "lather/watcher"
2
+
3
+ module Lather
4
+ VERSION = "1.4.0"
5
+ end
@@ -0,0 +1,69 @@
1
+ require "optparse"
2
+
3
+ require "lather"
4
+
5
+ module Lather
6
+ class Cli
7
+ def initialize
8
+ @command = nil
9
+ @globs = []
10
+ @verbose = false
11
+
12
+ @options = OptionParser.new do |o|
13
+ o.banner = "#$0 [-hVv] [-r <cmd>] <globs...>"
14
+ o.separator ""
15
+
16
+ o.on "--help", "-h", "-?", "Shows help." do
17
+ exit help!
18
+ end
19
+
20
+ o.on "--verbose", "-v", "Talks your ear off." do
21
+ @verbose = true
22
+ end
23
+
24
+ o.on "--version", "-V", "Prints #{Lather::VERSION}." do
25
+ puts Lather::VERSION
26
+ exit
27
+ end
28
+
29
+ o.on "--rinse [cmd]", "--run", "-r", "Runs when things change." do |cmd|
30
+ @command = cmd
31
+ end
32
+
33
+ o.separator ""
34
+ end
35
+ end
36
+
37
+ def parse! args
38
+ @options.parse! args
39
+ @globs.concat args
40
+ exit help! if @globs.empty?
41
+ end
42
+
43
+ def go! args
44
+ parse! args
45
+
46
+ watcher = Lather::Watcher.new @globs do |files|
47
+ if @command
48
+ system @command
49
+ else
50
+ puts "Changed: #{files.join(" ")}"
51
+ end
52
+ end
53
+
54
+ verbose "Watching: #{watcher.files.keys.sort.join(" ")}"
55
+ watcher.go!
56
+ end
57
+
58
+ private
59
+
60
+ def verbose *args
61
+ puts args.join(" ") if @verbose
62
+ end
63
+
64
+ def help!
65
+ puts @options
66
+ 1 # process exit code
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ module Lather
2
+ class Watcher
3
+ attr_reader :files
4
+ attr_reader :options
5
+
6
+ def initialize *globs, &callback
7
+ raise ArgumentError, "need a callback" unless block_given?
8
+ @callback = callback
9
+
10
+ @options = { :force => false, :sleep => 1 }
11
+ @options.merge!(globs.pop) if globs.last.is_a? Hash
12
+
13
+ @globs = globs.flatten
14
+ @files = find_files
15
+ end
16
+
17
+ def go!
18
+ @timestamp = Time.now
19
+
20
+ @callback[@files.keys] if @options[:force]
21
+
22
+ loop do
23
+ unless (changed = update_files_and_timestamp).empty?
24
+ @callback[changed]
25
+ end
26
+
27
+ Kernel.sleep @options[:sleep]
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def update_files_and_timestamp
34
+ @files = find_files
35
+ updated = @files.keys.select { |k| @files[k] > @timestamp }
36
+ @timestamp = @files.values.max
37
+
38
+ updated
39
+ end
40
+
41
+ def find_files
42
+ files = {}
43
+
44
+ @globs.collect { |g| Dir[g] }.flatten.each do |file|
45
+ # silently skip stat failures: file deleted, etc.
46
+ files[file] = File.stat(file).mtime rescue next
47
+ end
48
+
49
+ files
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,103 @@
1
+ require "rake"
2
+ require "rake/tasklib"
3
+ require "lather/watcher"
4
+
5
+ module Rake
6
+
7
+ # Runs the <tt>target</tt> task any time a file matching one of the
8
+ # <tt>globs</tt> changes.
9
+
10
+ class LatherTask < TaskLib
11
+
12
+ # An array of globs to watch.
13
+
14
+ attr_accessor :globs
15
+
16
+ # A hash of options, most of which are passed on to
17
+ # <tt>Lather::Watcher</tt>.
18
+
19
+ attr_accessor :options
20
+
21
+ # The task to run when things change. Default is
22
+ # <tt>:test</tt>. If this is an instance of
23
+ # <tt>Rake::TestTask</tt>, the task's <tt>file_list</tt> will be
24
+ # added to <tt>globs</tt>, and the <tt>TEST</tt> environment
25
+ # variable will be set to a glob of changed tests before each
26
+ # invocation.
27
+
28
+ attr_accessor :target
29
+
30
+ def initialize *globs, &block
31
+ @options = Hash === globs.last ? globs.pop : {}
32
+ @globs = globs
33
+ @target = @options.delete(:target) || :test
34
+
35
+ @changed = case @target
36
+ when Rake::TestTask then handle_rake_test_task
37
+ else lambda {}
38
+ end
39
+
40
+ yield self if block_given?
41
+
42
+ @target = Rake::Task[@target]
43
+
44
+ desc "Rinse and repeat"
45
+ task :lather do
46
+ watcher = Lather::Watcher.new @globs, @options do |changed|
47
+ begin
48
+ @changed[changed]
49
+ @target.invoke
50
+ rescue StandardError => e
51
+ raise e unless e.to_s =~ /^Command failed/
52
+ ensure
53
+ reenable @target
54
+ end
55
+ end
56
+
57
+ watcher.go!
58
+ end
59
+ end
60
+
61
+ # Get and set the block called each time a file matching one of
62
+ # the <tt>globs</tt> changes. Default is <tt>lambda {}</tt>.
63
+
64
+ def changed &block
65
+ return @changed unless block_given?
66
+ @changed = block
67
+ end
68
+
69
+ private
70
+
71
+ def reenable target
72
+ target.reenable
73
+ target.prerequisites.each { |p| reenable Rake::Task[p] }
74
+ end
75
+
76
+ # Special setup when <tt>target</tt> is a <tt>Rake::TestTask</tt>.
77
+
78
+ def handle_rake_test_task
79
+ test_task = @target
80
+ all_tests = test_task.file_list
81
+
82
+ @target = test_task.name
83
+ @globs << test_task.file_list
84
+ @options[:force] = true
85
+
86
+ lambda do |changed|
87
+ tests = all_tests & changed
88
+
89
+ basenames = (changed - tests).collect do |f|
90
+ File.basename(f).split(".").first
91
+ end
92
+
93
+ tests.concat all_tests.
94
+ select { |t| basenames.any? { |b| t =~ /#{b}/ } }
95
+
96
+ tests = all_tests.dup if tests.empty?
97
+
98
+ # Nice API, Rake::TestTask.
99
+ ENV["TEST"] = "{#{tests.uniq.join(',')}}"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,29 @@
1
+ require "minitest/autorun"
2
+ require "lather/cli"
3
+
4
+ module Lather
5
+ class CliTest < MiniTest::Unit::TestCase
6
+ def setup
7
+ @cli = Lather::Cli.new
8
+ def @cli.exit *args; throw :exit end
9
+ end
10
+
11
+ def parse! *args
12
+ capture_io do
13
+ catch(:exit) { @cli.parse! args }
14
+ end
15
+ end
16
+
17
+ def test_empty_invocation_prints_help
18
+ out, err = parse!
19
+ assert_match(/Shows help/, out)
20
+ end
21
+
22
+ def test_V_option_prints_version
23
+ %w(-V --version).each do |flag|
24
+ out, err = parse! flag
25
+ assert_equal Lather::VERSION, out.chomp
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ require "minitest/autorun"
2
+ require "lather/watcher"
3
+
4
+ module Lather
5
+ class WatcherTest < MiniTest::Unit::TestCase
6
+ def test_initialize_complains_without_a_callback
7
+ assert_raises ArgumentError do
8
+ Lather::Watcher.new
9
+ end
10
+ end
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lather
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.4.0
5
+ platform: ruby
6
+ authors:
7
+ - John Barnette
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.2.0
24
+ version:
25
+ description: |-
26
+ Lather is an easy way to watch files and do something when they
27
+ change. By default, it checks for changes every second.
28
+ email:
29
+ - jbarnette@rubyforge.org
30
+ executables:
31
+ - lather
32
+ extensions: []
33
+
34
+ extra_rdoc_files:
35
+ - Manifest.txt
36
+ - CHANGELOG.rdoc
37
+ - README.rdoc
38
+ files:
39
+ - CHANGELOG.rdoc
40
+ - Manifest.txt
41
+ - README.rdoc
42
+ - Rakefile
43
+ - bin/lather
44
+ - lib/lather.rb
45
+ - lib/lather/cli.rb
46
+ - lib/lather/watcher.rb
47
+ - lib/rake/lathertask.rb
48
+ - test/test_cli.rb
49
+ - test/test_watcher.rb
50
+ has_rdoc: true
51
+ homepage: http://github.com/jbarnette/lather
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --main
57
+ - README.rdoc
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project: lather
75
+ rubygems_version: 1.3.4
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Lather is an easy way to watch files and do something when they change
79
+ test_files:
80
+ - test/test_cli.rb
81
+ - test/test_watcher.rb