/
rake_task.rb
172 lines (143 loc) · 5.33 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
require 'rake'
require 'rake/tasklib'
require 'rspec/support/ruby_features'
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. Defaults to `:spec`.
attr_accessor :name
# Files matching this pattern will be loaded.
# Defaults to `'spec/**{,/*/**}/*_spec.rb'`.
attr_accessor :pattern
# Files matching this pattern will be excluded.
# Defaults to `nil`.
attr_accessor :exclude_pattern
# Whether or not to fail Rake when an error occurs (typically when
# examples fail). Defaults to `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. Defaults to `true`.
attr_accessor :verbose
# Command line options to pass to ruby. Defaults to `nil`.
attr_accessor :ruby_opts
# Path to RSpec. Defaults to the absolute path to the
# rspec binary from the loaded rspec-core gem.
attr_accessor :rspec_path
# Command line options to pass to RSpec. Defaults to `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" if verbose
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
if RSpec::Support::OS.windows?
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