diff --git a/Gemfile b/Gemfile
index 9b6f3c5..bd1d194 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,5 +13,6 @@ if Config::CONFIG['target_os'] =~ /linux/i
gem 'libnotify', '~> 0.1.3', :require => false
end
if Config::CONFIG['target_os'] =~ /mswin|mingw/i
- gem 'win32console'
+ gem 'win32console', :require => false
+ gem 'rb-fchange', '>= 0.0.2', :require => false
end
diff --git a/README.markdown b/README.markdown
index 1a8d72a..fd09da1 100644
--- a/README.markdown
+++ b/README.markdown
@@ -10,6 +10,7 @@ Features
* [FSEvent](http://en.wikipedia.org/wiki/FSEvents) support on Mac OS X 10.5+ (without RubyCocoa!, [rb-fsevent gem, >= 0.3.5](https://rubygems.org/gems/rb-fsevent) required).
* [Inotify](http://en.wikipedia.org/wiki/Inotify) support on Linux ([rb-inotify gem, >= 0.5.1](https://rubygems.org/gems/rb-inotify) required).
+* [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support on Windows ([rb-fchange, >= 0.0.2](https://rubygems.org/gems/rb-fchange) required).
* Polling on the other operating systems (help us to support more OS).
* Automatic & Super fast (when polling is not used) files modifications detection (even new files are detected).
* Growl notifications ([growlnotify](http://growl.info/documentation/growlnotify.php) & [growl gem](https://rubygems.org/gems/growl) required).
@@ -21,9 +22,11 @@ Install
Install the gem:
- $ gem install guard
+``` bash
+$ gem install guard
+```
-Add it to your Gemfile (inside the test group):
+Add it to your Gemfile (inside the `test` group):
``` ruby
gem 'guard'
@@ -31,7 +34,9 @@ gem 'guard'
Generate an empty Guardfile with:
- $ guard init
+``` bash
+$ guard init
+```
Add the guards you need to your Guardfile (see the existing guards below).
@@ -39,11 +44,15 @@ Add the guards you need to your Guardfile (see the existing guards below).
Install the rb-fsevent gem for [FSEvent](http://en.wikipedia.org/wiki/FSEvents) support:
- $ gem install rb-fsevent
+``` bash
+$ gem install rb-fsevent
+```
Install the Growl gem if you want notification support:
- $ gem install growl
+``` bash
+$ gem install growl
+```
And add it to you Gemfile:
@@ -55,11 +64,15 @@ gem 'growl'
Install the rb-inotify gem for [inotify](http://en.wikipedia.org/wiki/Inotify) support:
- $ gem install rb-inotify
+``` bash
+$ gem install rb-inotify
+```
Install the Libnotify gem if you want notification support:
- $ gem install libnotify
+``` bash
+$ gem install libnotify
+```
And add it to you Gemfile:
@@ -67,49 +80,69 @@ And add it to you Gemfile:
gem 'libnotify'
```
+### On Windows
+
+Install the rb-fchange gem for [Directory Change Notification](http://msdn.microsoft.com/en-us/library/aa365261\(VS.85\).aspx) support:
+
+``` bash
+$ gem install rb-fchange
+```
+
Usage
-----
Just launch Guard inside your Ruby / Rails project with:
- $ guard [start]
+``` bash
+$ guard [start]
+```
or if you use Bundler, to run the Guard executable specific to your bundle:
- $ bundle exec guard
+``` bash
+$ bundle exec guard
+```
Command line options
--------------------
Shell can be cleared after each change with:
- $ guard --clear
- $ guard -c # shortcut
+``` bash
+$ guard --clear
+$ guard -c # shortcut
+```
Notifications (growl/libnotify) can be disabled with:
- $ guard --notify false
- $ guard -n false # shortcut
+``` bash
+$ guard --notify false
+$ guard -n false # shortcut
+```
Notifications can also be disabled by setting a `GUARD_NOTIFY` environment variable to `false`
-The guards to start can be specified by group (see the Guardfile DSL below) specifying the --group (or -g) option:
+The guards to start can be specified by group (see the Guardfile DSL below) specifying the `--group` (or `-g`) option:
- $ guard --group group_name another_group_name
- $ guard -g group_name another_group_name # shortcut
+``` bash
+$ guard --group group_name another_group_name
+$ guard -g group_name another_group_name # shortcut
+```
Options list is available with:
- $ guard help [TASK]
+``` bash
+$ guard help [TASK]
+```
Signal handlers
---------------
Signal handlers are used to interact with Guard:
-* Ctrl-C - Calls each guard's stop method, in the same order they are declared in the Guardfile, and then quits Guard itself.
-* Ctrl-\\ - Calls each guard's run_all method, in the same order they are declared in the Guardfile.
-* Ctrl-Z - Calls each guard's reload method, in the same order they are declared in the Guardfile.
+* `Ctrl-C` - Calls each guard's `stop` method, in the same order they are declared in the Guardfile, and then quits Guard itself.
+* `Ctrl-\` - Calls each guard's `run_all` method, in the same order they are declared in the Guardfile.
+* `Ctrl-Z` - Calls each guard's `reload` method, in the same order they are declared in the Guardfile.
Available Guards
----------------
@@ -118,7 +151,7 @@ Available Guards
### Add a guard to your Guardfile
-Add it to your Gemfile (inside the test group):
+Add it to your Gemfile (inside the `test` group):
``` ruby
gem ''
@@ -126,21 +159,25 @@ gem ''
Insert default guard's definition to your Guardfile by running this command:
- $ guard init
+``` bash
+$ guard init
+```
You are good to go!
Guardfile DSL
-------------
-The Guardfile DSL consists of just three simple methods: guard, watch & group.
+The Guardfile DSL consists of just three simple methods: `guard`, `watch` & `group`.
Required:
-* The guard method allows you to add a guard with an optional hash of options.
-* The watch method allows you to define which files are supervised by this guard. An optional block can be added to overwrite the paths sent to the run_on_change guard method or to launch any arbitrary command.
+
+* The `guard` method allows you to add a guard with an optional hash of options.
+* The `watch` method allows you to define which files are supervised by this guard. An optional block can be added to overwrite the paths sent to the `run_on_change` guard method or to launch any arbitrary command.
Optional:
-* The group method allows you to group several guards together. Groups to be run can be specified with the Guard DSL option --group (or -g). This comes in handy especially when you have a huge Guardfile and want to focus your development on a certain part.
+
+* The `group` method allows you to group several guards together. Groups to be run can be specified with the Guard DSL option `--group` (or `-g`). This comes in handy especially when you have a huge Guardfile and want to focus your development on a certain part.
Example:
@@ -176,7 +213,7 @@ end
Create a new guard
------------------
-Creating a new guard is very easy, just create a new gem (bundle gem if you use Bundler) with this basic structure:
+Creating a new guard is very easy, just create a new gem (`bundle gem` if you use Bundler) with this basic structure:
lib/
guard/
@@ -185,7 +222,7 @@ Creating a new guard is very easy, just create a new gem (bundle gem if
Guardfile (needed for guard init )
guard-name.rb
-Guard::GuardName (in lib/guard/guard-name.rb) must inherit from Guard::Guard and should overwrite at least one of the five basic Guard::Guard instance methods. Example:
+`Guard::GuardName` (in `lib/guard/guard-name.rb`) must inherit from `Guard::Guard` and should overwrite at least one of the five basic `Guard::Guard` instance methods. Example:
``` ruby
require 'guard'
@@ -246,7 +283,7 @@ Alternatively, a new guard can be added inline to a Guardfile with this basic st
require 'guard/guard'
module ::Guard
- class Example < ::Guard::Guard
+ class InlineGuard < ::Guard::Guard
def run_all
true
end
@@ -271,3 +308,8 @@ Author
------
[Thibaud Guillaume-Gentil](https://github.com/thibaudgg)
+
+Contributors
+------
+
+https://github.com/guard/guard/contributors
\ No newline at end of file
diff --git a/lib/guard.rb b/lib/guard.rb
index ed3756c..3bdcca2 100644
--- a/lib/guard.rb
+++ b/lib/guard.rb
@@ -16,7 +16,7 @@ module Guard
@listener = Listener.select_and_init
@guards = []
- options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off
+ @options[:notify] && ENV["GUARD_NOTIFY"] != 'false' ? Notifier.turn_on : Notifier.turn_off
self
end
@@ -60,7 +60,7 @@ module Guard
guard.send(task_to_supervise, *args)
rescue Exception
UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise.to_s}> command: #{$!}")
- ::Guard.guards.delete guard
+ guards.delete guard
UI.info("Guard #{guard.class.name} has just been fired")
return $!
end
@@ -82,7 +82,7 @@ module Guard
def get_guard_class(name)
try_to_load_gem name
- self.const_get(self.constants.find{|klass_name| klass_name.to_s.downcase == name.downcase })
+ self.const_get(self.constants.find{ |klass_name| klass_name.to_s.downcase == name.downcase })
rescue TypeError
UI.error "Could not find load find gem 'guard-#{name}' or find class Guard::#{name}"
end
diff --git a/lib/guard/listener.rb b/lib/guard/listener.rb
index 3675489..0021c6b 100644
--- a/lib/guard/listener.rb
+++ b/lib/guard/listener.rb
@@ -4,6 +4,7 @@ module Guard
autoload :Darwin, 'guard/listeners/darwin'
autoload :Linux, 'guard/listeners/linux'
+ autoload :Windows, 'guard/listeners/windows'
autoload :Polling, 'guard/listeners/polling'
class Listener
@@ -14,6 +15,8 @@ module Guard
Darwin.new
elsif linux? && Linux.usable?
Linux.new
+ elsif windows? && Windows.usable?
+ Windows.new
else
UI.info "Using polling (Please help us to support your system better than that.)"
Polling.new
@@ -54,6 +57,10 @@ module Guard
Config::CONFIG['target_os'] =~ /linux/i
end
+ def self.windows?
+ Config::CONFIG['target_os'] =~ /mswin|mingw/i
+ end
+
end
end
diff --git a/lib/guard/listeners/windows.rb b/lib/guard/listeners/windows.rb
new file mode 100644
index 0000000..e6d888a
--- /dev/null
+++ b/lib/guard/listeners/windows.rb
@@ -0,0 +1,36 @@
+module Guard
+ class Windows < Listener
+ attr_reader :fchange
+
+ def initialize
+ super
+ @fchange = FChange::Notifier.new
+ end
+
+ def on_change(&callback)
+ @fchange.watch(Dir.pwd, :all_events, :recursive) do |event|
+ paths = [File.expand_path(event.watcher.path) + '/']
+ files = modified_files(paths, {:all => true})
+ update_last_event
+ callback.call(files)
+ end
+ end
+
+ def start
+ @fchange.run
+ end
+
+ def stop
+ @fchange.stop
+ end
+
+ def self.usable?
+ require 'rb-fchange'
+ true
+ rescue LoadError
+ UI.info "Please install rb-fchange gem for Windows file events support"
+ false
+ end
+
+ end
+end
diff --git a/spec/guard/listener_spec.rb b/spec/guard/listener_spec.rb
index dfbface..5d09104 100644
--- a/spec/guard/listener_spec.rb
+++ b/spec/guard/listener_spec.rb
@@ -14,10 +14,10 @@ describe Guard::Listener do
subject.select_and_init
end
- it "uses polling listener on Windows" do
- Config::CONFIG['target_os'] = 'win32'
- Guard::Polling.stub(:usable?).and_return(true)
- Guard::Polling.should_receive(:new)
+ it "uses windows listener on Windows" do
+ Config::CONFIG['target_os'] = 'mingw'
+ Guard::Windows.stub(:usable?).and_return(true)
+ Guard::Windows.should_receive(:new)
subject.select_and_init
end
diff --git a/spec/guard/listeners/windows_spec.rb b/spec/guard/listeners/windows_spec.rb
new file mode 100644
index 0000000..4cc1c6b
--- /dev/null
+++ b/spec/guard/listeners/windows_spec.rb
@@ -0,0 +1,88 @@
+require 'spec_helper'
+require 'guard/listeners/windows'
+
+describe Guard::Windows do
+ subject { Guard::Windows }
+
+ if linux?
+ it "isn't usable on linux" do
+ subject.should_not be_usable
+ end
+ end
+
+ if mac?
+ it "isn't usable on Mac" do
+ subject.should_not be_usable
+ end
+ end
+
+ if windows?
+ it "is usable on Windows 2000 and later" do
+ subject.should be_usable
+ end
+
+ describe "#on_change" do
+ before(:each) do
+ @results = []
+ @listener = Guard::Windows.new
+ @listener.on_change do |files|
+ @results += files
+ end
+ end
+
+ it "catches new file" do
+ file = @fixture_path.join("newfile.rb")
+ if File.exists?(file)
+ begin
+ File.delete file
+ rescue
+ end
+ end
+ File.exists?(file).should be_false
+ start
+ FileUtils.touch file
+ stop
+ begin
+ File.delete file
+ rescue
+ end
+ @results.should == ['spec/fixtures/newfile.rb']
+ end
+
+ it "catches file update" do
+ file = @fixture_path.join("folder1/file1.txt")
+ File.exists?(file).should be_true
+ start
+ FileUtils.touch file
+ stop
+ @results.should == ['spec/fixtures/folder1/file1.txt']
+ end
+
+ it "catches files update" do
+ file1 = @fixture_path.join("folder1/file1.txt")
+ file2 = @fixture_path.join("folder1/folder2/file2.txt")
+ File.exists?(file1).should be_true
+ File.exists?(file2).should be_true
+ start
+ FileUtils.touch file1
+ FileUtils.touch file2
+ stop
+ @results.should == ['spec/fixtures/folder1/file1.txt', 'spec/fixtures/folder1/folder2/file2.txt']
+ end
+ end
+ end
+
+private
+
+ def start
+ sleep 0.6
+ Thread.new { @listener.start }
+ sleep 0.6
+ end
+
+ def stop
+ sleep 0.6
+ @listener.stop
+ end
+
+end
diff --git a/spec/guard/notifier_spec.rb b/spec/guard/notifier_spec.rb
index e09622c..5a228e1 100644
--- a/spec/guard/notifier_spec.rb
+++ b/spec/guard/notifier_spec.rb
@@ -38,14 +38,14 @@ describe Guard::Notifier do
end
describe ".turn_off" do
+ before(:each) { subject.turn_off }
+
if mac? && growl_installed?
it "does nothing" do
Growl.should_not_receive(:notify)
subject.notify 'great', :title => 'Guard'
end
- end
-
- if linux? && libnotify_installed?
+ elsif linux? && libnotify_installed?
it "does nothing" do
Libnotify.should_not_receive(:show)
subject.notify 'great', :title => 'Guard'
diff --git a/spec/support/platform_helper.rb b/spec/support/platform_helper.rb
index 2b8bfb5..c1acf10 100644
--- a/spec/support/platform_helper.rb
+++ b/spec/support/platform_helper.rb
@@ -4,4 +4,8 @@ end
def linux?
Config::CONFIG['target_os'] =~ /linux/i
+end
+
+def windows?
+ Config::CONFIG['target_os'] =~ /mswin|mingw/i
end
\ No newline at end of file