Skip to content

Commit

Permalink
Merge pull request guard#232 from Maher4Ever/master
Browse files Browse the repository at this point in the history
Add the ability to initialize all guards at once and a --bare option to the init task
  • Loading branch information
thibaudgg committed Jan 28, 2012
2 parents c61a49c + 688100a commit 3e854a9
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 83 deletions.
25 changes: 20 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,26 +201,41 @@ $ guard help start

### Init

You can generate an empty `Guardfile` by running the `init` task:
You can generate a Guardfile and have all installed guards be automatically added into
it by running the `init` task without any option:

```bash
$ guard init
```

In addition, the `init` task can be used to append a supplied Guard template from an installed Guard to your existing
`Guardfile`:
You can also specify the name of an installed Guard to only get that Guard
in the generated Guardfile:

```bash
$ 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
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>
```

**Note**: If you already have a `Guardfile` in the current directory, the `init` task can be used
to append a supplied Guard template from an installed Guard to your existing
`Guardfile`.

#### `-b`/`--bare` option

You can generate an empty `Guardfile` by running the `init` task with the bare
option:

```bash
$ guard init --bare
$ guard init -b # shortcut
```

### Start

Just launch Guard inside your Ruby or Rails project with:
Expand Down Expand Up @@ -832,7 +847,7 @@ When you file an issue, please try to follow to these simple rules if applicable
* Add your `Guardfile` and `Gemfile` to the issue.
* Make sure that the issue is reproducible with your description.

