Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit c8a45e9

Browse files
committed
Merge pull request #1289 from rspec/fix-spec-helper-files-to-run
Fix for #1280
2 parents 5317c30 + b342ffb commit c8a45e9

File tree

11 files changed

+156
-85
lines changed

11 files changed

+156
-85
lines changed

features/command_line/init.feature

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,36 @@ Feature: --init option
2222
Given I have a brand new project with no files
2323
And I have run `rspec --init`
2424
When I accept the recommended settings by removing `=begin` and `=end` from `spec/spec_helper.rb`
25-
And I create a spec file with the following content:
26-
"""
25+
And I create "spec/addition_spec.rb" with the following content:
26+
"""ruby
2727
RSpec.describe "Addition" do
2828
it "works" do
2929
expect(1 + 1).to eq(2)
3030
end
3131
end
3232
"""
33-
And I run `rspec`
33+
And I create "spec/subtraction_spec.rb" with the following content:
34+
"""ruby
35+
RSpec.describe "Subtraction" do
36+
it "works" do
37+
expect(1 - 1).to eq(0)
38+
end
39+
end
40+
"""
41+
42+
When I run `rspec`
43+
Then the examples should all pass
44+
And the output should not contain:
45+
"""
46+
Addition
47+
works
48+
"""
49+
50+
When I run `rspec spec/addition_spec.rb`
3451
Then the examples should all pass
52+
And the output should contain:
53+
"""
54+
Addition
55+
works
56+
"""
3557

features/step_definitions/additional_cli_steps.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
end
7474
end
7575

76-
When /^I create a spec file with the following content:$/ do |content|
77-
write_file("spec/example_spec.rb", content)
76+
When /^I create "([^"]*)" with the following content:$/ do |file_name, content|
77+
write_file(file_name, content)
7878
end
7979

lib/rspec/core/command_line.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ class CommandLine
44
def initialize(options, configuration=RSpec::configuration, world=RSpec::world)
55
if Array === options
66
options = ConfigurationOptions.new(options)
7-
options.parse_options
87
end
98
@options = options
109
@configuration = configuration

lib/rspec/core/configuration.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def treat_symbols_as_metadata_keys_with_true_values=(value)
231231
# @private
232232
add_setting :include_or_extend_modules
233233
# @private
234-
add_setting :files_to_run
234+
attr_writer :files_to_run
235235
# @private
236236
add_setting :expecting_with_rspec
237237
# @private
@@ -248,7 +248,7 @@ def initialize
248248
@expectation_frameworks = []
249249
@include_or_extend_modules = []
250250
@mock_framework = nil
251-
@files_to_run = []
251+
@files_or_directories_to_run = []
252252
@color = false
253253
@pattern = '**/*_spec.rb'
254254
@failure_exit_code = 1
@@ -620,7 +620,12 @@ def profile_examples
620620
def files_or_directories_to_run=(*files)
621621
files = files.flatten
622622
files << default_path if (command == 'rspec' || Runner.running_in_drb?) && default_path && files.empty?
623-
self.files_to_run = get_files_to_run(files)
623+
@files_or_directories_to_run = files
624+
@files_to_run = nil
625+
end
626+
627+
def files_to_run
628+
@files_to_run ||= get_files_to_run(@files_or_directories_to_run)
624629
end
625630

626631
# Creates a method that delegates to `example` including the submitted
@@ -897,7 +902,7 @@ def safe_include(mod, host)
897902
end
898903

899904
# @private
900-
def setup_load_path_and_require(paths)
905+
def requires=(paths)
901906
directories = ['lib', default_path].select { |p| File.directory? p }
902907
RSpec::Core::RubyProject.add_to_load_path(*directories)
903908
paths.each {|path| require path}

lib/rspec/core/configuration_options.rb

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ module RSpec
55
module Core
66
# @private
77
class ConfigurationOptions
8-
attr_reader :options
9-
108
def initialize(args)
119
@args = args.map {|a|
1210
a.sub("default_path", "default-path").sub("line_number", "line-number")
@@ -16,20 +14,17 @@ def initialize(args)
1614
def configure(config)
1715
config.filter_manager = filter_manager
1816

19-
config.libs = options[:libs] || []
20-
config.setup_load_path_and_require(options[:requires] || [])
21-
2217
process_options_into config
2318
load_formatters_into config
2419
end
2520

26-
def parse_options
27-
@options = (file_options << command_line_options << env_options).
21+
def options
22+
@options ||= (file_options << command_line_options << env_options).
2823
each {|opts|
2924
filter_manager.include opts.delete(:inclusion_filter) if opts.has_key?(:inclusion_filter)
3025
filter_manager.exclude opts.delete(:exclusion_filter) if opts.has_key?(:exclusion_filter)
3126
}.
32-
inject {|h, opts|
27+
inject(:libs => [], :requires => []) {|h, opts|
3328
h.merge(opts) {|k, oldval, newval|
3429
[:libs, :requires].include?(k) ? oldval + newval : newval
3530
}
@@ -51,23 +46,44 @@ def filter_manager
5146
:line_numbers, :full_description, :full_backtrace, :tty
5247
].to_set
5348

54-
UNPROCESSABLE_OPTIONS = [:libs, :formatters, :requires].to_set
49+
UNPROCESSABLE_OPTIONS = [:formatters].to_set
5550

5651
def force?(key)
5752
!UNFORCED_OPTIONS.include?(key)
5853
end
5954

60-
def order(keys, *ordered)
61-
ordered.reverse.each do |key|
55+
def order(keys)
56+
OPTIONS_ORDER.reverse.each do |key|
6257
keys.unshift(key) if keys.delete(key)
6358
end
6459
keys
6560
end
6661

62+
OPTIONS_ORDER = [
63+
# load paths depend on nothing, but must be set before `requires`
64+
# to support load-path-relative requires.
65+
:libs,
66+
67+
# `files_or_directories_to_run` uses `default_path` so it must be
68+
# set before it.
69+
:default_path,
70+
71+
# must be set before `requires` to support checking `config.files_to_run`
72+
# from within `spec_helper.rb` when a `-rspec_helper` option is used.
73+
:files_or_directories_to_run,
74+
75+
# In general, we want to require the specified files as early as possible.
76+
# The `--require` option is specifically intended to allow early requires.
77+
# For later requires, they can just put the require in their spec files, but
78+
# `--require` provides a unique opportunity for users to instruct RSpec to
79+
# load an extension file early for maximum flexibility.
80+
:requires
81+
]
82+
6783
def process_options_into(config)
6884
opts = options.reject { |k, _| UNPROCESSABLE_OPTIONS.include? k }
6985

70-
order(opts.keys, :default_path, :pattern).each do |key|
86+
order(opts.keys).each do |key|
7187
force?(key) ? config.force(key => opts[key]) : config.__send__("#{key}=", opts[key])
7288
end
7389
end

lib/rspec/core/runner.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ def self.trap_interrupt
8787
def self.run(args, err=$stderr, out=$stdout)
8888
trap_interrupt
8989
options = ConfigurationOptions.new(args)
90-
options.parse_options
9190

9291
if options.options[:drb]
9392
require 'rspec/core/drb_command_line'

spec/rspec/core/command_line_spec.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module RSpec::Core
3333
it "assigns ConfigurationOptions built from Array of options to @options" do
3434
config_options = ConfigurationOptions.new(%w[--color])
3535
command_line = CommandLine.new(%w[--color])
36-
expect(command_line.instance_eval { @options.options }).to eq(config_options.parse_options)
36+
expect(command_line.instance_eval { @options.options }).to eq(config_options.options)
3737
end
3838

3939
it "assigns submitted ConfigurationOptions to @options" do
@@ -106,9 +106,7 @@ def build_command_line *args
106106
end
107107

108108
def build_config_options *args
109-
options = ConfigurationOptions.new args
110-
options.parse_options
111-
options
109+
ConfigurationOptions.new args
112110
end
113111
end
114112
end

spec/rspec/core/configuration_options_spec.rb

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
it "warns when HOME env var is not set", :unless => (RUBY_PLATFORM == 'java') do
99
without_env_vars 'HOME' do
1010
expect_warning_with_call_site(__FILE__, __LINE__ + 1)
11-
RSpec::Core::ConfigurationOptions.new([]).parse_options
11+
RSpec::Core::ConfigurationOptions.new([]).options
1212
end
1313
end
1414

15-
it "duplicates the arguments array" do
15+
it "does not mutate the provided args array" do
1616
args = ['-e', 'some spec']
17-
coo = RSpec::Core::ConfigurationOptions.new(args)
18-
coo.parse_options
17+
RSpec::Core::ConfigurationOptions.new(args).options
1918
expect(args).to eq(['-e', 'some spec'])
2019
end
2120

@@ -26,40 +25,59 @@
2625
opts = config_options_object(*%w[--require a/path -I a/lib])
2726
config = double("config").as_null_object
2827
expect(config).to receive(:libs=).ordered
29-
expect(config).to receive(:setup_load_path_and_require).ordered
28+
expect(config).to receive(:requires=).ordered
3029
opts.configure(config)
3130
end
3231

33-
it "sends loads requires before loading specs" do
32+
it "loads requires before loading specs" do
3433
opts = config_options_object(*%w[-rspec_helper])
35-
config = double("config").as_null_object
36-
expect(config).to receive(:setup_load_path_and_require).ordered
37-
expect(config).to receive(:files_or_directories_to_run=).ordered
34+
config = RSpec::Core::Configuration.new
35+
expect(config).to receive(:requires=).ordered
36+
expect(config).to receive(:get_files_to_run).ordered
3837
opts.configure(config)
38+
config.files_to_run
3939
end
4040

4141
it "sets up load path and requires before formatter" do
4242
opts = config_options_object(*%w[--require a/path -f a/formatter])
4343
config = double("config").as_null_object
44-
expect(config).to receive(:setup_load_path_and_require).ordered
44+
expect(config).to receive(:requires=).ordered
4545
expect(config).to receive(:add_formatter).ordered
4646
opts.configure(config)
4747
end
4848

49-
it "sends default_path before files_or_directories_to_run" do
49+
it "sets default_path before loading specs" do
5050
opts = config_options_object(*%w[--default_path spec])
51-
config = double("config").as_null_object
51+
config = RSpec::Core::Configuration.new
52+
expect(config).to receive(:force).with(:default_path => 'spec').ordered
53+
expect(config).to receive(:get_files_to_run).ordered
54+
opts.configure(config)
55+
config.files_to_run
56+
end
57+
58+
it "sets `files_or_directories_to_run` before `requires` so users can check `files_to_run` in a spec_helper loaded by `--require`" do
59+
opts = config_options_object(*%w[--require spec_helper])
60+
config = RSpec::Core::Configuration.new
61+
expect(config).to receive(:files_or_directories_to_run=).ordered
62+
expect(config).to receive(:requires=).ordered
63+
opts.configure(config)
64+
end
65+
66+
it "sets default_path before `files_or_directories_to_run` since it relies on it" do
67+
opts = config_options_object(*%w[--default_path spec])
68+
config = RSpec::Core::Configuration.new
5269
expect(config).to receive(:force).with(:default_path => 'spec').ordered
5370
expect(config).to receive(:files_or_directories_to_run=).ordered
5471
opts.configure(config)
5572
end
5673

57-
it "sends pattern before files_or_directories_to_run" do
74+
it "sets pattern before loading specs" do
5875
opts = config_options_object(*%w[--pattern **/*.spec])
59-
config = double("config").as_null_object
76+
config = RSpec::Core::Configuration.new
6077
expect(config).to receive(:force).with(:pattern => '**/*.spec').ordered
61-
expect(config).to receive(:files_or_directories_to_run=).ordered
78+
expect(config).to receive(:get_files_to_run).ordered
6279
opts.configure(config)
80+
config.files_to_run
6381
end
6482

6583
it "assigns inclusion_filter" do
@@ -301,11 +319,12 @@
301319

302320
describe "default_path" do
303321
it "gets set before files_or_directories_to_run" do
304-
config = double("config").as_null_object
322+
config = RSpec::Core::Configuration.new
305323
expect(config).to receive(:force).with(:default_path => 'foo').ordered
306-
expect(config).to receive(:files_or_directories_to_run=).ordered
324+
expect(config).to receive(:get_files_to_run).ordered
307325
opts = config_options_object("--default_path", "foo")
308326
opts.configure(config)
327+
config.files_to_run
309328
end
310329
end
311330

0 commit comments

Comments
 (0)