respec 0.0.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/.gitignore +1 -0
- data/CHANGELOG +3 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.markdown +63 -0
- data/Rakefile +1 -0
- data/bin/respec +11 -0
- data/lib/respec.rb +5 -0
- data/lib/respec/app.rb +117 -0
- data/lib/respec/formatter.rb +11 -0
- data/lib/respec/version.rb +11 -0
- data/respec.gemspec +17 -0
- data/spec/integration_spec.rb +49 -0
- data/spec/respec/app_spec.rb +91 -0
- data/spec/spec_helper.rb +6 -0
- metadata +76 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/*.gem
|
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) George Ogata
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
## Respec
|
2
|
+
|
3
|
+
Provides a command, `respec`, which wraps `rspec`, and records your
|
4
|
+
failing examples for easy rerunning.
|
5
|
+
|
6
|
+
## How?
|
7
|
+
|
8
|
+
Run your specs:
|
9
|
+
|
10
|
+
respec
|
11
|
+
|
12
|
+
3 fail. Rerun just the 3 failures like this:
|
13
|
+
|
14
|
+
respec f
|
15
|
+
|
16
|
+
Need to debug failure #1? Pop a `debugger` in your code, and rerun it
|
17
|
+
like this:
|
18
|
+
|
19
|
+
respec 1
|
20
|
+
|
21
|
+
This will just rerun failure 1. Once it's passing, rerun the 3 failing
|
22
|
+
examples again:
|
23
|
+
|
24
|
+
respec f
|
25
|
+
|
26
|
+
1 is now fixed, but 2 and 3 are still failing - `respec f` will now
|
27
|
+
only run failures 2 and 3 again.
|
28
|
+
|
29
|
+
## How it works
|
30
|
+
|
31
|
+
All that's happening is the list of failed examples is being recorded
|
32
|
+
in a file (`.respec_failures`). The `f` argument means "run these
|
33
|
+
recorded failures only." A numeric argument like `1` means "just run
|
34
|
+
that failure."
|
35
|
+
|
36
|
+
The list of failed examples is always updated _except_ when selecting
|
37
|
+
which failures to rerun with a number (more than one number can also
|
38
|
+
be given, incidentally).
|
39
|
+
|
40
|
+
## Other tricks
|
41
|
+
|
42
|
+
You can pass `respec` file or directory names, just like
|
43
|
+
`rspec`. However, you can also just specify example names on the
|
44
|
+
command line:
|
45
|
+
|
46
|
+
respec 'My example name'
|
47
|
+
|
48
|
+
If the argument doesn't name an existing file, it's assumed to be an
|
49
|
+
example name.
|
50
|
+
|
51
|
+
There are a few other shortcuts. Do `respec --help` to see them all.
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
* [Bug reports](https://github.com/oggy/respec/issues)
|
56
|
+
* [Source](https://github.com/oggy/respec)
|
57
|
+
* Patches: Fork on Github, send pull request.
|
58
|
+
* Include tests where practical.
|
59
|
+
* Leave the version alone, or bump it in a separate commit.
|
60
|
+
|
61
|
+
## Copyright
|
62
|
+
|
63
|
+
Copyright (c) George Ogata. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ritual'
|
data/bin/respec
ADDED
data/lib/respec.rb
ADDED
data/lib/respec/app.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
module Respec
|
2
|
+
class App
|
3
|
+
def initialize(*args)
|
4
|
+
if (i = args.index('--'))
|
5
|
+
@args = args.slice!(0...i)
|
6
|
+
@raw_args = args[1..-1]
|
7
|
+
else
|
8
|
+
@args = args
|
9
|
+
@raw_args = []
|
10
|
+
end
|
11
|
+
@formatter = 'progress'
|
12
|
+
@output_failures = true
|
13
|
+
process_args
|
14
|
+
end
|
15
|
+
|
16
|
+
def command
|
17
|
+
@command ||= ['rspec'] + formatter_args + generated_args + raw_args
|
18
|
+
end
|
19
|
+
|
20
|
+
def formatter_args
|
21
|
+
if @output_failures
|
22
|
+
formatter_path = File.expand_path('formatter.rb', File.dirname(__FILE__))
|
23
|
+
['--require', formatter_path, '--format', 'Respec::Formatter', '--out', failures_path, '--format', @formatter]
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :generated_args, :raw_args
|
30
|
+
|
31
|
+
class << self
|
32
|
+
attr_accessor :failures_path
|
33
|
+
end
|
34
|
+
self.failures_path = ENV['RESPEC_FAILURES'] || File.expand_path("~/.respec_failures")
|
35
|
+
|
36
|
+
def help_only?
|
37
|
+
@help_only
|
38
|
+
end
|
39
|
+
|
40
|
+
def help
|
41
|
+
<<-EOS.gsub(/^ *\|/, '')
|
42
|
+
|USAGE: respec RESPEC-ARGS ... [ -- RSPEC-ARGS ... ]
|
43
|
+
|
|
44
|
+
|Run rspec recording failed examples for easy rerunning later.
|
45
|
+
|
|
46
|
+
|RESPEC-ARGS may consist of:
|
47
|
+
|
|
48
|
+
| f Rerun all failed examples
|
49
|
+
| <integer> Rerun only the n-th failure
|
50
|
+
| s Output specdoc format, instead of progress
|
51
|
+
| c Output context diffs
|
52
|
+
| <file name> Run specs in these files
|
53
|
+
| <other> Run only examples matching this pattern
|
54
|
+
| --help This! (Also 'help'.)
|
55
|
+
|
|
56
|
+
|RSPEC-ARGS may follow a '--' argument, and are passed
|
57
|
+
|directly to rspec.
|
58
|
+
|
|
59
|
+
|More info: http://github.com/oggy/respec
|
60
|
+
EOS
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def process_args
|
66
|
+
args = []
|
67
|
+
files = []
|
68
|
+
@args.each do |arg|
|
69
|
+
if File.exist?(arg)
|
70
|
+
files << arg
|
71
|
+
elsif arg =~ /\A(--)?help\z/
|
72
|
+
@help_only = true
|
73
|
+
elsif arg == 'f'
|
74
|
+
if File.exist?(failures_path)
|
75
|
+
if failures.empty?
|
76
|
+
abort "No specs failed!"
|
77
|
+
else
|
78
|
+
failures.each do |line|
|
79
|
+
args << line.strip
|
80
|
+
end
|
81
|
+
end
|
82
|
+
else
|
83
|
+
warn "no fail file - ignoring 'f' argument"
|
84
|
+
end
|
85
|
+
elsif arg == 's'
|
86
|
+
@formatter = 'specdoc'
|
87
|
+
elsif arg == 'c'
|
88
|
+
args << '--diff' << 'context'
|
89
|
+
elsif arg =~ /\A\d+\z/
|
90
|
+
i = Integer(arg)
|
91
|
+
if (failure = failures[i - 1])
|
92
|
+
args << failure
|
93
|
+
@output_failures = false
|
94
|
+
else
|
95
|
+
warn "invalid failure: #{i} for (1..#{failures.size})"
|
96
|
+
end
|
97
|
+
else
|
98
|
+
args << '--example' << arg.gsub(/[$]/, '\\\\\\0')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
@generated_args = args + files
|
102
|
+
end
|
103
|
+
|
104
|
+
def failures_path
|
105
|
+
self.class.failures_path
|
106
|
+
end
|
107
|
+
|
108
|
+
def failures
|
109
|
+
@failures ||=
|
110
|
+
if File.exist?(failures_path)
|
111
|
+
File.read(failures_path).split(/\n/)
|
112
|
+
else
|
113
|
+
[]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/respec.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
$:.unshift File.expand_path('lib', File.dirname(__FILE__))
|
2
|
+
require 'respec/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'respec'
|
6
|
+
gem.version = Respec::VERSION
|
7
|
+
gem.authors = ['George Ogata']
|
8
|
+
gem.email = ['george.ogata@gmail.com']
|
9
|
+
gem.summary = "Rerun failing RSpec examples easily."
|
10
|
+
gem.homepage = 'http://github.com/oggy/respec'
|
11
|
+
|
12
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
|
16
|
+
gem.add_development_dependency 'ritual', '~> 0.4.0'
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
describe Respec do
|
5
|
+
CONFIG = (Object.const_defined?(:RbConfig) ? RbConfig : Config)::CONFIG
|
6
|
+
def respec(args)
|
7
|
+
ruby = File.join(CONFIG['bindir'], CONFIG['ruby_install_name'])
|
8
|
+
respec = "#{ROOT}/bin/respec"
|
9
|
+
output = `RESPEC_FAILURES=#{TMP}/failures.txt #{ruby} -I #{ROOT}/lib #{respec} #{args} 2>&1`
|
10
|
+
[$?, output]
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_spec(params)
|
14
|
+
num_failures = params[:num_failures] or
|
15
|
+
raise ArgumentError, "expected :num_failures parameter"
|
16
|
+
|
17
|
+
source = "describe 'test' do\n"
|
18
|
+
(0...2).map do |i|
|
19
|
+
if i < num_failures
|
20
|
+
source << " it('#{i}') { 1.should == 2 }\n"
|
21
|
+
else
|
22
|
+
source << " it('#{i}') {}\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
source << "end"
|
26
|
+
open(spec_path, 'w') { |f| f.puts source }
|
27
|
+
end
|
28
|
+
|
29
|
+
def spec_path
|
30
|
+
"#{TMP}/test_spec.rb"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should let you rerun failing specs until they all pass" do
|
34
|
+
make_spec(num_failures: 2)
|
35
|
+
status, output = respec(spec_path)
|
36
|
+
status.should_not be_success
|
37
|
+
output.should include('2 examples, 2 failures')
|
38
|
+
|
39
|
+
make_spec(num_failures: 1)
|
40
|
+
status, output = respec("#{spec_path} f")
|
41
|
+
status.should_not be_success
|
42
|
+
output.should include('2 examples, 1 failure')
|
43
|
+
|
44
|
+
make_spec(num_failures: 0)
|
45
|
+
status, output = respec("#{spec_path} f")
|
46
|
+
status.should be_success
|
47
|
+
output.should include('1 example, 0 failures')
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
describe Respec::App do
|
6
|
+
FORMATTER_PATH = File.expand_path("#{ROOT}/lib/respec/formatter.rb", File.dirname(__FILE__))
|
7
|
+
FAIL_PATH = "#{TMP}/failures.txt"
|
8
|
+
|
9
|
+
Respec::App.failures_path = FAIL_PATH
|
10
|
+
|
11
|
+
def make_failures_file(*examples)
|
12
|
+
open Respec::App.failures_path, 'w' do |file|
|
13
|
+
examples.each do |example|
|
14
|
+
file.puts example
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#generated_args" do
|
20
|
+
it "should run with --context if 'c' is given" do
|
21
|
+
app = Respec::App.new('c')
|
22
|
+
app.generated_args.should == ['--diff', 'context']
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should run all failures if 'f' is given" do
|
26
|
+
make_failures_file 'a.rb:1', 'b.rb:2'
|
27
|
+
app = Respec::App.new('f')
|
28
|
+
app.generated_args.should == ['a.rb:1', 'b.rb:2']
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should run the n-th failure if a numeric argument 'n' is given" do
|
32
|
+
make_failures_file 'a.rb:1', 'b.rb:2'
|
33
|
+
app = Respec::App.new('2')
|
34
|
+
app.generated_args.should == ['b.rb:2']
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should interpret existing file names as file name arguments" do
|
38
|
+
FileUtils.touch "#{TMP}/existing.rb"
|
39
|
+
app = Respec::App.new("#{TMP}/existing.rb")
|
40
|
+
app.generated_args.should == ["#{TMP}/existing.rb"]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should treat other arguments as example names" do
|
44
|
+
FileUtils.touch "#{TMP}/FILE"
|
45
|
+
app = Respec::App.new("#{TMP}/FILE")
|
46
|
+
app.generated_args.should == ["#{TMP}/FILE"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#formatter_args" do
|
51
|
+
it "should include the respec and progress formatters by default" do
|
52
|
+
app = Respec::App.new
|
53
|
+
app.formatter_args.should == ['--require', FORMATTER_PATH, '--format', 'Respec::Formatter', '--out', FAIL_PATH, '--format', 'progress']
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should include '--format specdoc' if an 's' argument is given" do
|
57
|
+
app = Respec::App.new('s')
|
58
|
+
app.formatter_args.should == ['--require', FORMATTER_PATH, '--format', 'Respec::Formatter', '--out', FAIL_PATH, '--format', 'specdoc']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should update the stored failures if no args are given" do
|
62
|
+
app = Respec::App.new
|
63
|
+
app.formatter_args.should == ['--require', FORMATTER_PATH, '--format', 'Respec::Formatter', '--out', FAIL_PATH, '--format', 'progress']
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should update the stored failures if 'f' is used" do
|
67
|
+
app = Respec::App.new('f')
|
68
|
+
app.formatter_args.should == ['--require', FORMATTER_PATH, '--format', 'Respec::Formatter', '--out', FAIL_PATH, '--format', 'progress']
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should not update the stored failures if a numeric argument is given" do
|
72
|
+
app = Respec::App.new('1')
|
73
|
+
app.formatter_args.should == []
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#raw_args" do
|
78
|
+
it "should pass arguments after '--' directly to rspec" do
|
79
|
+
app = Respec::App.new('--', '--blah')
|
80
|
+
app.raw_args.should == ['--blah']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "#command" do
|
85
|
+
it "should combine all the args" do
|
86
|
+
make_failures_file 'a.rb:1'
|
87
|
+
app = Respec::App.new('f', '--', '-t', 'TAG')
|
88
|
+
app.command.should == ['rspec', '--require', FORMATTER_PATH, '--format', 'Respec::Formatter', '--out', FAIL_PATH, '--format', 'progress', 'a.rb:1', '-t', 'TAG']
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: respec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- George Ogata
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ritual
|
16
|
+
requirement: &70131397136780 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.4.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70131397136780
|
25
|
+
description:
|
26
|
+
email:
|
27
|
+
- george.ogata@gmail.com
|
28
|
+
executables:
|
29
|
+
- respec
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- CHANGELOG
|
35
|
+
- Gemfile
|
36
|
+
- LICENSE
|
37
|
+
- README.markdown
|
38
|
+
- Rakefile
|
39
|
+
- bin/respec
|
40
|
+
- lib/respec.rb
|
41
|
+
- lib/respec/app.rb
|
42
|
+
- lib/respec/formatter.rb
|
43
|
+
- lib/respec/version.rb
|
44
|
+
- respec.gemspec
|
45
|
+
- spec/integration_spec.rb
|
46
|
+
- spec/respec/app_spec.rb
|
47
|
+
- spec/spec_helper.rb
|
48
|
+
homepage: http://github.com/oggy/respec
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.10
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Rerun failing RSpec examples easily.
|
72
|
+
test_files:
|
73
|
+
- spec/integration_spec.rb
|
74
|
+
- spec/respec/app_spec.rb
|
75
|
+
- spec/spec_helper.rb
|
76
|
+
has_rdoc:
|