guard-rspec 1.2.1 → 1.2.2
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.
- checksums.yaml +7 -0
- data/lib/guard/rspec/command.rb.orig +70 -0
- data/lib/guard/rspec/dsl.rb.orig +52 -0
- data/lib/guard/rspec/results.rb.orig +0 -0
- data/lib/guard/rspec/runner.rb +36 -5
- data/lib/guard/rspec/runner.rb.orig +118 -0
- data/lib/guard/rspec/templates/Guardfile.orig +52 -0
- data/lib/guard/rspec/version.rb +1 -1
- data/lib/guard/rspec/version.rb.orig +5 -0
- data/lib/guard/rspec_formatter.rb +113 -0
- data/lib/guard/rspec_formatter.rb.orig +116 -0
- metadata +24 -27
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 8b5d7c7623699fd71c39dc1e907b04b7a50600ca
|
|
4
|
+
data.tar.gz: 8acb79a0ea41075758dbb6ad22c9a4b2619140fa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 07d0e950425323cfb7198bee3566e923a24b07e342554776a51bb1a341f2b2d132ffecfde4b5b91e29f96012ae97d8f72af657d643d852de2e7973aa1a23a012
|
|
7
|
+
data.tar.gz: 364fa4dc0e0acf4d75e39df847f415080562f58fb70c937a27a85fc040fdb5e4c8be82a87e21f7436f9bf7c08e555e96e7d223af640727e72f4980fab3379b4c
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require "rspec/core"
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
require "guard/rspec"
|
|
5
|
+
|
|
6
|
+
module Guard
|
|
7
|
+
class RSpec < Plugin
|
|
8
|
+
class Command < String
|
|
9
|
+
FAILURE_EXIT_CODE = 2
|
|
10
|
+
|
|
11
|
+
attr_accessor :paths, :options
|
|
12
|
+
|
|
13
|
+
def initialize(paths, options = {})
|
|
14
|
+
@paths = paths
|
|
15
|
+
@options = options
|
|
16
|
+
super(_parts.join(" "))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def _parts
|
|
22
|
+
parts = [options[:cmd]]
|
|
23
|
+
parts << _visual_formatter
|
|
24
|
+
parts << _guard_formatter
|
|
25
|
+
parts << "--failure-exit-code #{FAILURE_EXIT_CODE}"
|
|
26
|
+
parts << options[:cmd_additional_args] || ""
|
|
27
|
+
|
|
28
|
+
parts << _paths(options).join(" ")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def _paths(options)
|
|
32
|
+
return paths unless chdir = options[:chdir]
|
|
33
|
+
paths.map { |path| path.sub(File.join(chdir, "/"), "") }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _visual_formatter
|
|
37
|
+
return if _cmd_include_formatter?
|
|
38
|
+
_rspec_formatters || "-f progress"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def _rspec_formatters
|
|
42
|
+
# RSpec::Core::ConfigurationOptions#parse_options method was renamed to
|
|
43
|
+
# #options in rspec-core v3.0.0.beta2 so call the first one if
|
|
44
|
+
# available. Fixes #249
|
|
45
|
+
config = ::RSpec::Core::ConfigurationOptions.new([])
|
|
46
|
+
config.parse_options if config.respond_to?(:parse_options)
|
|
47
|
+
formatters = config.options[:formatters] || nil
|
|
48
|
+
|
|
49
|
+
# RSpec's parser returns an array in the format
|
|
50
|
+
#
|
|
51
|
+
# [[formatter, output], ...],
|
|
52
|
+
#
|
|
53
|
+
# so match their format Construct a matching command line option,
|
|
54
|
+
# including output target
|
|
55
|
+
|
|
56
|
+
return formatters unless formatters
|
|
57
|
+
formatters.map { |entries| "-f #{entries.join " -o "}" }.join(" ")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def _cmd_include_formatter?
|
|
61
|
+
options[:cmd] =~ /(?:^|\s)(?:-f\s*|--format(?:=|\s+))([\w:]+)/
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def _guard_formatter
|
|
65
|
+
dir = Pathname.new(__FILE__).dirname.dirname
|
|
66
|
+
"-r #{dir + "rspec_formatter.rb"} -f Guard::RSpecFormatter"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require "ostruct"
|
|
2
|
+
|
|
3
|
+
require "guard/rspec"
|
|
4
|
+
|
|
5
|
+
module Guard
|
|
6
|
+
class RSpec < Plugin
|
|
7
|
+
class Dsl
|
|
8
|
+
def initialize(dsl)
|
|
9
|
+
@dsl = dsl
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def watch_spec_files_for(expr)
|
|
13
|
+
@dsl.send(:watch, expr) { |m| rspec.spec.(m[1]) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def rspec
|
|
17
|
+
@rspec ||= OpenStruct.new(to_s: "spec").tap do |rspec|
|
|
18
|
+
rspec.spec_dir = "spec"
|
|
19
|
+
rspec.spec = ->(m) { "#{rspec.spec_dir}/#{m}_spec.rb" }
|
|
20
|
+
rspec.spec_helper = "#{rspec.spec_dir}/spec_helper.rb"
|
|
21
|
+
rspec.spec_files = %r{^#{rspec.spec_dir}/.+_spec\.rb$}
|
|
22
|
+
rspec.spec_support = %r{^#{rspec.spec_dir}/support/(.+)\.rb$}
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ruby
|
|
27
|
+
# Ruby apps
|
|
28
|
+
@ruby || OpenStruct.new.tap do |ruby|
|
|
29
|
+
ruby.lib_files = %r{^(lib/.+)\.rb$}
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def rails(options = {})
|
|
34
|
+
# Rails example
|
|
35
|
+
@rails ||= OpenStruct.new.tap do |rails|
|
|
36
|
+
exts = options.dup.delete(:view_extensions) || %w(erb haml slim)
|
|
37
|
+
|
|
38
|
+
rails.app_files = %r{^app/(.+)\.rb$}
|
|
39
|
+
|
|
40
|
+
rails.views = %r{^app/(views/.+/[^/]*\.(?:#{exts * "|"}))$}
|
|
41
|
+
rails.view_dirs = %r{^app/views/(.+)/[^/]*\.(?:#{exts * "|"})$}
|
|
42
|
+
rails.layouts = %r{^app/layouts/(.+)/.*\.("#{exts * "|"}")$}
|
|
43
|
+
|
|
44
|
+
rails.controllers = %r{^app/controllers/(.+)_controller\.rb$}
|
|
45
|
+
rails.routes = "config/routes.rb"
|
|
46
|
+
rails.app_controller = "app/controllers/application_controller.rb"
|
|
47
|
+
rails.spec_helper = "#{rspec.spec_dir}/rails_helper.rb"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
File without changes
|
data/lib/guard/rspec/runner.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
require 'drb/drb'
|
|
2
|
+
require 'pathname'
|
|
3
|
+
|
|
4
|
+
require 'rspec/core' rescue LoadError
|
|
2
5
|
|
|
3
6
|
module Guard
|
|
4
7
|
class RSpec
|
|
@@ -60,7 +63,7 @@ module Guard
|
|
|
60
63
|
@rspec_class ||= case rspec_version
|
|
61
64
|
when 1
|
|
62
65
|
"Spec"
|
|
63
|
-
when 2
|
|
66
|
+
when 2, 3
|
|
64
67
|
"RSpec"
|
|
65
68
|
end
|
|
66
69
|
end
|
|
@@ -84,8 +87,24 @@ module Guard
|
|
|
84
87
|
arg_parts << options[:cli]
|
|
85
88
|
if @options[:notification]
|
|
86
89
|
arg_parts << parsed_or_default_formatter unless options[:cli] =~ formatter_regex
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
|
|
91
|
+
formatter_file = "(undefined)"
|
|
92
|
+
formatter_class_name = "(undefined)"
|
|
93
|
+
|
|
94
|
+
case rspec_version
|
|
95
|
+
when 1, 2
|
|
96
|
+
formatter_class_name = "Guard::RSpec::Formatter::Notification#{rspec_class}"
|
|
97
|
+
formatter_file = "rspec/formatters/notification_#{rspec_class.downcase}.rb"
|
|
98
|
+
when 3
|
|
99
|
+
formatter_class_name = "Guard::RSpecFormatter"
|
|
100
|
+
formatter_file = "rspec_formatter.rb"
|
|
101
|
+
else
|
|
102
|
+
fail "Guard::RSpec fatal error: UNKNOWN RSPEC VERSION: #{rspec_version.inspect}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
lib_guard = Pathname(__FILE__).dirname.dirname
|
|
106
|
+
arg_parts << "-r #{lib_guard + formatter_file}"
|
|
107
|
+
arg_parts << formatter_arg(formatter_class_name)
|
|
89
108
|
end
|
|
90
109
|
arg_parts << "--failure-exit-code #{FAILURE_EXIT_CODE}" if failure_exit_code_supported?
|
|
91
110
|
arg_parts << "-r turnip/rspec" if @options[:turnip]
|
|
@@ -94,6 +113,15 @@ module Guard
|
|
|
94
113
|
arg_parts.compact.join(' ')
|
|
95
114
|
end
|
|
96
115
|
|
|
116
|
+
def formatter_arg(formatter_name)
|
|
117
|
+
case rspec_version
|
|
118
|
+
when 1
|
|
119
|
+
"-f #{formatter_name}:/dev/null"
|
|
120
|
+
when 2, 3
|
|
121
|
+
"-f #{formatter_name} --out /dev/null"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
97
125
|
def rspec_command(paths, options)
|
|
98
126
|
cmd_parts = []
|
|
99
127
|
cmd_parts << "rvm #{@options[:rvm].join(',')} exec" if @options[:rvm].respond_to?(:join)
|
|
@@ -114,7 +142,8 @@ module Guard
|
|
|
114
142
|
end
|
|
115
143
|
|
|
116
144
|
def rspec_command_exited_with_an_exception?
|
|
117
|
-
|
|
145
|
+
return !$?.zero? unless failure_exit_code_supported?
|
|
146
|
+
$?.exitstatus != FAILURE_EXIT_CODE
|
|
118
147
|
end
|
|
119
148
|
|
|
120
149
|
# We can optimize this path by hitting up the drb server directly, circumventing the overhead
|
|
@@ -206,11 +235,13 @@ module Guard
|
|
|
206
235
|
end
|
|
207
236
|
|
|
208
237
|
def determine_rspec_version
|
|
238
|
+
Integer(::RSpec::Core::Version::STRING.split(".").first)
|
|
239
|
+
rescue NameError
|
|
209
240
|
if File.exist?("#{Dir.pwd}/spec/spec_helper.rb")
|
|
210
241
|
File.new("#{Dir.pwd}/spec/spec_helper.rb").read.include?("Spec::Runner") ? 1 : 2
|
|
211
242
|
elsif bundler_allowed?
|
|
212
243
|
ENV['BUNDLE_GEMFILE'] = "#{Dir.pwd}/Gemfile"
|
|
213
|
-
`bundle show rspec
|
|
244
|
+
/[\/ ]rspec-1\./ =~ `bundle show rspec 2>&1` ? 1 : 2
|
|
214
245
|
else
|
|
215
246
|
2
|
|
216
247
|
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require "guard/rspec/inspectors/factory"
|
|
2
|
+
require "guard/rspec/command"
|
|
3
|
+
require "guard/rspec/notifier"
|
|
4
|
+
|
|
5
|
+
module Guard
|
|
6
|
+
class RSpec < Plugin
|
|
7
|
+
class Runner
|
|
8
|
+
# NOTE: must match with const in RspecFormatter!
|
|
9
|
+
TEMPORARY_FILE_PATH ||= "tmp/rspec_guard_result"
|
|
10
|
+
|
|
11
|
+
attr_accessor :options, :inspector, :notifier
|
|
12
|
+
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
@options = options
|
|
15
|
+
@inspector = Inspectors::Factory.create(@options)
|
|
16
|
+
@notifier = Notifier.new(@options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run_all
|
|
20
|
+
paths = options[:spec_paths]
|
|
21
|
+
options = @options.merge(@options[:run_all])
|
|
22
|
+
return true if paths.empty?
|
|
23
|
+
Compat::UI.info(options[:message], reset: true)
|
|
24
|
+
_run(true, paths, options)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run(paths)
|
|
28
|
+
paths = inspector.paths(paths)
|
|
29
|
+
return true if paths.empty?
|
|
30
|
+
Compat::UI.info("Running: #{paths.join(" ")}", reset: true)
|
|
31
|
+
_run(false, paths, options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def reload
|
|
35
|
+
inspector.reload
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def _run(all, paths, options)
|
|
41
|
+
return unless _cmd_option_present(options)
|
|
42
|
+
command = Command.new(paths, options)
|
|
43
|
+
|
|
44
|
+
_without_bundler_env { Kernel.system(command) }.tap do |success|
|
|
45
|
+
_process_run_result(success, all)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def _without_bundler_env
|
|
50
|
+
if defined?(::Bundler)
|
|
51
|
+
::Bundler.with_clean_env { yield }
|
|
52
|
+
else
|
|
53
|
+
yield
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def _cmd_option_present(options)
|
|
58
|
+
return true if options[:cmd]
|
|
59
|
+
Compat::UI.error("No cmd option specified, unable to run specs!")
|
|
60
|
+
notifier.notify_failure
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def _command_success?(success)
|
|
65
|
+
return false if success.nil?
|
|
66
|
+
[Command::FAILURE_EXIT_CODE, 0].include?($CHILD_STATUS.exitstatus)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def _command_output
|
|
70
|
+
formatter_tmp_file = _tmp_file(options[:chdir])
|
|
71
|
+
lines = File.readlines(formatter_tmp_file)
|
|
72
|
+
summary = lines.first.strip
|
|
73
|
+
failed_paths = lines[1..11].map(&:strip).compact
|
|
74
|
+
|
|
75
|
+
[summary, failed_paths]
|
|
76
|
+
rescue
|
|
77
|
+
[nil, nil]
|
|
78
|
+
ensure
|
|
79
|
+
File.delete(formatter_tmp_file) if File.exist?(formatter_tmp_file)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def _open_launchy
|
|
83
|
+
return unless options[:launchy]
|
|
84
|
+
require "launchy"
|
|
85
|
+
pn = Pathname.new(options[:launchy])
|
|
86
|
+
::Launchy.open(options[:launchy]) if pn.exist?
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def _run_all_after_pass
|
|
90
|
+
return unless options[:all_after_pass]
|
|
91
|
+
run_all
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def _process_run_result(result, all)
|
|
95
|
+
unless _command_success?(result)
|
|
96
|
+
notifier.notify_failure
|
|
97
|
+
return
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
summary, failed_paths = _command_output
|
|
101
|
+
unless summary && failed_paths
|
|
102
|
+
notifier.notify_failure
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
inspector.failed(failed_paths)
|
|
107
|
+
notifier.notify(summary)
|
|
108
|
+
_open_launchy
|
|
109
|
+
|
|
110
|
+
_run_all_after_pass if !all && result
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def _tmp_file(chdir)
|
|
114
|
+
chdir ? File.join(chdir, TEMPORARY_FILE_PATH) : TEMPORARY_FILE_PATH
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
|
2
|
+
# rspec may be run, below are examples of the most common uses.
|
|
3
|
+
# * bundler: 'bundle exec rspec'
|
|
4
|
+
# * bundler binstubs: 'bin/rspec'
|
|
5
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
|
6
|
+
# installed the spring binstubs per the docs)
|
|
7
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
|
8
|
+
# * 'just' rspec: 'rspec'
|
|
9
|
+
|
|
10
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
|
11
|
+
require "guard/rspec/dsl"
|
|
12
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
|
13
|
+
|
|
14
|
+
# Feel free to open issues for suggestions and improvements
|
|
15
|
+
|
|
16
|
+
# RSpec files
|
|
17
|
+
rspec = dsl.rspec
|
|
18
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
|
19
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
|
20
|
+
watch(rspec.spec_files)
|
|
21
|
+
|
|
22
|
+
# Ruby files
|
|
23
|
+
ruby = dsl.ruby
|
|
24
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
|
25
|
+
|
|
26
|
+
# Rails files
|
|
27
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
|
28
|
+
dsl.watch_spec_files_for(rails.app_files)
|
|
29
|
+
dsl.watch_spec_files_for(rails.views)
|
|
30
|
+
|
|
31
|
+
watch(rails.controllers) do |m|
|
|
32
|
+
[
|
|
33
|
+
rspec.spec.("routing/#{m[1]}_routing"),
|
|
34
|
+
rspec.spec.("controllers/#{m[1]}_controller"),
|
|
35
|
+
rspec.spec.("acceptance/#{m[1]}")
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Rails config changes
|
|
40
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
|
41
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
|
42
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
|
43
|
+
|
|
44
|
+
# Capybara features specs
|
|
45
|
+
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
|
46
|
+
|
|
47
|
+
# Turnip features and steps
|
|
48
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
|
49
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
|
50
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/guard/rspec/version.rb
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# NOTE: This class only exists for RSpec and should not be used by
|
|
2
|
+
# other classes in this project!
|
|
3
|
+
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
|
|
7
|
+
#require "rspec"
|
|
8
|
+
require "rspec/core/formatters/base_formatter"
|
|
9
|
+
|
|
10
|
+
module Guard
|
|
11
|
+
class RSpecFormatter < ::RSpec::Core::Formatters::BaseFormatter
|
|
12
|
+
TEMPORARY_FILE_PATH ||= "tmp/rspec_guard_result"
|
|
13
|
+
|
|
14
|
+
def self.rspec_3?
|
|
15
|
+
::RSpec::Core::Version::STRING.split(".").first == "3"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if rspec_3?
|
|
19
|
+
::RSpec::Core::Formatters.register self, :dump_summary, :example_failed
|
|
20
|
+
|
|
21
|
+
def example_failed(failure)
|
|
22
|
+
examples.push failure.example
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def examples
|
|
26
|
+
@examples ||= []
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# rspec issue https://github.com/rspec/rspec-core/issues/793
|
|
31
|
+
def self.extract_spec_location(metadata)
|
|
32
|
+
root_metadata = metadata
|
|
33
|
+
location = metadata[:location]
|
|
34
|
+
|
|
35
|
+
until spec_path?(location)
|
|
36
|
+
metadata = metadata[:example_group]
|
|
37
|
+
|
|
38
|
+
unless metadata
|
|
39
|
+
STDERR.puts "no spec file found for #{root_metadata[:location]}"
|
|
40
|
+
return root_metadata[:location]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rspec issue https://github.com/rspec/rspec-core/issues/1243
|
|
44
|
+
location = (metadata[:location] || "").split(":").first
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
location
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.spec_path?(path)
|
|
51
|
+
path ||= ""
|
|
52
|
+
flags = File::FNM_PATHNAME | File::FNM_DOTMATCH
|
|
53
|
+
if File.const_defined?(:FNM_EXTGLOB) # ruby >= 2
|
|
54
|
+
flags |= File::FNM_EXTGLOB
|
|
55
|
+
end
|
|
56
|
+
pattern = ::RSpec.configuration.pattern
|
|
57
|
+
path = path.sub(/:\d+\z/, "")
|
|
58
|
+
path = Pathname.new(path).cleanpath.to_s
|
|
59
|
+
File.fnmatch(pattern, path, flags)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def dump_summary(*args)
|
|
63
|
+
return write_summary(*args) unless self.class.rspec_3?
|
|
64
|
+
|
|
65
|
+
notification = args[0]
|
|
66
|
+
write_summary(
|
|
67
|
+
notification.duration,
|
|
68
|
+
notification.example_count,
|
|
69
|
+
notification.failure_count,
|
|
70
|
+
notification.pending_count
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
# Write summary to temporary file for runner
|
|
77
|
+
def write_summary(duration, total, failures, pending)
|
|
78
|
+
_write do |f|
|
|
79
|
+
f.puts _message(total, failures, pending, duration)
|
|
80
|
+
f.puts _failed_paths.join("\n") if failures > 0
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def _write(&block)
|
|
85
|
+
file = File.expand_path(TEMPORARY_FILE_PATH)
|
|
86
|
+
FileUtils.mkdir_p(File.dirname(file))
|
|
87
|
+
File.open(file, "w", &block)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def _failed_paths
|
|
91
|
+
klass = self.class
|
|
92
|
+
failed = examples.select { |example| _status_failed?(example) }
|
|
93
|
+
failed.map { |e| klass.extract_spec_location(e.metadata) }.sort.uniq
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def _message(example_count, failure_count, pending_count, duration)
|
|
97
|
+
message = "#{example_count} examples, #{failure_count} failures"
|
|
98
|
+
if pending_count > 0
|
|
99
|
+
message << " (#{pending_count} pending)"
|
|
100
|
+
end
|
|
101
|
+
message << " in #{duration.round(4)} seconds"
|
|
102
|
+
message
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def _status_failed?(example)
|
|
106
|
+
if self.class.rspec_3?
|
|
107
|
+
example.execution_result.status.to_s == "failed"
|
|
108
|
+
else
|
|
109
|
+
example.execution_result[:status].to_s == "failed"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# NOTE: This class only exists for RSpec and should not be used by
|
|
2
|
+
# other classes in this project!
|
|
3
|
+
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "fileutils"
|
|
6
|
+
|
|
7
|
+
require "rspec"
|
|
8
|
+
require "rspec/core/formatters/base_formatter"
|
|
9
|
+
|
|
10
|
+
module Guard
|
|
11
|
+
class RSpecFormatter < ::RSpec::Core::Formatters::BaseFormatter
|
|
12
|
+
TEMPORARY_FILE_PATH ||= "tmp/rspec_guard_result"
|
|
13
|
+
|
|
14
|
+
def self.rspec_3?
|
|
15
|
+
::RSpec::Core::Version::STRING.split(".").first == "3"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if rspec_3?
|
|
19
|
+
::RSpec::Core::Formatters.register self, :dump_summary, :example_failed
|
|
20
|
+
|
|
21
|
+
def example_failed(failure)
|
|
22
|
+
examples.push failure.example
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def examples
|
|
26
|
+
@examples ||= []
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# rspec issue https://github.com/rspec/rspec-core/issues/793
|
|
31
|
+
def self.extract_spec_location(metadata)
|
|
32
|
+
root_metadata = metadata
|
|
33
|
+
location = metadata[:location]
|
|
34
|
+
|
|
35
|
+
until spec_path?(location)
|
|
36
|
+
metadata = metadata[:example_group]
|
|
37
|
+
|
|
38
|
+
unless metadata
|
|
39
|
+
STDERR.puts "no spec file found for #{root_metadata[:location]}"
|
|
40
|
+
return root_metadata[:location]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rspec issue https://github.com/rspec/rspec-core/issues/1243
|
|
44
|
+
location = (metadata[:location] || "").split(":").first
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
location
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.spec_path?(path)
|
|
51
|
+
path ||= ""
|
|
52
|
+
flags = File::FNM_PATHNAME | File::FNM_DOTMATCH
|
|
53
|
+
if File.const_defined?(:FNM_EXTGLOB) # ruby >= 2
|
|
54
|
+
flags |= File::FNM_EXTGLOB
|
|
55
|
+
end
|
|
56
|
+
pattern = ::RSpec.configuration.pattern
|
|
57
|
+
path = path.sub(/:\d+\z/, "")
|
|
58
|
+
path = Pathname.new(path).cleanpath.to_s
|
|
59
|
+
File.fnmatch(pattern, path, flags)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def dump_summary(*args)
|
|
63
|
+
if self.class.rspec_3?
|
|
64
|
+
notification = args[0]
|
|
65
|
+
write_summary(
|
|
66
|
+
notification.duration,
|
|
67
|
+
notification.example_count,
|
|
68
|
+
notification.failure_count,
|
|
69
|
+
notification.pending_count
|
|
70
|
+
)
|
|
71
|
+
else
|
|
72
|
+
write_summary(*args)
|
|
73
|
+
end
|
|
74
|
+
rescue
|
|
75
|
+
# nothing really we can do, at least don"t kill the test runner
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Write summary to temporary file for runner
|
|
79
|
+
def write_summary(duration, total, failures, pending)
|
|
80
|
+
_write do |f|
|
|
81
|
+
f.puts _message(total, failures, pending, duration)
|
|
82
|
+
f.puts _failed_paths.join("\n") if failures > 0
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def _write(&block)
|
|
89
|
+
file = File.expand_path(TEMPORARY_FILE_PATH)
|
|
90
|
+
FileUtils.mkdir_p(File.dirname(file))
|
|
91
|
+
File.open(file, "w", &block)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def _failed_paths
|
|
95
|
+
failed = examples.select do |e|
|
|
96
|
+
if self.class.rspec_3?
|
|
97
|
+
e.execution_result.status.to_s == "failed"
|
|
98
|
+
else
|
|
99
|
+
e.execution_result[:status].to_s == "failed"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
klass = self.class
|
|
104
|
+
failed.map { |e| klass.extract_spec_location(e.metadata) }.sort.uniq
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def _message(example_count, failure_count, pending_count, duration)
|
|
108
|
+
message = "#{example_count} examples, #{failure_count} failures"
|
|
109
|
+
if pending_count > 0
|
|
110
|
+
message << " (#{pending_count} pending)"
|
|
111
|
+
end
|
|
112
|
+
message << " in #{duration.round(4)} seconds"
|
|
113
|
+
message
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
metadata
CHANGED
|
@@ -1,62 +1,55 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: guard-rspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 1.2.2
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Thibaud Guillaume-Gentil
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 2015-06-12 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: guard
|
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
|
17
|
-
none: false
|
|
18
16
|
requirements:
|
|
19
|
-
- -
|
|
17
|
+
- - ">="
|
|
20
18
|
- !ruby/object:Gem::Version
|
|
21
19
|
version: '1.1'
|
|
22
20
|
type: :runtime
|
|
23
21
|
prerelease: false
|
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
-
none: false
|
|
26
23
|
requirements:
|
|
27
|
-
- -
|
|
24
|
+
- - ">="
|
|
28
25
|
- !ruby/object:Gem::Version
|
|
29
26
|
version: '1.1'
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
|
31
28
|
name: bundler
|
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
30
|
requirements:
|
|
35
|
-
- - ~>
|
|
31
|
+
- - "~>"
|
|
36
32
|
- !ruby/object:Gem::Version
|
|
37
33
|
version: '1.0'
|
|
38
34
|
type: :development
|
|
39
35
|
prerelease: false
|
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
-
none: false
|
|
42
37
|
requirements:
|
|
43
|
-
- - ~>
|
|
38
|
+
- - "~>"
|
|
44
39
|
- !ruby/object:Gem::Version
|
|
45
40
|
version: '1.0'
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
|
47
42
|
name: rspec
|
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
|
49
|
-
none: false
|
|
50
44
|
requirements:
|
|
51
|
-
- - ~>
|
|
45
|
+
- - "~>"
|
|
52
46
|
- !ruby/object:Gem::Version
|
|
53
47
|
version: '2.11'
|
|
54
48
|
type: :development
|
|
55
49
|
prerelease: false
|
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
-
none: false
|
|
58
51
|
requirements:
|
|
59
|
-
- - ~>
|
|
52
|
+
- - "~>"
|
|
60
53
|
- !ruby/object:Gem::Version
|
|
61
54
|
version: '2.11'
|
|
62
55
|
description: Guard::RSpec automatically run your specs (much like autotest).
|
|
@@ -66,41 +59,45 @@ executables: []
|
|
|
66
59
|
extensions: []
|
|
67
60
|
extra_rdoc_files: []
|
|
68
61
|
files:
|
|
62
|
+
- LICENSE
|
|
63
|
+
- README.md
|
|
64
|
+
- lib/guard/rspec.rb
|
|
65
|
+
- lib/guard/rspec/command.rb.orig
|
|
66
|
+
- lib/guard/rspec/dsl.rb.orig
|
|
69
67
|
- lib/guard/rspec/formatter.rb
|
|
70
68
|
- lib/guard/rspec/formatters/notification_rspec.rb
|
|
71
69
|
- lib/guard/rspec/formatters/notification_spec.rb
|
|
72
70
|
- lib/guard/rspec/inspector.rb
|
|
71
|
+
- lib/guard/rspec/results.rb.orig
|
|
73
72
|
- lib/guard/rspec/runner.rb
|
|
73
|
+
- lib/guard/rspec/runner.rb.orig
|
|
74
74
|
- lib/guard/rspec/templates/Guardfile
|
|
75
|
+
- lib/guard/rspec/templates/Guardfile.orig
|
|
75
76
|
- lib/guard/rspec/version.rb
|
|
76
|
-
- lib/guard/rspec.rb
|
|
77
|
-
-
|
|
78
|
-
-
|
|
77
|
+
- lib/guard/rspec/version.rb.orig
|
|
78
|
+
- lib/guard/rspec_formatter.rb
|
|
79
|
+
- lib/guard/rspec_formatter.rb.orig
|
|
79
80
|
homepage: http://rubygems.org/gems/guard-rspec
|
|
80
81
|
licenses: []
|
|
82
|
+
metadata: {}
|
|
81
83
|
post_install_message:
|
|
82
84
|
rdoc_options: []
|
|
83
85
|
require_paths:
|
|
84
86
|
- lib
|
|
85
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
-
none: false
|
|
87
88
|
requirements:
|
|
88
|
-
- -
|
|
89
|
+
- - ">="
|
|
89
90
|
- !ruby/object:Gem::Version
|
|
90
91
|
version: '0'
|
|
91
|
-
segments:
|
|
92
|
-
- 0
|
|
93
|
-
hash: -2503119173622208473
|
|
94
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
|
-
none: false
|
|
96
93
|
requirements:
|
|
97
|
-
- -
|
|
94
|
+
- - ">="
|
|
98
95
|
- !ruby/object:Gem::Version
|
|
99
96
|
version: 1.3.6
|
|
100
97
|
requirements: []
|
|
101
98
|
rubyforge_project: guard-rspec
|
|
102
|
-
rubygems_version:
|
|
99
|
+
rubygems_version: 2.4.7
|
|
103
100
|
signing_key:
|
|
104
|
-
specification_version:
|
|
101
|
+
specification_version: 4
|
|
105
102
|
summary: Guard gem for RSpec
|
|
106
103
|
test_files: []
|