-
-
Notifications
You must be signed in to change notification settings - Fork 763
/
rake_task.rb
187 lines (158 loc) · 5.48 KB
/
rake_task.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
require 'rake'
require 'rake/tasklib'
require 'rbconfig'
module RSpec
module Core
# Rspec rake task
#
# @see Rakefile
class RakeTask < ::Rake::TaskLib
include ::Rake::DSL if defined?(::Rake::DSL)
# Default path to the rspec executable
DEFAULT_RSPEC_PATH = File.expand_path('../../../../exe/rspec', __FILE__)
# Default pattern for spec files.
DEFAULT_PATTERN = 'spec/**{,/*/**}/*_spec.rb'
# Name of task.
#
# default:
# :spec
attr_accessor :name
# Files matching this pattern will be loaded.
#
# default:
# 'spec/**{,/*/**}/*_spec.rb'
attr_accessor :pattern
# Files matching this pattern will be excluded.
#
# default:
# 'spec/**/*_spec.rb'
attr_accessor :exclude_pattern
# Whether or not to fail Rake when an error occurs (typically when examples fail).
#
# default:
# true
attr_accessor :fail_on_error
# A message to print to stderr when there are failures.
attr_accessor :failure_message
# Use verbose output. If this is set to true, the task will print the
# executed spec command to stdout.
#
# default:
# true
attr_accessor :verbose
# Command line options to pass to ruby.
#
# default:
# nil
attr_accessor :ruby_opts
# Path to rspec
#
# default:
# 'rspec'
attr_accessor :rspec_path
# Command line options to pass to rspec.
#
# default:
# nil
attr_accessor :rspec_opts
def initialize(*args, &task_block)
@name = args.shift || :spec
@ruby_opts = nil
@rspec_opts = nil
@verbose = true
@fail_on_error = true
@rspec_path = DEFAULT_RSPEC_PATH
@pattern = DEFAULT_PATTERN
define(args, &task_block)
end
# @private
def run_task(verbose)
command = spec_command
begin
puts command if verbose
success = system(command)
rescue
puts failure_message if failure_message
end
return unless fail_on_error && !success
$stderr.puts "#{command} failed"
exit $?.exitstatus
end
private
# @private
def define(args, &task_block)
desc "Run RSpec code examples" unless ::Rake.application.last_comment
task name, *args do |_, task_args|
RakeFileUtils.__send__(:verbose, verbose) do
task_block.call(*[self, task_args].slice(0, task_block.arity)) if task_block
run_task verbose
end
end
end
def file_inclusion_specification
if ENV['SPEC']
FileList[ ENV['SPEC']].sort
elsif String === pattern && !File.exist?(pattern)
"--pattern #{escape pattern}"
else
# Before RSpec 3.1, we used `FileList` to get the list of matched files, and
# then pass that along to the `rspec` command. Starting with 3.1, we prefer to
# pass along the pattern as-is to the `rspec` command, for 3 reasons:
#
# * It's *much* less verbose to pass one `--pattern` option than a long list of files.
# * It ensures `task.pattern` and `--pattern` have the same behavior.
# * It fixes a bug, where `task.pattern = pattern_that_matches_no_files` would run
# *all* files because it would cause no pattern or file args to get passed to `rspec`,
# which causes all files to get run.
#
# However, `FileList` is *far* more flexible than the `--pattern` option. Specifically, it
# supports individual files and directories, as well as arrays of files, directories and globs,
# as well as other `FileList` objects.
#
# For backwards compatibility, we have to fall back to using FileList if the user has passed
# a `pattern` option that will not work with `--pattern`.
#
# TODO: consider deprecating support for this and removing it in RSpec 4.
FileList[pattern].sort.map { |file| escape file }
end
end
# Manaully comparing because in 3.2 we have RSpec::Support::OS.windows?
# but in 3.1 we don't and requiring rspec/world would be weighty here.
if RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/
def escape(shell_command)
"'#{shell_command.gsub("'", "\'")}'"
end
else
require 'shellwords'
def escape(shell_command)
shell_command.shellescape
end
end
def file_exclusion_specification
" --exclude-pattern #{escape exclude_pattern}" if exclude_pattern
end
def spec_command
cmd_parts = []
cmd_parts << RUBY
cmd_parts << ruby_opts
cmd_parts << rspec_load_path
cmd_parts << rspec_path
cmd_parts << file_inclusion_specification
cmd_parts << file_exclusion_specification
cmd_parts << rspec_opts
cmd_parts.flatten.reject(&blank).join(" ")
end
def blank
lambda { |s| s.nil? || s == "" }
end
def rspec_load_path
@rspec_load_path ||= begin
core_and_support = $LOAD_PATH.grep(
/#{File::SEPARATOR}rspec-(core|support)[^#{File::SEPARATOR}]*#{File::SEPARATOR}lib/
).uniq
"-I#{core_and_support.map { |file| escape file }.join(File::PATH_SEPARATOR)}"
end
end
end
end
end