Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge https://github.com/guard/guard

  • Loading branch information...
commit c01bef5dab1a3daa571cf4f827f79edd40b4f4ac 2 parents 1d0d1eb + 3b56ef7
@Maher4Ever authored
View
44 CHANGELOG.md
@@ -1,3 +1,36 @@
+## Master
+
+### Bug fix
+
+- [#213 & 214](https://github.com/guard/guard/issues/214): Fixes the "ERROR: No guards found in Guardfile" message wrongly displayed when running `guard list`. ([@pirukire][])
+
+## 0.10.0 - 1 January, 2012
+
+### Improvement
+
+- Improved Readline constraints. ([@netzpirat][])
+- Stop & start all guards on Guardfile reevaluation. ([@thibaudgg][])
+
+### Bug fix
+
+- Terminal keep-alive causing ERROR: Unknown command. ([@waldo][])
+
+## 0.9.4 - December 25, 2011
+
+### Improvement
+
+- Add the ability to load user defined templates. ([@hawx][])
+
+### Bug fix
+
+- Fix guard-rspec notifications by using ENV variable to store Notifier.notifications. ([@thibaudgg][])
+
+## 0.9.3 - December 23, 2011
+
+### Improvement
+
+- Fix terminal status after interrupting the Readline interactor. ([@Maher4Ever][])
+
## 0.9.2 - December 22, 2011
### Improvements
@@ -7,16 +40,16 @@
## 0.9.1 - December 19, 2011
-### Bug fix
+### Bug fixes
- Fix wrong `--no-vendor` option. ([@netzpirat][])
-- [#195](https://github.com/guard/guard/issues/195): Empty watch directory prohibit Guard from running. (reported by [@madtrick][], fixed by [@netzpirat][]
+- [#195](https://github.com/guard/guard/issues/195): Empty watch directory prohibit Guard from running. (reported by [@madtrick][], fixed by [@netzpirat][])
## 0.9.0 - December 19, 2011
-### Bug fix
+### Bug fixes
-- [#173](https://github.com/guard/guard/issues/173): Cannot set the watch_all_modifications option. (reported by [@sutherland][], fixed by [@netzpirat][]
+- [#173](https://github.com/guard/guard/issues/173): Cannot set the watch_all_modifications option. (reported by [@sutherland][], fixed by [@netzpirat][])
- Fix `guard init` when a guard name is given. ([@rymai][])
### Improvements
@@ -360,6 +393,7 @@
[@fnichol]: https://github.com/fnichol
[@Gazer]: https://github.com/Gazer
[@gix]: https://github.com/gix
+[@hawx]: https://github.com/hawx
[@hron]: https://github.com/hron
[@hardipe]: https://github.com/hardipe
[@hashrocketeer]: https://github.com/hashrocketeer
@@ -382,6 +416,7 @@
[@niklas]: https://github.com/niklas
[@oliamb]: https://github.com/oliamb
[@pcreux]: https://github.com/pcreux
+[@pirukire]: https://github.com/pirukire
[@rmm5t]: https://github.com/rmm5t
[@rymai]: https://github.com/rymai
[@scottdavis]: https://github.com/scottdavis
@@ -396,6 +431,7 @@
[@tpope]: https://github.com/tpope
[@uk-ar]: https://github.com/uk-ar
[@veged]: https://github.com/veged
+[@waldo]: https://github.com/waldo
[@wereHamster]: https://github.com/wereHamster
[@yannlugrin]: https://github.com/yannlugrin
[@zonque]: https://github.com/zonque
View
2  LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2011 Thibaud Guillaume-Gentil
+Copyright (c) 2009-2012 Thibaud Guillaume-Gentil
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
View
56 README.md
@@ -63,7 +63,8 @@ the time, try the [Rubygems Bundler](https://github.com/mpapis/rubygems-bundler)
### System notifications
-You can configure Guard to make use of the following system notification libraries:
+You can configure Guard to make use of the following system notification libraries, but it's strongly recommended
+to use either Ruby GNTP, Libnotify or Notifu:
#### Ruby GNTP
@@ -87,31 +88,6 @@ group :development do
end
```
-#### Growl
-
-* Runs on Mac OS X
-* Supports all [Growl](http://growl.info/) versions
-
-The [growl](https://rubygems.org/gems/growl) gem is compatible with all versions of Growl and uses a command line tool
-[growlnotify](http://growl.info/extras.php#growlnotify) that must be separately downloaded and installed. The version of
-the command line tool must match your Growl version. The `growl` gem does **not** support multiple notification
-channels.
-
-You can download an installer for `growlnotify` from the [Growl download section](http://growl.info/downloads) or
-install it with HomeBrew:
-
-```bash
-$ brew install growlnotify
-```
-
-To use `growl` you have to add it to your `Gemfile` and run bundler:
-
-```ruby
-group :development do
- gem 'growl'
-end
-```
-
#### Libnotify
* Runs on Linux, FreeBSD, OpenBSD and Solaris
@@ -144,6 +120,26 @@ group :development do
end
```
+#### Growl
+
+* Runs on Mac OS X
+* Supports all [Growl](http://growl.info/) versions
+
+The [growl](https://rubygems.org/gems/growl) gem is compatible with all versions of Growl and uses a command line tool
+[growlnotify](http://growl.info/extras.php#growlnotify) that must be separately downloaded and installed. The version of
+the command line tool must match your Growl version. The `growl` gem does **not** support multiple notification
+channels.
+
+You have to download the installer for `growlnotify` from the [Growl download section](http://growl.info/downloads).
+
+To use `growl` you have to add it to your `Gemfile` and run bundler:
+
+```ruby
+group :development do
+ gem 'growl'
+end
+```
+
#### GrowlNotify
* Runs on Mac OS X
@@ -218,6 +214,13 @@ In addition, the `init` task can be used to append a supplied Guard template fro
$ guard init <guard-name>
```
+You can also define your own templates in `~/.guard/templates/` which can be appended in the same way to your existing
+`Guardfile`:
+
+```bash
+$ guard init <template-name>
+```
+
### Start
Just launch Guard inside your Ruby or Rails project with:
@@ -839,6 +842,7 @@ Pull requests are very welcome! Please try to follow these simple rules if appli
* Please create a topic branch for every separate change you make.
* Make sure your patches are well tested. All specs run with `rake spec:portability` must pass.
+ * On OS X you need to compile once rb-fsevent executable with `rake build_mac_exec`.
* Update the [Yard](http://yardoc.org/) documentation.
* Update the README.
* Update the CHANGELOG for noteworthy changes.
View
34 lib/guard.rb
@@ -17,6 +17,8 @@ module Guard
# The Guardfile template for `guard init`
GUARDFILE_TEMPLATE = File.expand_path('../guard/templates/Guardfile', __FILE__)
+ # The location of user defined templates
+ HOME_TEMPLATES = File.expand_path('~/.guard/templates')
class << self
attr_accessor :options, :interactor, :listener, :lock
@@ -26,7 +28,7 @@ class << self
#
# @see Guard::Guard.init
#
- # @param [String] guard_name the name of the Guard to initialize
+ # @param [String] guard_name the name of the Guard or template to initialize
#
def initialize_template(guard_name = nil)
if !File.exist?('Guardfile')
@@ -38,8 +40,24 @@ def initialize_template(guard_name = nil)
end
if guard_name
- guard_class = ::Guard.get_guard_class(guard_name)
- guard_class.init(guard_name)
+ guard_class = ::Guard.get_guard_class(guard_name, true)
+ if guard_class
+ guard_class.init(guard_name)
+ elsif File.exist?(File.join(HOME_TEMPLATES, guard_name))
+ content = File.read('Guardfile')
+ template = File.read(File.join(HOME_TEMPLATES, guard_name))
+
+ File.open('Guardfile', 'wb') do |f|
+ f.puts(content)
+ f.puts("")
+ f.puts(template)
+ end
+
+ ::Guard::UI.info "#{ guard_name } template added to Guardfile, feel free to edit it"
+ else
+ const_name = guard_name.downcase.gsub('-', '')
+ UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }"
+ end
end
end
@@ -162,6 +180,7 @@ def start(options = {})
setup(options)
Dsl.evaluate_guardfile(options)
+ UI.error 'No guards found in Guardfile, please add at least one.' if ::Guard.guards.empty?
options[:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off
@@ -432,9 +451,10 @@ def add_group(name, options = {})
# * `rspec` will find a class `Guard::RSpec`
#
# @param [String] name the name of the Guard
+ # @param [Boolean] fail_gracefully whether error messages should not be printed
# @return [Class, nil] the loaded class
#
- def get_guard_class(name)
+ def get_guard_class(name, fail_gracefully=false)
name = name.to_s
try_require = false
const_name = name.gsub(/\/(.?)/) { "::#{ $1.upcase }" }.gsub(/(?:^|[_-])(.)/) { $1.upcase }
@@ -449,8 +469,10 @@ def get_guard_class(name)
UI.error "Could not find class Guard::#{ const_name.capitalize }"
end
rescue LoadError => loadError
- UI.error "Could not load 'guard/#{ name.downcase }' or find class Guard::#{ const_name.capitalize }"
- UI.error loadError.to_s
+ unless fail_gracefully
+ UI.error "Could not load 'guard/#{ name.downcase }' or find class Guard::#{ const_name.capitalize }"
+ UI.error loadError.to_s
+ end
end
end
View
29 lib/guard/dsl.rb
@@ -100,21 +100,30 @@ def evaluate_guardfile(options = {})
fetch_guardfile_contents
instance_eval_guardfile(guardfile_contents_with_user_config)
-
- UI.error 'No guards found in Guardfile, please add at least one.' if !::Guard.guards.nil? && ::Guard.guards.empty?
end
# Re-evaluate the `Guardfile` to update the current Guard configuration.
#
def reevaluate_guardfile
- ::Guard.guards.clear
- ::Guard.reset_groups
- ::Guard::Notifier.notifications.clear
- @@options.delete(:guardfile_contents)
- Dsl.evaluate_guardfile(@@options)
- msg = 'Guardfile has been re-evaluated.'
- UI.info(msg)
- Notifier.notify(msg)
+ ::Guard.run do
+ # Stop each old guards
+ ::Guard.run_on_guards do |guard|
+ ::Guard.run_supervised_task(guard, :stop)
+ end
+ ::Guard.guards.clear
+ ::Guard.reset_groups
+ ::Guard::Notifier.clear_notifications
+ @@options.delete(:guardfile_contents)
+ Dsl.evaluate_guardfile(@@options)
+ UI.error 'No guards found in Guardfile, please add at least one.' if ::Guard.guards.empty?
+ msg = 'Guardfile has been re-evaluated.'
+ UI.info(msg)
+ Notifier.notify(msg)
+ # Start each new guards
+ ::Guard.run_on_guards do |guard|
+ ::Guard.run_supervised_task(guard, :start)
+ end
+ end
end
# Evaluate the content of the `Guardfile`.
View
2  lib/guard/dsl_describer.rb
@@ -48,7 +48,7 @@ def list(options)
evaluate_guardfile(options)
installed_guards = guardfile_structure.inject([]) do |installed, group|
- group[:guards].each { |guard| installed << guard[:name] } if group[:guards]
+ group[:guards].each { |guard| installed << guard[:name].to_s } if group[:guards]
installed
end
View
3  lib/guard/interactor.rb
@@ -79,7 +79,7 @@ def self.fabricate
def self.auto_detect
require 'readline'
- if defined?(RbReadline) || defined?(JRUBY_VERSION) || !RbConfig::CONFIG['target_os'] =~ /darwin/i
+ if defined?(RbReadline) || defined?(JRUBY_VERSION) || RbConfig::CONFIG['target_os'] =~ /linux/i
ReadlineInteractor.new
else
SimpleInteractor.new
@@ -96,6 +96,7 @@ def start
# Kill interactor thread if not current
#
def stop
+ return if ENV['GUARD_ENV'] == 'test'
unless Thread.current == @thread
@thread.kill
end
View
3  lib/guard/interactors/readline.rb
@@ -15,7 +15,7 @@ class ReadlineInteractor < Interactor
def initialize
require 'readline'
- unless defined?(RbReadline) || defined?(JRUBY_VERSION)
+ unless defined?(RbReadline) || defined?(JRUBY_VERSION) || RbConfig::CONFIG['target_os'] =~ /linux/i
::Guard::UI.info 'Please add rb-readline for proper Readline support.'
end
@@ -46,6 +46,7 @@ def stop
#
def read_line
while line = Readline.readline(prompt, true)
+ line.gsub!(/^\W*/, '')
if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
Readline::HISTORY.pop
end
View
2  lib/guard/interactors/simple.rb
@@ -9,7 +9,7 @@ class SimpleInteractor < Interactor
#
def read_line
while line = $stdin.gets
- process_input(line.chomp)
+ process_input(line.gsub(/^\W*/, '').chomp)
end
end
View
14 lib/guard/notifier.rb
@@ -1,3 +1,5 @@
+require 'yaml'
+
require 'rbconfig'
require 'pathname'
require 'guard/ui'
@@ -53,7 +55,7 @@ module Notifier
# @return [Hash] the notifications
#
def notifications
- @notifications ||= []
+ ENV['GUARD_NOTIFICATIONS'] ? YAML::load(ENV['GUARD_NOTIFICATIONS']) : []
end
# Set the available notifications.
@@ -61,7 +63,13 @@ def notifications
# @param [Array<Hash>] notifications the notifications
#
def notifications=(notifications)
- @notifications = notifications
+ ENV['GUARD_NOTIFICATIONS'] = YAML::dump(notifications)
+ end
+
+ # Clear available notifications.
+ #
+ def clear_notifications
+ ENV['GUARD_NOTIFICATIONS'] = nil
end
# Turn notifications on. If no notifications are defined
@@ -107,7 +115,7 @@ def add_notification(name, options = { }, silent = false)
return turn_off if name == :off
if NOTIFIERS.has_key?(name) && NOTIFIERS[name].available?(silent)
- notifications << { :name => name, :options => options }
+ self.notifications = notifications << { :name => name, :options => options }
true
else
false
View
2  lib/guard/version.rb
@@ -1,6 +1,6 @@
module Guard
unless defined? Guard::VERSION
# The current gem version of Guard
- VERSION = '0.9.2'
+ VERSION = '0.10.0'
end
end
View
6 spec/guard/dsl_describer_spec.rb
@@ -6,7 +6,7 @@
let(:guardfile) do
<<-GUARD
- guard 'test', :a => :b do
+ guard :test, :a => :b do
watch('c')
end
@@ -17,7 +17,7 @@
end
group "b" do
- guard 'another' do
+ guard :another do
watch('c')
end
end
@@ -34,7 +34,7 @@
end
describe '.list' do
- it 'lists the available Guards' do
+ it "lists the available Guards when they're declared as strings or symbols" do
Guard.stub(:guard_gem_names).and_return ['test', 'another', 'even', 'more']
describer.list(:guardfile_contents => guardfile)
@output.should eql <<OUTPUT
View
34 spec/guard/dsl_spec.rb
@@ -78,10 +78,10 @@ def self.disable_user_config
lambda { described_class.evaluate_guardfile }.should raise_error
end
- it "displays an error message when no guard are defined in Guardfile" do
+ it "doesn't display an error message when no guard are defined in Guardfile" do
::Guard::Dsl.stub!(:instance_eval_guardfile)
::Guard.stub!(:guards).and_return([])
- Guard::UI.should_receive(:error)
+ Guard::UI.should_not_receive(:error)
described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string)
end
@@ -155,6 +155,19 @@ def self.disable_user_config
describe ".reevaluate_guardfile" do
before(:each) { ::Guard::Dsl.stub!(:instance_eval_guardfile) }
+ it "stops already defined guard before calling evaluate_guardfile" do
+ Guard::Notifier.turn_off
+ described_class.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string)
+
+ ::Guard.guards.should_not be_empty
+ ::Guard.guards.each do |guard|
+ ::Guard.should_receive(:run_supervised_task).with(guard, :stop)
+ end
+ ::Guard::Dsl.should_receive(:evaluate_guardfile)
+
+ described_class.reevaluate_guardfile
+ end
+
it "resets already defined guards before calling evaluate_guardfile" do
Guard::Notifier.turn_off
described_class.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string)
@@ -177,7 +190,7 @@ def self.disable_user_config
described_class.reevaluate_guardfile
::Guard.groups.should_not be_empty
- ::Guard.groups[0].name.should eql :default
+ ::Guard.groups[0].name.should eq :default
::Guard.groups[0].options.should == {}
end
@@ -193,6 +206,21 @@ def self.disable_user_config
::Guard::Notifier.notifications.should be_empty
end
+
+ # Tricky because ::Guard.guards is reset during reevaluate_guardfile so we can't mocking it. Any idea?
+ pending "starts new defined guard after calling evaluate_guardfile" do
+ Guard::Notifier.turn_off
+ described_class.evaluate_guardfile(:guardfile_contents => invalid_guardfile_string)
+
+ ::Guard::Dsl.should_receive(:evaluate_guardfile)
+ ::Guard.guards.should_not be_empty
+ ::Guard.guards.each do |guard|
+ ::Guard.should_receive(:run_supervised_task).with(guard, :stop)
+ ::Guard.should_receive(:run_supervised_task).with(any_args(), :start)
+ end
+
+ described_class.reevaluate_guardfile
+ end
end
describe ".guardfile_default_path" do
View
2  spec/guard/interactors/readline_spec.rb
@@ -66,9 +66,11 @@
it 'reads all lines for processing' do
Readline.should_receive(:readline).and_return 'First line'
Readline.should_receive(:readline).and_return 'Second line'
+ Readline.should_receive(:readline).and_return "\x00 \tControl line"
Readline.should_receive(:readline).and_return nil
subject.should_receive(:process_input).with('First line').and_return
subject.should_receive(:process_input).with('Second line').and_return
+ subject.should_receive(:process_input).with('Control line').and_return
subject.read_line
end
end
View
2  spec/guard/interactors/simple_spec.rb
@@ -11,10 +11,12 @@
it 'reads all lines for processing' do
$stdin.should_receive(:gets).and_return "First line\n"
$stdin.should_receive(:gets).and_return "Second line\n"
+ $stdin.should_receive(:gets).and_return "\x00 \tControl line\n"
$stdin.should_receive(:gets).and_return nil
subject.should_receive(:process_input).with('First line')
subject.should_receive(:process_input).with('Second line')
+ subject.should_receive(:process_input).with('Control line')
subject.read_line
end
end
View
32 spec/guard_spec.rb
@@ -33,6 +33,25 @@ class Guard::Foo < Guard::Guard
Guard.initialize_template('foo')
end
end
+
+ context "with a user defined template" do
+ let(:template) { File.join(Guard::HOME_TEMPLATES, '/bar') }
+
+ before {
+ File.should_receive(:exist?).with('Guardfile').and_return false
+ File.should_receive(:exist?).with(template).and_return true
+ }
+
+ it "copies the Guardfile template and initializes the Guard" do
+ FileUtils.should_receive(:cp).with(an_instance_of(String), 'Guardfile')
+ File.should_receive(:read).with('Guardfile').and_return 'Guardfile content'
+ File.should_receive(:read).with(template).and_return 'Template content'
+ io = StringIO.new
+ File.should_receive(:open).with('Guardfile', 'wb').and_yield io
+ Guard.initialize_template('bar')
+ io.string.should eql "Guardfile content\n\nTemplate content\n"
+ end
+ end
end
context "without a Guard name" do
@@ -246,6 +265,12 @@ class Guard::FooBaz < Guard::Guard; end
::Guard.start(options)
end
+ it "displays an error message when no guard are defined in Guardfile" do
+ ::Guard::Dsl.should_receive(:evaluate_guardfile).with(options)
+ ::Guard::UI.should_receive(:error)
+ ::Guard.start(options)
+ end
+
it "starts the listeners" do
::Guard.listener.should_receive(:start)
::Guard.start(options)
@@ -495,6 +520,13 @@ class Inline < Guard
Guard.get_guard_class('inline').should == Guard::Inline
end
end
+
+ context 'when set to fail gracefully' do
+ it 'does not print error messages on fail' do
+ ::Guard::UI.should_not_receive(:error)
+ Guard.get_guard_class('notAGuardClass', true).should be_nil
+ end
+ end
end
describe ".locate_guard" do
Please sign in to comment.
Something went wrong with that request. Please try again.