Skip to content

Commit

Permalink
version 0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mordaroso committed Aug 10, 2012
1 parent bc548ba commit 4508be7
Show file tree
Hide file tree
Showing 15 changed files with 611 additions and 72 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
@@ -0,0 +1,2 @@
rvm:
- 1.9.3
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -2,3 +2,7 @@ source 'https://rubygems.org'

# Specify your gem's dependencies in guard-motion.gemspec
gemspec

platforms :ruby do
gem 'rb-readline'
end
9 changes: 9 additions & 0 deletions Guardfile
@@ -0,0 +1,9 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard 'rspec', :version => 2 do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
end

102 changes: 86 additions & 16 deletions README.md
@@ -1,29 +1,99 @@
# Guard::Motion
# Guard::Motion [![Build Status](https://secure.travis-ci.org/mordaroso/guard-motion.png?branch=master)](http://travis-ci.org/mordaroso/guard-motion)

TODO: Write a gem description
Motion guard allows to automatically & intelligently launch [RubyMotion](http://www.rubymotion.com/) specs when files are modified.

## Installation
## Install

Add this line to your application's Gemfile:
Please be sure to have [Guard](https://github.com/guard/guard) installed before continue.

gem 'guard-motion'
Install the gem:

And then execute:
```
$ gem install guard-motion
```

$ bundle
Add it to your Gemfile (inside development group):

Or install it yourself as:
``` ruby
gem 'guard-motion'
```

$ gem install guard-motion
Add guard definition to your Guardfile by running this command:

```
$ guard init motion
```

Make sure Guard::Motion is loaded in your project Rakefile:

```
require 'guard/motion'
```

## Usage

TODO: Write usage instructions here
Please read [Guard usage doc](https://github.com/guard/guard#readme)

## Guardfile

Motion guard can be really adapted to all kind of project setup.

### Typical RubyMotion App

``` ruby
guard 'motion' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
end
```

### Typical RubyMotion library

``` ruby
guard 'motion' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/[^/]+/(.+)\.rb$}) { |m| "./spec/#{m[1]}_spec.rb" }
end
```

Please read [Guard doc](https://github.com/guard/guard#readme) for more information about the Guardfile DSL.

## Options

By default, Guard::Motion will only look for spec files within `spec` in your project root. You can configure Guard::Motion to look in additional paths by using the `:spec_paths` option:

``` ruby
guard 'motion', :spec_paths => ["spec", "vendor/other_project/spec"] do
# ...
end
```
If you have only one path to look, you can configure `:spec_paths` option with a string:

``` ruby
guard 'motion', :spec_paths => "test" do
# ...
end
```

### List of available options:

``` ruby
:bundler => false # use "bundle exec" to run the rake command, default: true
:binstubs => true # use "bin/rake" to run the rake command (takes precedence over :bundle), default: false
:notification => false # display Growl (or Libnotify) notification after the specs are done running, default: true
:all_after_pass => false # run all specs after changed specs pass, default: true
:all_on_start => false # run all the specs at startup, default: true
:keep_failed => false # keep failed specs until they pass, default: true
:spec_paths => ["spec"] # specify an array of paths that contain spec files
```

You can also use a custom binstubs directory using `:binstubs => 'some-dir'`.

Development
-----------

## Contributing
* Source hosted at [GitHub](https://github.com/mordaroso/guard-motion)
* Report issues/Questions/Feature requests on [GitHub Issues](https://github.com/mordaroso/guard-motion/issues)

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
you make.
5 changes: 2 additions & 3 deletions guard-motion.gemspec
Expand Up @@ -4,11 +4,9 @@ require File.expand_path('../lib/guard/motion/version', __FILE__)
Gem::Specification.new do |gem|
gem.authors = ["mordaroso"]
gem.email = ["mordaroso@gmail.com"]
gem.description = %q{TODO: Write a gem description}
gem.summary = %q{TODO: Write a gem summary}
gem.homepage = 'http://rubygems.org/gems/guard-motion'
gem.summary = 'Guard gem for RubyMotion'
gem.description = 'Guard::Motion automatically runs RubyMotion specs'
gem.description = 'Guard::Motion automatically run your specs (much like autotest).'

gem.files = `git ls-files`.split($\)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
Expand All @@ -18,6 +16,7 @@ Gem::Specification.new do |gem|
gem.version = Guard::MotionVersion::VERSION

gem.add_dependency 'guard', '>= 1.1.0'
gem.add_dependency 'rake', '>= 0.9'

gem.add_development_dependency 'bundler', '~> 1.1.0'
gem.add_development_dependency 'rspec', '~> 2.10'
Expand Down
86 changes: 86 additions & 0 deletions lib/guard/motion.rb
@@ -0,0 +1,86 @@
require 'guard'
require 'guard/guard'

require 'guard/motion/tasks'

module Guard
class Motion < Guard
autoload :Runner, 'guard/motion/runner'

# Initialize a Guard.
# @param [Array<Guard::Watcher>] watchers the Guard file watchers
# @param [Hash] options the custom Guard options
def initialize(watchers = [], options = {})
super
@options = {
:all_after_pass => true,
:all_on_start => true,
:keep_failed => true,
:spec_paths => ["spec"]
}.merge(options)
@last_failed = false
@failed_paths = []

@runner = Runner.new(@options)
end

# Call once when Guard starts. Please override initialize method to init stuff.
# @raise [:task_has_failed] when start has failed
def start
UI.info "Guard::Motion is running"
run_all if @options[:all_on_start]
end

# Called when `reload|r|z + enter` is pressed.
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
# @raise [:task_has_failed] when reload has failed
def reload
@failed_paths = []
end

# Called when just `enter` is pressed
# This method should be principally used for long action like running all specs/tests/...
# @raise [:task_has_failed] when run_all has failed
def run_all
passed = @runner.run

unless @last_failed = !passed
@failed_paths = []
else
throw :task_has_failed
end
end

# Called on file(s) modifications that the Guard watches.
# @param [Array<String>] paths the changes files or paths
# @raise [:task_has_failed] when run_on_change has failed
def run_on_changes(paths)
paths += @failed_paths if @options[:keep_failed]

if passed = @runner.run(paths)
remove_failed(paths)

# run all the specs if the run before this one failed
if @last_failed && @options[:all_after_pass]
@last_failed = false
run_all
end
else
@last_failed = true
add_failed(paths)

throw :task_has_failed
end
end

private
def remove_failed(paths)
@failed_paths -= paths if @options[:keep_failed]
end

def add_failed(paths)
@failed_paths += paths if @options[:keep_failed]
end

end
end
93 changes: 93 additions & 0 deletions lib/guard/motion/runner.rb
@@ -0,0 +1,93 @@
module Guard
class Motion
class Runner

def initialize(options = {})
@options = {
:bundler => true,
:binstubs => false,
:notification => true,
}.merge(options)
end

def run(paths = nil, options = {})
if paths.nil?
paths = all_spec_paths
message = options[:message] || "Running all specs"
else
message = options[:message] || "Running: #{paths.join(' ')}"
end

UI.info(message, :reset => true)

run_via_shell rake_command(paths)
end

def rake_executable
@rake_executable ||= begin
binstubs? ? "#{binstubs}/rake" : 'rake'
end
end

def rake_command(paths)
cmd_parts = []
cmd_parts << "bundle exec" if bundle_exec?
cmd_parts << rake_executable
cmd_parts << "spec:specific[\"#{paths.join(';')}\"]"
cmd_parts.compact.join(' ')
end

def run_via_shell(command)
success = system(command)

if @options[:notification] && !success
Notifier.notify("Failed", :title => "Motion spec results", :image => :failed, :priority => 2)
end

success
end

def all_spec_paths
@options[:spec_paths].map { |spec_path|
Dir.glob("#{spec_path}/**/*_spec.rb")
}.flatten
end

def bundler_allowed?
if @bundler_allowed.nil?
@bundler_allowed = File.exist?("#{Dir.pwd}/Gemfile")
else
@bundler_allowed
end
end

def bundler?
if @bundler.nil?
@bundler = bundler_allowed? && @options[:bundler]
else
@bundler
end
end

def binstubs?
if @binstubs.nil?
@binstubs = !!@options[:binstubs]
else
@binstubs
end
end

def binstubs
if @options[:binstubs] == true
"bin"
else
@options[:binstubs]
end
end

def bundle_exec?
bundler? && !binstubs?
end
end
end
end
21 changes: 21 additions & 0 deletions lib/guard/motion/tasks.rb
@@ -0,0 +1,21 @@
# include rake task spec:specific only if included in a rake file
if Kernel.const_defined?(:Rake)
desc "Run a specific list of motion specs"
namespace :spec do
task :specific, :files do |task, args|
files = args[:files]

if files.nil? || files.empty?
puts "No spec file passed to the task."
puts "Please run the task like this: `rake spec:specific[./spec/app_delegate_spec.rb;./spec/other_spec.rb]`"
exit 1
end

App.config.spec_mode = true
spec_files = App.config.spec_files.select{|file_path| !(file_path =~ /_spec.rb$/)}
spec_files += files.split(';')
App.config.instance_variable_set("@spec_files", spec_files)
Rake::Task["simulator"].invoke
end
end
end
4 changes: 2 additions & 2 deletions lib/guard/motion/templates/Guardfile
Expand Up @@ -2,8 +2,8 @@ guard 'motion' do
watch(%r{^spec/.+_spec\.rb$})

# RubyMotion App example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.+)\.rb$}) { |m| "./spec/#{m[1]}_spec.rb" }

# RubyMotion gem example
watch(%r{^lib/[^/]+/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^lib/[^/]+/(.+)\.rb$}) { |m| "./spec/#{m[1]}_spec.rb" }
end
2 changes: 1 addition & 1 deletion lib/guard/motion/version.rb
@@ -1,5 +1,5 @@
module Guard
module MotionVersion
VERSION = "0.0.1"
VERSION = "0.1.0"
end
end

0 comments on commit 4508be7

Please sign in to comment.