Development [![Dependency Status](https://gemnasium.com/guard/guard.png?branch=master)](https://gemnasium.com/guard/guard)
Development [![Dependency Status](https://gemnasium.com/guard/guard.png?branch=master)](https://gemnasium.com/guard/guard)
-----------

* Documentation hosted at [RubyDoc](http://rubydoc.info/github/guard/guard/master/frames).
Expand Down
66 changes: 42 additions & 24 deletions lib/guard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,62 @@ module Guard
class << self
attr_accessor :options, :interactor, :listener, :lock

# Creates the initial Guardfile template and/or add a Guard implementation
# Guardfile template to an existing Guardfile.
# Creates the initial Guardfile template when it does not
# already exist.
#
# @see Guard::Guard.init
# @see Guard::CLI.init
#
# @param [String] guard_name the name of the Guard or template to initialize
# @param [Hash] options The options for creating a Guardfile
# @option options [Boolean] :abort_on_existence Whether to abort or not when a Guardfile already exists
#
def initialize_template(guard_name = nil)
def create_guardfile(options = {})
if !File.exist?('Guardfile')
::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
elsif guard_name.nil?
elsif options[:abort_on_existence]
::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
exit 1
abort
end
end

if 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
# Adds the Guardfile template of a Guard implementation
# to an existing Guardfile.
#
# @see Guard::CLI.init
#
# @param [String] guard_name the name of the Guard or template to initialize
#
def initialize_template(guard_name)
guard_class = ::Guard.get_guard_class(guard_name, true)

::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 }"
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

# Adds the templates of all installed Guard implementations
# to an existing Guardfile.
#
# @see Guard::CLI.init
#
def initialize_all_templates
guard_gem_names.each {|g| initialize_template(g) }
end

# Initialize the Guard singleton:
#
# - Initialize the internal Guard state.
Expand Down
27 changes: 22 additions & 5 deletions lib/guard/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,35 @@ def version
::Guard::UI.info "Guard version #{ ::Guard::VERSION }"
end

desc 'init [GUARD]', 'Generates a Guardfile at the current working directory, or insert the given GUARD to an existing Guardfile'
desc 'init [GUARD]', 'Generates a Guardfile at the current directory (if it is not already there) and adds all installed guards or the given GUARD into it'

# Appends the Guard template to the `Guardfile`, or creates an initial
# `Guardfile` when no Guard name is passed.
method_option :bare,
:type => :boolean,
:default => false,
:aliases => '-b',
:banner => 'Generate a bare Guardfile without adding any installed guard into it'

# Initializes the templates of all installed Guards and adds them
# to the `Guardfile` when no Guard name is passed. When passed
# a guard name is does the same but only for that Guard.
#
# @see Guard.initialize_template
# @see Guard::Guard.initialize_template
# @see Guard::Guard.initialize_all_templates
#
# @param [String] guard_name the name of the Guard to initialize
#
def init(guard_name = nil)
verify_bundler_presence
::Guard.initialize_template(guard_name)

::Guard.create_guardfile(:abort_on_existence => options[:bare])

return if options[:bare]

if guard_name.nil?
::Guard::initialize_all_templates
else
::Guard.initialize_template(guard_name)
end
end

desc 'show', 'Show all defined Guards and their options'
Expand Down
36 changes: 33 additions & 3 deletions spec/guard/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,43 @@
end

describe '#init' do
before { ::Guard.stub(:initialize_template) }
let(:options) { {:bare => false} }

it 'delegates to Guard::DslDescriber.list' do
::Guard.should_receive(:initialize_template)
before do
subject.stub(:options => options)
::Guard.stub(:create_guardfile)
::Guard.stub(:initialize_all_templates)
end

it 'creates a Guardfile by delegating to Guard.create_guardfile' do
::Guard.should_receive(:create_guardfile).with(:abort_on_existence => options[:bare])
subject.init
end

it 'initializes the templates of all installed Guards by delegating to Guard.initialize_all_templates' do
::Guard.should_receive(:initialize_all_templates)
subject.init
end

context 'when passed a guard name' do
it 'initializes the template of the passed Guard by delegating to Guard.initialize_template' do
::Guard.should_receive(:initialize_template).with('rspec')
subject.init 'rspec'
end
end

context 'with the bare option' do
let(:options) { {:bare => true} }

it 'Only creates the Guardfile and does not initialize any Guard template' do
::Guard.should_receive(:create_guardfile)
::Guard.should_not_receive(:initialize_template)
::Guard.should_not_receive(:initialize_all_templates)

subject.init
end
end

context 'when running with Bundler' do
before do
@bundler_env = ENV['BUNDLE_GEMFILE']
Expand Down
118 changes: 72 additions & 46 deletions spec/guard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,102 @@
File.exists?(Guard::GUARDFILE_TEMPLATE).should be_true
end

describe ".initialize_template" do
describe ".create_guardfile" do
before { Dir.stub(:pwd).and_return "/home/user" }

context "with a Guard name" do
class Guard::Foo < Guard::Guard
context "with an existing Guardfile" do
before { File.should_receive(:exist?).and_return true }

it "does not copy the Guardfile template or notify the user" do
::Guard::UI.should_not_receive(:info)
FileUtils.should_not_receive(:cp)

subject.create_guardfile
end

context "with an existing Guardfile" do
before { File.should_receive(:exist?).and_return true }
it "does not display any kind of error or abort" do
::Guard::UI.should_not_receive(:error)
subject.should_not_receive(:abort)
subject.create_guardfile
end

it "initializes the Guard" do
Guard::Foo.should_receive(:init)
Guard.initialize_template('foo')
context "with the :abort_on_existence option set to true" do
it "displays an error message and aborts the process" do
::Guard::UI.should_receive(:error).with("Guardfile already exists at /home/user/Guardfile")
subject.should_receive(:abort)
subject.create_guardfile(:abort_on_existence => true)
end
end
end

context "without an existing Guardfile" do
before { File.should_receive(:exist?).and_return false }
context "without an existing Guardfile" do
before { File.should_receive(:exist?).and_return false }

it "copies the Guardfile template and initializes the Guard" do
::Guard::UI.should_receive(:info).with("Writing new Guardfile to /home/user/Guardfile")
FileUtils.should_receive(:cp).with(an_instance_of(String), 'Guardfile')
Guard::Foo.should_receive(:init)
Guard.initialize_template('foo')
end
it "copies the Guardfile template and notifies the user" do
::Guard::UI.should_receive(:info)
FileUtils.should_receive(:cp)

subject.create_guardfile
end
end
end

context "with a user defined template" do
let(:template) { File.join(Guard::HOME_TEMPLATES, '/bar') }
describe ".initialize_template" do
context 'with an installed Guard implementation' do
let(:foo_guard) { double('Guard::Foo').as_null_object }

before {
File.should_receive(:exist?).with('Guardfile').and_return false
File.should_receive(:exist?).with(template).and_return true
}
before { ::Guard.should_receive(:get_guard_class).and_return(foo_guard) }

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
it "initializes the Guard" do
foo_guard.should_receive(:init)
subject.initialize_template('foo')
end
end

context "without a Guard name" do
context "with an existing Guardfile" do
before { File.should_receive(:exist?).and_return true }
context "with a user defined template" do
let(:template) { File.join(Guard::HOME_TEMPLATES, '/bar') }

it "shows an error" do
Guard.should_receive(:exit).with 1
::Guard::UI.should_receive(:error).with("Guardfile already exists at /home/user/Guardfile")
Guard.initialize_template
end
before { File.should_receive(:exist?).with(template).and_return true }

it "copies the Guardfile template and initializes the Guard" do
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
subject.initialize_template('bar')
io.string.should eql "Guardfile content\n\nTemplate content\n"
end
end

context "without an existing Guardfile" do
before { File.should_receive(:exist?).and_return false }
context "when the passed guard can't be found" do
before do
::Guard.should_receive(:get_guard_class).and_return nil
File.should_receive(:exist?).and_return false
end

it "copies the Guardfile template" do
::Guard::UI.should_receive(:info).with("Writing new Guardfile to /home/user/Guardfile")
FileUtils.should_receive(:cp).with(an_instance_of(String), 'Guardfile')
Guard.initialize_template
end
it "notifies the user about the problem" do
::Guard::UI.should_receive(:error).with(
"Could not load 'guard/foo' or '~/.guard/templates/foo' or find class Guard::Foo"
)
subject.initialize_template('foo')
end
end
end

describe ".initialize_all_templates" do
let(:guards) { ['rspec', 'spork', 'phpunit'] }

before { subject.should_receive(:guard_gem_names).and_return(guards) }

it "calls Guard.initialize_template on all installed guards" do
guards.each do |g|
subject.should_receive(:initialize_template).with(g)
end

subject.initialize_all_templates
end
end

describe ".setup" do
subject { ::Guard.setup }

Expand Down

0 comments on commit 3e854a9

Please sign in to comment.