watchful 0.0.0.pre1 → 0.0.1.1
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/.autotest +7 -0
- data/.gitignore +3 -0
- data/README.md +44 -35
- data/Rakefile +17 -19
- data/VERSION +1 -1
- data/bin/watchful +28 -26
- data/lib/watchful.rb +12 -0
- data/lib/watchful/action.rb +16 -8
- data/lib/watchful/configuration.rb +8 -8
- data/lib/watchful/defaultconfiguration.rb +5 -5
- data/lib/watchful/paths.rb +1 -0
- data/lib/watchful/watch.rb +70 -28
- data/test/unit/action_test.rb +68 -0
- data/test/unit/configuration_test.rb +39 -0
- data/test/unit/paths_test.rb +48 -0
- data/test/unit/watch_test.rb +81 -0
- metadata +31 -42
- data/doc/DSL-Specification.rb +0 -51
- data/test/action_test.rb +0 -159
- data/test/configuration_test.rb +0 -80
- data/test/customconfiguration_test.rb +0 -20
- data/test/paths_test.rb +0 -63
- data/test/test_helper.rb +0 -13
- data/watchful.gemspec +0 -78
data/.autotest
ADDED
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -6,60 +6,69 @@ A shell script for busy web developers
|
|
6
6
|
What?
|
7
7
|
-----
|
8
8
|
|
9
|
-
Watchful is a lightweight tool that runs command line tools on updated files. It was built by a web developer who got seriously tired of managing a whole range of CLI minification, translation, and compression tools on his CSS
|
9
|
+
Watchful is a lightweight tool that runs command line tools on updated files. It was built by a web developer who got seriously tired of managing a whole range of CLI minification, translation, and compression tools on his CSS, Javascript, PNGs, etc.
|
10
10
|
|
11
|
-
You can think of Watchful as kind of recursive,
|
11
|
+
You can think of Watchful as kind of recursive, constantly-running [Rake](http://rake.rubyforge.org/): you tell it which tools to run on which files, then fire it off in your current project directory and go back to your text editor. When you save a change to a relevant file under that directory, Watchful will run the proper tool on it. If you have [Growl](http://growl.info/) installed, you’ll get a notification. If you’re on OS X Leopard and have [the FSEvents gem](http://rubygems.org/gems/fsevents) installed, you’ll get a rather nice performance to boot.
|
12
12
|
|
13
13
|
Where?
|
14
14
|
------
|
15
15
|
|
16
|
-
Watchful is
|
16
|
+
Watchful is available as a Gem:
|
17
|
+
|
18
|
+
sudo gem install watchful
|
19
|
+
|
20
|
+
The development git repo is currently hosted on [GitHub](http://github.com):
|
17
21
|
|
18
22
|
[http://github.com/kemitchell/watchful](http://github.com/kemitchell/watchful)
|
19
23
|
|
20
24
|
Please feel free to fork me!
|
21
|
-
|
22
|
-
Eventually, Watchful will be available as a Ruby Gem:
|
23
|
-
|
24
|
-
sudo gem install watchful
|
25
25
|
|
26
|
+
To install the latest from GitHub:
|
27
|
+
|
28
|
+
cd /tmp
|
29
|
+
git clone git://github.com/kemitchell/watchful.git
|
30
|
+
cd watchful
|
31
|
+
rake build
|
32
|
+
sudo rake install
|
33
|
+
|
26
34
|
How?
|
27
35
|
----
|
28
36
|
|
29
|
-
All configuration is done in pure Ruby. Configurations are created by subclassing `Watchful::Configuration` in
|
37
|
+
All configuration is done in pure Ruby. Configurations are created by subclassing `Watchful::Configuration` in `watchful` files. Configurations contain `action` lines which describe CLI commands, the extension of the files they should be run on, and the extension that should be used for the resulting output. An example follows:
|
30
38
|
|
39
|
+
require 'rubygems'
|
31
40
|
require 'watchful/configuration'
|
32
|
-
|
41
|
+
|
33
42
|
class MyConfiguration < Watchful::Configuration
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
43
|
+
|
44
|
+
description 'LESS CSS and YUI Compressor'
|
45
|
+
|
46
|
+
# actions are applied in order, hence Less is defined before YUI
|
47
|
+
|
48
|
+
action :name => "Less CSS", # Used for command line and Growl notifications
|
49
|
+
:in => ".less", # The extension of files to use as input
|
50
|
+
:out => ".css", # Extension to replace the above for output files
|
51
|
+
:command => "lessc %s %s", # The command to create output files from input files
|
52
|
+
# In the future all of the above will also take blocks.
|
53
|
+
# Currently the command is built using sprintf.
|
54
|
+
# The first %s is the full input path.
|
55
|
+
# The second %s is the full output path.
|
56
|
+
:dependencies => ['less'] # If “less” isn’t found in PATH, this action will be disabled.
|
57
|
+
|
58
|
+
action :name => 'YUI Compressor',
|
59
|
+
:in => '.css',
|
60
|
+
:out => '.min.css', # Notice that Watchful computes extensions differently than basename
|
61
|
+
# Namely, the extension is anything in the file name from the
|
62
|
+
# first period onward, hence this.big.ext.name => '.big.ext.name'
|
63
|
+
:command => 'java -jar /usr/local/utils/yuicompressor-2.4.2.jar --type css --charset utf-8 %s -o %s',
|
64
|
+
:dependencies => ['java', '/usr/local/utils/yuicompressor-2.4.2.jar']
|
65
|
+
# Dependencies can be programs (e.g. “java”), or full file paths.
|
66
|
+
|
58
67
|
end
|
59
68
|
|
60
|
-
When Watchful is started, it searches in the following locations (in the following order) for files called
|
69
|
+
When Watchful is started, it searches in the following locations (in the following order) for files called `watchful` and loads them:
|
61
70
|
|
62
71
|
1. In the directory Watchful is told to monitor
|
63
72
|
2. In the current user’s home directory
|
64
73
|
|
65
|
-
If no such files are found, Watchful will use the default configuration, which searches your PATH for tools it recognizes. If your tool isn't listed in [http://github.com/kemitchell/watchful/blob/master/lib/watchful/defaultconfiguration.rb](defaultconfiguration.rb) and you would like it to be, please fork the project
|
74
|
+
If no such files are found, Watchful will use the default configuration, which searches your PATH for tools it recognizes. If your tool isn't listed in [http://github.com/kemitchell/watchful/blob/master/lib/watchful/defaultconfiguration.rb](defaultconfiguration.rb) and you would like it to be, please fork the project or send me a patch. I would be happy to include any web development tools with current stable or Beta releases.
|
data/Rakefile
CHANGED
@@ -9,38 +9,36 @@ begin
|
|
9
9
|
gem.description = 'Applies intermediary tools to modified files'
|
10
10
|
gem.email = "kyleevanmitchell@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/kemitchell/watchful"
|
12
|
-
gem.authors = ["
|
13
|
-
gem.
|
14
|
-
gem.add_dependency('
|
15
|
-
gem.add_dependency('
|
16
|
-
gem.add_dependency('open4')
|
12
|
+
gem.authors = ["K E Mitchell"]
|
13
|
+
gem.add_dependency('commandline', '>= 0.7.10')
|
14
|
+
gem.add_dependency('extensions', '>= 0.6.0')
|
15
|
+
gem.add_dependency('open4', '>= 1.0.1')
|
17
16
|
gem.rubyforge_project = 'watchful'
|
18
17
|
end
|
19
18
|
Jeweler::RubyforgeTasks.new do |rubyforge|
|
20
|
-
rubyforge.doc_task = '
|
19
|
+
rubyforge.doc_task = 'rdoc'
|
21
20
|
end
|
22
21
|
rescue LoadError
|
23
22
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
23
|
end
|
25
24
|
|
26
|
-
Jeweler::RubyforgeTasks.new do |rf|
|
27
|
-
rf.doc_task = 'rdoc'
|
28
|
-
end
|
29
|
-
|
30
25
|
require 'rake/testtask'
|
31
26
|
|
27
|
+
TEST_FILE_PATTERN = 'test/unit/*_test.rb'
|
28
|
+
|
32
29
|
Rake::TestTask.new(:test) do |test|
|
33
30
|
test.libs << 'lib' << 'test'
|
34
|
-
test.pattern =
|
31
|
+
test.pattern = TEST_FILE_PATTERN
|
35
32
|
test.verbose = true
|
36
33
|
end
|
37
34
|
|
38
35
|
begin
|
39
36
|
require 'rcov/rcovtask'
|
40
|
-
Rcov::RcovTask.new do |
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
Rcov::RcovTask.new do |t|
|
38
|
+
t.libs << 'lib' << 'test'
|
39
|
+
t.test_files = FileList[TEST_FILE_PATTERN]
|
40
|
+
t.verbose = true
|
41
|
+
t.rcov_opts << '--exclude gems'
|
44
42
|
end
|
45
43
|
rescue LoadError
|
46
44
|
task :rcov do
|
@@ -48,10 +46,6 @@ rescue LoadError
|
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
|
-
task :test => :check_dependencies
|
52
|
-
|
53
|
-
task :default => [:test, :build]
|
54
|
-
|
55
49
|
require 'rake/rdoctask'
|
56
50
|
|
57
51
|
Rake::RDocTask.new do |rdoc|
|
@@ -66,3 +60,7 @@ Rake::RDocTask.new do |rdoc|
|
|
66
60
|
rdoc.rdoc_files.include('README*')
|
67
61
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
68
62
|
end
|
63
|
+
|
64
|
+
task :test => :check_dependencies
|
65
|
+
|
66
|
+
task :default => :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1.1
|
data/bin/watchful
CHANGED
@@ -6,19 +6,8 @@ require 'rubygems'
|
|
6
6
|
require 'commandline'
|
7
7
|
require 'watchful'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
rescue LoadError
|
12
|
-
HAVE_GROWL = false
|
13
|
-
else
|
14
|
-
if (Growl.installed? rescue false)
|
15
|
-
HAVE_GROWL = true
|
16
|
-
else
|
17
|
-
HAVE_GROWL = false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class App < CommandLine::Application
|
9
|
+
class App < CommandLine::Application_wo_AutoRun
|
10
|
+
|
22
11
|
def initialize
|
23
12
|
version Watchful::version
|
24
13
|
author 'KEM'
|
@@ -28,33 +17,46 @@ class App < CommandLine::Application
|
|
28
17
|
A configurable deamon for running source code translation and minification tools–
|
29
18
|
such as CSS and Javascript minification tools and generators—on updated files.
|
30
19
|
eos
|
31
|
-
synopsis "[-dhv] path"
|
20
|
+
synopsis "[-dhv] [--default] [--poll] path"
|
32
21
|
option :help
|
33
22
|
option :debug
|
34
23
|
option :version
|
35
|
-
option
|
36
|
-
|
37
|
-
|
24
|
+
option :flag,
|
25
|
+
:names => %w{--use-default-configuration --default -D},
|
26
|
+
:opt_description => 'Override custom configurations.'
|
27
|
+
option :flag,
|
28
|
+
:names => %w{--force-polling --poll -P},
|
29
|
+
:opt_description => 'Use stat() polling, even if filesystem events are supported.'
|
38
30
|
expected_args :path
|
39
31
|
end
|
32
|
+
|
40
33
|
def main
|
41
|
-
Watchful::Configuration.active_configuration = Watchful::DefaultConfiguration
|
42
|
-
# todo: check dependencies of actions of active configuration
|
43
|
-
|
44
34
|
path = File.expand_path(args[0])
|
45
|
-
fail "No such directory: #{path} " unless File.directory? path
|
35
|
+
fail "? No such directory: #{path} " unless File.directory? path
|
46
36
|
|
47
37
|
Watchful::load_configuration(path, opt['--use-default-configuration'])
|
48
38
|
|
49
39
|
# show the active config
|
50
|
-
|
40
|
+
puts "=> " + Watchful::Configuration.active_configuration._description
|
51
41
|
|
52
42
|
# list active actions
|
53
43
|
Watchful::Configuration.active_configuration.actions.each do |a|
|
54
|
-
|
44
|
+
puts "=>\t+ #{a.name} (#{a.in} -> #{a.out})"
|
55
45
|
end
|
56
46
|
|
57
|
-
|
58
|
-
|
47
|
+
begin
|
48
|
+
Watchful::watch_files(path, opt['--force-polling'])
|
49
|
+
rescue Exception => e
|
50
|
+
if HAVE_GROWL
|
51
|
+
growl = Growl.new
|
52
|
+
growl.title = "GOING DOWN"
|
53
|
+
growl.message = 'Uncaught exception'
|
54
|
+
growl.run
|
55
|
+
end
|
56
|
+
raise e
|
57
|
+
end
|
59
58
|
end
|
60
|
-
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
App.run
|
data/lib/watchful.rb
CHANGED
@@ -10,6 +10,18 @@ require 'watchful/watch'
|
|
10
10
|
require 'watchful/action'
|
11
11
|
require 'watchful/defaultconfiguration'
|
12
12
|
|
13
|
+
begin
|
14
|
+
require 'growl'
|
15
|
+
rescue LoadError
|
16
|
+
HAVE_GROWL = false
|
17
|
+
else
|
18
|
+
if (Growl.installed? rescue false)
|
19
|
+
HAVE_GROWL = true
|
20
|
+
else
|
21
|
+
HAVE_GROWL = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
13
25
|
module Watchful
|
14
26
|
def self.version
|
15
27
|
File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).strip
|
data/lib/watchful/action.rb
CHANGED
@@ -1,36 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
1
2
|
require 'commandline' # for debug
|
3
|
+
require 'extensions/string'
|
2
4
|
|
3
5
|
module Watchful
|
4
6
|
|
5
7
|
class Action
|
6
8
|
|
7
|
-
# todo: support blocks for @in, @out,
|
9
|
+
# todo: support blocks for @in, @out, @command, @dependencies
|
8
10
|
|
9
11
|
PROPERTIES = [:name, :dependencies, :command, :in, :out]
|
10
12
|
|
11
13
|
PROPERTIES.each { |k| attr_accessor k }
|
12
14
|
|
13
|
-
@enabled = true
|
14
15
|
def enabled?; @enabled ;end
|
15
16
|
|
16
|
-
|
17
17
|
def initialize(options = {})
|
18
18
|
|
19
19
|
options[:dependencies] ||= []
|
20
20
|
|
21
|
+
@enabled = true
|
22
|
+
|
21
23
|
PROPERTIES.each do |key|
|
22
24
|
self.instance_variable_set('@' + key.to_s, options[key])
|
23
25
|
end
|
24
26
|
|
25
27
|
@dependencies = [@dependencies] if @dependencies.kind_of? String
|
26
28
|
|
27
|
-
raise "Dependencies option must be a string or array" if not @dependencies.kind_of? Array
|
29
|
+
raise ArgumentError.new("Dependencies option must be a string or array") if not @dependencies.kind_of? Array
|
28
30
|
|
29
31
|
[@in, @out].each do |i|
|
30
|
-
@enabled = false unless i and i.instance_of?
|
32
|
+
@enabled = false unless i and i.instance_of?(String) and i.starts_with?('.')
|
31
33
|
end
|
32
34
|
|
33
|
-
@enabled =
|
35
|
+
@enabled = false unless @command.instance_of?(String)
|
36
|
+
|
37
|
+
@enabled = false unless self.has_dependencies?
|
34
38
|
|
35
39
|
end
|
36
40
|
|
@@ -40,7 +44,7 @@ module Watchful
|
|
40
44
|
(Action.have_command?(d)) || (File.exists?(File.expand_path(d)))
|
41
45
|
end
|
42
46
|
# todo: more detailed messages about missing dependencies
|
43
|
-
|
47
|
+
puts "Missing dependencies for action \"#{@name}\"" unless have_all
|
44
48
|
return have_all
|
45
49
|
end
|
46
50
|
|
@@ -59,13 +63,17 @@ module Watchful
|
|
59
63
|
false
|
60
64
|
end
|
61
65
|
|
66
|
+
# given an input file, return the path of an output file
|
62
67
|
def output_path_for(source_path)
|
68
|
+
unless self.input_file?(source_path)
|
69
|
+
raise ArgumentError.new("#{source_path} is not an input file for action #{@name}")
|
70
|
+
end
|
63
71
|
return File.dirname(source_path) + '/' + File.basename(source_path, @in) + @out
|
64
72
|
end
|
65
73
|
|
66
74
|
# does the given path look like a path to which this action might write output?
|
67
75
|
def output_file?(path)
|
68
|
-
Watchful::compound_extension_of(path) == @
|
76
|
+
Watchful::compound_extension_of(path) == @out
|
69
77
|
end
|
70
78
|
|
71
79
|
# does the given path look like a path to which this action could be applied?
|
@@ -7,20 +7,20 @@ module Watchful
|
|
7
7
|
@@active_configuration = nil
|
8
8
|
|
9
9
|
def self.active_configuration; @@active_configuration; end
|
10
|
-
def self.active_configuration=(x)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def self.active_configuration=(x); @@active_configuration = x; end
|
11
|
+
|
12
|
+
def self.action_for_file(path)
|
13
|
+
@actions ||= []
|
14
|
+
@actions.find { |a| a.input_file?(path) && a.enabled?}
|
15
15
|
end
|
16
16
|
|
17
17
|
class << self
|
18
18
|
|
19
19
|
attr_reader :actions
|
20
20
|
|
21
|
-
def description(s); @description = s; end
|
22
|
-
|
23
21
|
def _description; @description; end
|
22
|
+
|
23
|
+
def description(s); @description = s; end
|
24
24
|
|
25
25
|
def action(args)
|
26
26
|
# set the description in case the user doesn’t
|
@@ -29,7 +29,7 @@ module Watchful
|
|
29
29
|
# set to active configuration
|
30
30
|
@@active_configuration = self
|
31
31
|
|
32
|
-
# todo: support block-
|
32
|
+
# todo: support block-style action definition
|
33
33
|
@actions ||= []
|
34
34
|
a = Watchful::Action.new(args)
|
35
35
|
@actions << a
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'watchful/configuration'
|
2
2
|
|
3
|
+
# todo: Don't require DefaultConfiguration by default
|
4
|
+
|
3
5
|
module Watchful
|
4
6
|
|
5
7
|
class DefaultConfiguration < Configuration
|
6
8
|
|
7
9
|
description "Default Configuration"
|
8
10
|
|
9
|
-
# LESS CSS, if installed
|
10
|
-
|
11
11
|
begin
|
12
|
-
|
12
|
+
require "less"
|
13
13
|
action :name => 'LESS CSS',
|
14
14
|
:in => '.less',
|
15
15
|
:out => '.css',
|
@@ -19,8 +19,6 @@ module Watchful
|
|
19
19
|
# pass
|
20
20
|
end
|
21
21
|
|
22
|
-
# SASS, if installed
|
23
|
-
|
24
22
|
if Action.have_command? 'sass'
|
25
23
|
action :name => 'SASS',
|
26
24
|
:in => '.sass',
|
@@ -29,6 +27,8 @@ module Watchful
|
|
29
27
|
:dependencies => 'sass'
|
30
28
|
end
|
31
29
|
|
30
|
+
# todo: Add more actions to DefaultConfiguration
|
31
|
+
|
32
32
|
end
|
33
33
|
|
34
34
|
end
|