lather 1.4.0

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.
@@ -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