guard-rspec 0.6.0 → 0.7.0
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/README.md +22 -15
- data/lib/guard/rspec.rb +28 -21
- data/lib/guard/rspec/formatter.rb +1 -1
- data/lib/guard/rspec/inspector.rb +12 -7
- data/lib/guard/rspec/runner.rb +156 -58
- data/lib/guard/rspec/version.rb +1 -1
- metadata +9 -9
data/README.md
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
-
Guard::RSpec ](http://travis-ci.org/guard/guard-rspec)
|
3
2
|
|
4
3
|
RSpec guard allows to automatically & intelligently launch specs when files are modified.
|
5
4
|
|
6
|
-
* Compatible with RSpec 1.x & RSpec 2.x (>= 2.4 needed for the notification feature)
|
7
|
-
* Tested against Ruby 1.8.7, 1.9.2,
|
5
|
+
* Compatible with RSpec 1.x & RSpec 2.x (>= 2.4 needed for the notification feature).
|
6
|
+
* Tested against Ruby 1.8.7, 1.9.2, 1.9.3, REE and the latest versions of JRuby & Rubinius.
|
8
7
|
|
9
|
-
Install
|
10
|
-
-------
|
8
|
+
## Install
|
11
9
|
|
12
10
|
Please be sure to have [Guard](https://github.com/guard/guard) installed before continue.
|
13
11
|
|
14
12
|
Install the gem:
|
15
13
|
|
16
|
-
|
14
|
+
```
|
15
|
+
$ gem install guard-rspec
|
16
|
+
```
|
17
17
|
|
18
18
|
Add it to your Gemfile (inside development group):
|
19
19
|
|
@@ -25,15 +25,15 @@ end
|
|
25
25
|
|
26
26
|
Add guard definition to your Guardfile by running this command:
|
27
27
|
|
28
|
-
|
28
|
+
```
|
29
|
+
$ guard init rspec
|
30
|
+
```
|
29
31
|
|
30
|
-
Usage
|
31
|
-
-----
|
32
|
+
## Usage
|
32
33
|
|
33
34
|
Please read [Guard usage doc](https://github.com/guard/guard#readme)
|
34
35
|
|
35
|
-
Guardfile
|
36
|
-
---------
|
36
|
+
## Guardfile
|
37
37
|
|
38
38
|
RSpec guard can be really adapted to all kind of projects.
|
39
39
|
|
@@ -64,8 +64,7 @@ end
|
|
64
64
|
|
65
65
|
Please read [Guard doc](https://github.com/guard/guard#readme) for more information about the Guardfile DSL.
|
66
66
|
|
67
|
-
Options
|
68
|
-
-------
|
67
|
+
## Options
|
69
68
|
|
70
69
|
By default, Guard::RSpec automatically detect your RSpec version (with the `spec_helper.rb` syntax or with Bundler) but you can force the version with the `:version` option:
|
71
70
|
|
@@ -99,7 +98,7 @@ end
|
|
99
98
|
```
|
100
99
|
|
101
100
|
|
102
|
-
Former `:color`, `:drb`, `:fail_fast` and `:formatter` options are
|
101
|
+
Former `:color`, `:drb`, `:fail_fast` and `:formatter` options are deprecated and have no effect anymore.
|
103
102
|
|
104
103
|
### List of available options:
|
105
104
|
|
@@ -117,6 +116,14 @@ Former `:color`, `:drb`, `:fail_fast` and `:formatter` options are thus deprecat
|
|
117
116
|
:spec_paths => ["spec"] # specify an array of paths that contain spec files
|
118
117
|
```
|
119
118
|
|
119
|
+
### DRb mode
|
120
|
+
|
121
|
+
When you specify `--drb` within `:cli`, guard-rspec will circumvent the `rspec` command line tool by
|
122
|
+
directly communicating with the RSpec DRb server. This avoids the extra overhead incurred by your
|
123
|
+
shell, bundler and loading RSpec's environment just to send a DRb message. It shaves off a
|
124
|
+
second or two before the specs start to run; they should run almost immediately.
|
125
|
+
|
126
|
+
|
120
127
|
Notification
|
121
128
|
------------
|
122
129
|
|
data/lib/guard/rspec.rb
CHANGED
@@ -6,23 +6,20 @@ module Guard
|
|
6
6
|
autoload :Runner, 'guard/rspec/runner'
|
7
7
|
autoload :Inspector, 'guard/rspec/inspector'
|
8
8
|
|
9
|
-
def initialize(watchers=[], options={})
|
9
|
+
def initialize(watchers = [], options = {})
|
10
10
|
super
|
11
11
|
@options = {
|
12
12
|
:all_after_pass => true,
|
13
13
|
:all_on_start => true,
|
14
14
|
:keep_failed => true,
|
15
|
-
:spec_paths => ["spec"]
|
16
|
-
|
15
|
+
:spec_paths => ["spec"],
|
16
|
+
:run_all => {}
|
17
|
+
}.merge(options)
|
17
18
|
@last_failed = false
|
18
19
|
@failed_paths = []
|
19
20
|
|
20
|
-
@
|
21
|
-
@
|
22
|
-
|
23
|
-
@runner.set_rspec_version(options)
|
24
|
-
@inspector.excluded = @options[:exclude]
|
25
|
-
@inspector.spec_paths = @options[:spec_paths]
|
21
|
+
@inspector = Inspector.new(@options)
|
22
|
+
@runner = Runner.new(@options)
|
26
23
|
end
|
27
24
|
|
28
25
|
# Call once when guard starts
|
@@ -32,10 +29,9 @@ module Guard
|
|
32
29
|
end
|
33
30
|
|
34
31
|
def run_all
|
35
|
-
passed = @runner.run(options[:spec_paths], options
|
32
|
+
passed = @runner.run(@options[:spec_paths], @options[:run_all].merge(:message => 'Running all specs'))
|
36
33
|
|
37
|
-
@last_failed = !passed
|
38
|
-
if passed
|
34
|
+
unless @last_failed = !passed
|
39
35
|
@failed_paths = []
|
40
36
|
else
|
41
37
|
throw :task_has_failed
|
@@ -49,22 +45,33 @@ module Guard
|
|
49
45
|
def run_on_change(paths)
|
50
46
|
paths += @failed_paths if @options[:keep_failed]
|
51
47
|
paths = @inspector.clean(paths)
|
52
|
-
passed = @runner.run(paths, options)
|
53
48
|
|
54
|
-
if passed
|
55
|
-
|
56
|
-
|
57
|
-
# run all the specs if the
|
58
|
-
|
49
|
+
if passed = @runner.run(paths)
|
50
|
+
remove_failed(paths)
|
51
|
+
|
52
|
+
# run all the specs if the run before this one failed
|
53
|
+
if @last_failed && @options[:all_after_pass]
|
54
|
+
@last_failed = false
|
55
|
+
run_all
|
56
|
+
end
|
59
57
|
else
|
60
|
-
# remember failed paths for the next change
|
61
|
-
@failed_paths += paths if @options[:keep_failed]
|
62
|
-
# track whether the changed specs failed for the next change
|
63
58
|
@last_failed = true
|
59
|
+
add_failed(paths)
|
60
|
+
|
64
61
|
throw :task_has_failed
|
65
62
|
end
|
66
63
|
end
|
67
64
|
|
65
|
+
private
|
66
|
+
|
67
|
+
def remove_failed(paths)
|
68
|
+
@failed_paths -= paths if @options[:keep_failed]
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_failed(paths)
|
72
|
+
@failed_paths += paths if @options[:keep_failed]
|
73
|
+
end
|
74
|
+
|
68
75
|
end
|
69
76
|
end
|
70
77
|
|
@@ -1,20 +1,26 @@
|
|
1
1
|
module Guard
|
2
2
|
class RSpec
|
3
3
|
class Inspector
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
self.excluded = options[:exclude]
|
7
|
+
self.spec_paths = options[:spec_paths]
|
8
|
+
end
|
9
|
+
|
4
10
|
def excluded
|
5
11
|
@excluded || []
|
6
12
|
end
|
7
13
|
|
8
|
-
def excluded=(
|
9
|
-
@excluded = Dir[
|
14
|
+
def excluded=(pattern)
|
15
|
+
@excluded = Dir[pattern.to_s]
|
10
16
|
end
|
11
17
|
|
12
18
|
def spec_paths
|
13
19
|
@spec_paths || []
|
14
20
|
end
|
15
21
|
|
16
|
-
def spec_paths=(
|
17
|
-
@spec_paths = Array(
|
22
|
+
def spec_paths=(paths)
|
23
|
+
@spec_paths = Array(paths)
|
18
24
|
end
|
19
25
|
|
20
26
|
def clean(paths)
|
@@ -42,15 +48,14 @@ module Guard
|
|
42
48
|
|
43
49
|
def spec_folder?(path)
|
44
50
|
path.match(%r{^(#{spec_paths.join("|")})[^\.]*$})
|
45
|
-
# path.match(%r{^spec[^\.]*$})
|
46
51
|
end
|
47
52
|
|
48
53
|
def spec_files
|
49
|
-
@spec_files ||= spec_paths.collect { |path| Dir[File.join(path, "**", "*_spec.rb")] }.flatten
|
54
|
+
@spec_files ||= spec_paths.collect { |path| Dir[File.join(path, "**{,/*/**}", "*_spec.rb")] }.flatten
|
50
55
|
end
|
51
56
|
|
52
57
|
def feature_files
|
53
|
-
@feature_files ||= spec_paths.collect { |path| Dir[File.join(path, "**", "*.feature")] }.flatten
|
58
|
+
@feature_files ||= spec_paths.collect { |path| Dir[File.join(path, "**{,/*/**}", "*.feature")] }.flatten
|
54
59
|
end
|
55
60
|
|
56
61
|
def clear_spec_files_list_after
|
data/lib/guard/rspec/runner.rb
CHANGED
@@ -3,104 +3,202 @@ module Guard
|
|
3
3
|
class Runner
|
4
4
|
attr_reader :rspec_version
|
5
5
|
|
6
|
-
|
6
|
+
FAILURE_EXIT_CODE = 2
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = {
|
10
|
+
:bundler => true,
|
11
|
+
:binstubs => false,
|
12
|
+
:rvm => nil,
|
13
|
+
:cli => nil,
|
14
|
+
:notification => true
|
15
|
+
}.merge(options)
|
16
|
+
|
17
|
+
deprecations_warnings
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(paths, options = {})
|
7
21
|
return false if paths.empty?
|
22
|
+
|
8
23
|
message = options[:message] || "Running: #{paths.join(' ')}"
|
9
24
|
UI.info(message, :reset => true)
|
10
|
-
system(rspec_command(paths, options))
|
11
25
|
|
12
|
-
|
13
|
-
|
26
|
+
options = @options.merge(options)
|
27
|
+
|
28
|
+
if drb_used?
|
29
|
+
run_via_drb(paths, options)
|
30
|
+
else
|
31
|
+
run_via_shell(paths, options)
|
14
32
|
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def rspec_version
|
36
|
+
@rspec_version ||= @options[:version] || determine_rspec_version
|
37
|
+
end
|
15
38
|
|
16
|
-
|
39
|
+
def rspec_executable
|
40
|
+
@rspec_executable ||= begin
|
41
|
+
exec = rspec_class.downcase
|
42
|
+
binstubs? ? "bin/#{exec}" : exec
|
43
|
+
end
|
17
44
|
end
|
18
45
|
|
19
|
-
def
|
20
|
-
@
|
46
|
+
def failure_exit_code_supported?
|
47
|
+
@failure_exit_code_supported ||= begin
|
48
|
+
cmd_parts = []
|
49
|
+
cmd_parts << "bundle exec" if bundler?
|
50
|
+
cmd_parts << rspec_executable
|
51
|
+
cmd_parts << "--help"
|
52
|
+
`#{cmd_parts.join(' ')}`.include? "--failure-exit-code"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def rspec_class
|
57
|
+
@rspec_class ||= case rspec_version
|
58
|
+
when 1
|
59
|
+
"Spec"
|
60
|
+
when 2
|
61
|
+
"RSpec"
|
62
|
+
end
|
21
63
|
end
|
22
64
|
|
23
65
|
private
|
24
66
|
|
25
|
-
def
|
26
|
-
|
67
|
+
def rspec_arguments(paths, options)
|
68
|
+
arg_parts = []
|
69
|
+
arg_parts << options[:cli]
|
70
|
+
arg_parts << "-f progress" if !options[:cli] || options[:cli].split(/[\s=]/).none? { |w| %w[-f --format].include?(w) }
|
71
|
+
if @options[:notification]
|
72
|
+
arg_parts << "-r #{File.dirname(__FILE__)}/formatters/notification_#{rspec_class.downcase}.rb"
|
73
|
+
arg_parts << "-f Guard::RSpec::Formatter::Notification#{rspec_class}#{rspec_version == 1 ? ":" : " --out "}/dev/null"
|
74
|
+
end
|
75
|
+
arg_parts << "--failure-exit-code #{FAILURE_EXIT_CODE}" if failure_exit_code_supported?
|
76
|
+
arg_parts << paths.join(' ')
|
77
|
+
|
78
|
+
arg_parts.compact.join(' ')
|
79
|
+
end
|
27
80
|
|
81
|
+
def rspec_command(paths, options)
|
28
82
|
cmd_parts = []
|
29
|
-
cmd_parts << "rvm #{options[:rvm].join(',')} exec" if options[:rvm].
|
30
|
-
cmd_parts << "bundle exec" if
|
31
|
-
cmd_parts <<
|
32
|
-
cmd_parts <<
|
33
|
-
cmd_parts << "-f progress" if options[:cli].nil? || !options[:cli].split(/[\s=]/).any? { |w| %w[-f --format].include?(w) }
|
34
|
-
cmd_parts << "-r #{File.dirname(__FILE__)}/formatters/notification_#{rspec_class.downcase}.rb -f Guard::RSpec::Formatter::Notification#{rspec_class}#{rspec_version == 1 ? ":" : " --out "}/dev/null" if options[:notification] != false
|
35
|
-
cmd_parts << "--failure-exit-code #{failure_exit_code}" if failure_exit_code_supported?(options)
|
36
|
-
cmd_parts << paths.join(' ')
|
83
|
+
cmd_parts << "rvm #{@options[:rvm].join(',')} exec" if @options[:rvm].respond_to?(:join)
|
84
|
+
cmd_parts << "bundle exec" if bundler?
|
85
|
+
cmd_parts << rspec_executable
|
86
|
+
cmd_parts << rspec_arguments(paths, options)
|
37
87
|
|
38
|
-
cmd_parts.join(' ')
|
88
|
+
cmd_parts.compact.join(' ')
|
39
89
|
end
|
40
90
|
|
41
|
-
def
|
42
|
-
|
91
|
+
def run_via_shell(paths, options)
|
92
|
+
success = system(rspec_command(paths, options))
|
93
|
+
|
94
|
+
if @options[:notification] && !drb_used? && !success && rspec_command_exited_with_an_exception?
|
95
|
+
Notifier.notify("Failed", :title => "RSpec results", :image => :failed, :priority => 2)
|
96
|
+
end
|
97
|
+
|
98
|
+
success
|
43
99
|
end
|
44
100
|
|
45
|
-
def
|
46
|
-
|
101
|
+
def rspec_command_exited_with_an_exception?
|
102
|
+
failure_exit_code_supported? && $?.exitstatus != FAILURE_EXIT_CODE
|
47
103
|
end
|
48
104
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
`#{cmd_parts.join(' ')}`.include? "--failure-exit-code"
|
105
|
+
# We can optimize this path by hitting up the drb server directly, circumventing the overhead
|
106
|
+
# of the user's shell, bundler and ruby environment.
|
107
|
+
def run_via_drb(paths, options)
|
108
|
+
require "shellwords"
|
109
|
+
argv = rspec_arguments(paths, options).shellsplit
|
110
|
+
|
111
|
+
# The user can specify --drb-port for rspec, we need to honor it.
|
112
|
+
if idx = argv.index("--drb-port")
|
113
|
+
port = argv[idx + 1].to_i
|
59
114
|
end
|
115
|
+
port = ENV["RSPEC_DRB"] || 8989 unless port && port > 0
|
116
|
+
|
117
|
+
ret = drb_service(port.to_i).run(argv, $stderr, $stdout)
|
118
|
+
ret == 0
|
119
|
+
rescue DRb::DRbConnError
|
120
|
+
# Fall back to the shell runner; we don't want to mangle the environment!
|
121
|
+
run_via_shell(paths, options)
|
60
122
|
end
|
61
123
|
|
62
|
-
def
|
63
|
-
|
124
|
+
def drb_used?
|
125
|
+
if @drb_used.nil?
|
126
|
+
@drb_used = @options[:cli] && @options[:cli].include?('--drb')
|
127
|
+
else
|
128
|
+
@drb_used
|
129
|
+
end
|
64
130
|
end
|
65
131
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
132
|
+
# RSpec 1 & 2 use the same DRb call signature, and we can avoid loading a large chunk of rspec
|
133
|
+
# just to let DRb know what to do.
|
134
|
+
#
|
135
|
+
# For reference:
|
136
|
+
#
|
137
|
+
# * RSpec 1: https://github.com/myronmarston/rspec-1/blob/master/lib/spec/runner/drb_command_line.rb
|
138
|
+
# * RSpec 2: https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/drb_command_line.rb
|
139
|
+
def drb_service(port)
|
140
|
+
require "drb/drb"
|
141
|
+
|
142
|
+
# Make sure we have a listener running
|
143
|
+
unless @drb_listener_running
|
144
|
+
begin
|
145
|
+
DRb.start_service("druby://localhost:0")
|
146
|
+
rescue SocketError, Errno::EADDRNOTAVAIL
|
147
|
+
DRb.start_service("druby://:0")
|
148
|
+
end
|
149
|
+
|
150
|
+
@drb_listener_running = true
|
151
|
+
end
|
152
|
+
|
153
|
+
@drb_services ||= {}
|
154
|
+
@drb_services[port.to_i] ||= DRbObject.new_with_uri("druby://127.0.0.1:#{port}")
|
155
|
+
end
|
156
|
+
|
157
|
+
def bundler_allowed?
|
158
|
+
if @bundler_allowed.nil?
|
159
|
+
@bundler_allowed = File.exist?("#{Dir.pwd}/Gemfile")
|
73
160
|
else
|
74
|
-
|
161
|
+
@bundler_allowed
|
75
162
|
end
|
76
163
|
end
|
77
164
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
"RSpec"
|
165
|
+
def bundler?
|
166
|
+
if @bundler.nil?
|
167
|
+
@bundler = bundler_allowed? && @options[:bundler]
|
168
|
+
else
|
169
|
+
@bundler
|
84
170
|
end
|
85
171
|
end
|
86
172
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
options[:binstubs] == true && options[:bundler] != false ? "bin/rspec" : "rspec"
|
173
|
+
def binstubs?
|
174
|
+
if @binstubs.nil?
|
175
|
+
@binstubs = bundler? && @options[:binstubs]
|
176
|
+
else
|
177
|
+
@binstubs
|
93
178
|
end
|
94
179
|
end
|
95
180
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
181
|
+
def determine_rspec_version
|
182
|
+
if File.exist?("#{Dir.pwd}/spec/spec_helper.rb")
|
183
|
+
File.new("#{Dir.pwd}/spec/spec_helper.rb").read.include?("Spec::Runner") ? 1 : 2
|
184
|
+
elsif bundler_allowed?
|
185
|
+
ENV['BUNDLE_GEMFILE'] = "#{Dir.pwd}/Gemfile"
|
186
|
+
`bundle show rspec`.include?("/rspec-1.") ? 1 : 2
|
187
|
+
else
|
188
|
+
2
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def deprecations_warnings
|
193
|
+
[:color, :drb, [:fail_fast, "fail-fast"], [:formatter, "format"]].each do |option|
|
194
|
+
key, value = option.is_a?(Array) ? option : [option, option.to_s]
|
195
|
+
if @options.key?(key)
|
196
|
+
@options.delete(key)
|
100
197
|
UI.info %{DEPRECATION WARNING: The :#{key} option is deprecated. Pass standard command line argument "--#{value}" to RSpec with the :cli option.}
|
101
198
|
end
|
102
199
|
end
|
103
200
|
end
|
201
|
+
|
104
202
|
end
|
105
203
|
end
|
106
204
|
end
|
data/lib/guard/rspec/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guard-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: guard
|
16
|
-
requirement: &
|
16
|
+
requirement: &70179267450520 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.10.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70179267450520
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bundler
|
27
|
-
requirement: &
|
27
|
+
requirement: &70179267449820 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70179267449820
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &70179267449300 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '2.7'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70179267449300
|
47
47
|
description: Guard::RSpec automatically run your specs (much like autotest).
|
48
48
|
email:
|
49
49
|
- thibaud@thibaud.me
|
@@ -81,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
81
|
version: 1.3.6
|
82
82
|
requirements: []
|
83
83
|
rubyforge_project: guard-rspec
|
84
|
-
rubygems_version: 1.8.
|
84
|
+
rubygems_version: 1.8.16
|
85
85
|
signing_key:
|
86
86
|
specification_version: 3
|
87
87
|
summary: Guard gem for RSpec
|