From fac618a1c12e3d0f767ae5acc0aaae103b052cbe Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sat, 13 Jul 2013 22:07:20 -0700 Subject: [PATCH 1/9] Add helper methods to assist with spec'ing deprecations. The most consistently tricky part to get right is the call site, so that's what this helper method helps with. --- spec/support/helper_methods.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/support/helper_methods.rb b/spec/support/helper_methods.rb index 4b6abe8705..97ee565190 100644 --- a/spec/support/helper_methods.rb +++ b/spec/support/helper_methods.rb @@ -23,4 +23,14 @@ def safely end end + def expect_deprecation_with_call_site(file, line) + expect(RSpec.configuration.reporter).to receive(:deprecation) do |options| + expect(options[:call_site]).to include([file, line].join(':')) + end + end + + def allow_deprecation + allow(RSpec.configuration.reporter).to receive(:deprecation) + end + end From 651e4b052fd03b9e1a199248c83c8257b4ee8a5c Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sat, 13 Jul 2013 23:31:33 -0700 Subject: [PATCH 2/9] Fix the call site to be the stack frame before one of rspec's. --- lib/rspec/core/deprecation.rb | 4 +++- spec/rspec/core/deprecation_spec.rb | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/rspec/core/deprecation.rb b/lib/rspec/core/deprecation.rb index 7351da6322..03bd8ff5ae 100644 --- a/lib/rspec/core/deprecation.rb +++ b/lib/rspec/core/deprecation.rb @@ -8,10 +8,12 @@ def deprecate(deprecated, replacement_or_hash={}, ignore_version=nil) # Temporarily support old and new APIs while we transition the other # rspec libs to use a hash for the 2nd arg and no version arg data = Hash === replacement_or_hash ? replacement_or_hash : { :replacement => replacement_or_hash } + call_site = caller.find { |line| line !~ %r{/lib/rspec/(core|mocks|expectations|matchers|rails)/} } + RSpec.configuration.reporter.deprecation( { :deprecated => deprecated, - :call_site => caller(0)[2] + :call_site => call_site }.merge(data) ) end diff --git a/spec/rspec/core/deprecation_spec.rb b/spec/rspec/core/deprecation_spec.rb index 75fd378cdf..d0622001bc 100644 --- a/spec/rspec/core/deprecation_spec.rb +++ b/spec/rspec/core/deprecation_spec.rb @@ -14,7 +14,7 @@ end it "adds the call site" do - expect(RSpec.configuration.reporter).to receive(:deprecation).with(hash_including :call_site => caller(0)[1]) + expect_deprecation_with_call_site(__FILE__, __LINE__ + 1) RSpec.deprecate("deprecated_method") end @@ -31,7 +31,7 @@ end it "adds the call site" do - expect(RSpec.configuration.reporter).to receive(:deprecation).with(hash_including :call_site => caller(0)[1]) + expect_deprecation_with_call_site(__FILE__, __LINE__ + 1) RSpec.deprecate("deprecated_method") end end From 66123fccb696482bb5894afca8c605f153dde084 Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Tue, 16 Jul 2013 11:14:22 +1000 Subject: [PATCH 3/9] refactor configuration so that requires happen before spec files are loaded to ensure we can programatically configure pattern --- features/command_line/pattern_option.feature | 18 ++++++++++++++++++ lib/rspec/core/configuration_options.rb | 9 +++++---- spec/rspec/core/configuration_options_spec.rb | 8 ++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/features/command_line/pattern_option.feature b/features/command_line/pattern_option.feature index cc0b54491e..99ba9b92ac 100644 --- a/features/command_line/pattern_option.feature +++ b/features/command_line/pattern_option.feature @@ -29,3 +29,21 @@ Feature: pattern option """ When I run `rspec --pattern "spec/**/*.spec"` Then the output should contain "1 example, 0 failures" + + Scenario: override the default pattern in configuration + Given a file named "spec/spec_helper.rb" with: + """ruby + RSpec.configure do |config| + config.pattern << ',**/*.spec' + end + """ + And a file named "spec/example.spec" with: + """ruby + describe "addition" do + it "adds things" do + (1 + 2).should eq(3) + end + end + """ + When I run `rspec -rspec_helper` + Then the output should contain "1 example, 0 failures" diff --git a/lib/rspec/core/configuration_options.rb b/lib/rspec/core/configuration_options.rb index 282fc2f1e3..7ab3de11e6 100644 --- a/lib/rspec/core/configuration_options.rb +++ b/lib/rspec/core/configuration_options.rb @@ -20,10 +20,11 @@ def initialize(args) def configure(config) config.filter_manager = filter_manager - process_options_into config + config.libs = options[:libs] || [] config.setup_load_path_and_require(options[:requires] || []) + process_options_into config load_formatters_into config end @@ -46,13 +47,13 @@ def filter_manager private NON_FORCED_OPTIONS = [ - :debug, :requires, :libs, :profile, :drb, :files_or_directories_to_run, + :debug, :requires, :profile, :drb, :libs, :files_or_directories_to_run, :line_numbers, :full_description, :full_backtrace, :tty ].to_set MERGED_OPTIONS = [:requires, :libs].to_set - UNPROCESSABLE_OPTIONS = [:formatters, :requires].to_set + UNPROCESSABLE_OPTIONS = [:libs, :formatters, :requires].to_set def force?(key) !NON_FORCED_OPTIONS.include?(key) @@ -68,7 +69,7 @@ def order(keys, *ordered) def process_options_into(config) opts = options.reject { |k, _| UNPROCESSABLE_OPTIONS.include? k } - order(opts.keys, :libs, :default_path, :pattern).each do |key| + order(opts.keys, :default_path, :pattern).each do |key| force?(key) ? config.force(key => opts[key]) : config.send("#{key}=", opts[key]) end end diff --git a/spec/rspec/core/configuration_options_spec.rb b/spec/rspec/core/configuration_options_spec.rb index 9c43268158..2a30393a9c 100644 --- a/spec/rspec/core/configuration_options_spec.rb +++ b/spec/rspec/core/configuration_options_spec.rb @@ -29,6 +29,14 @@ opts.configure(config) end + it "sends loads requires before loading specs" do + opts = config_options_object(*%w[-rspec_helper]) + config = double("config").as_null_object + expect(config).to receive(:setup_load_path_and_require).ordered + expect(config).to receive(:files_or_directories_to_run=).ordered + opts.configure(config) + end + it "sets up load path and requires before formatter" do opts = config_options_object(*%w[--require a/path -f a/formatter]) config = double("config").as_null_object From c56eb3450d7c6d80cd7f04bfed041ac2793bad69 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Wed, 17 Jul 2013 23:45:37 -0700 Subject: [PATCH 4/9] Autoload RSpec::Mocks and RSpec::Expectations. We already autoload RSpec::Matchers to support folks using `RSpec::Matchers.define` before the normal time that rspec-core loads rspec-expectation (e.g. right before eval'ing the first example group block). This extends it to RSpec::Mocks and RSpec::Expectations for parity and to improve things for folks who we accidentally broke via this rspec gem change: https://github.com/rspec/rspec/commit/f10bedd498dff2961d4be9cce793fa152c4a0bbe That was put in place to address rspec/rspec-mocks#359, which has more info. --- lib/rspec/core.rb | 32 +++++++++++++++++++------------- spec/rspec/core_spec.rb | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/lib/rspec/core.rb b/lib/rspec/core.rb index 25fd945cbf..0080d6696f 100644 --- a/lib/rspec/core.rb +++ b/lib/rspec/core.rb @@ -143,20 +143,26 @@ class << self end end + MODULES_TO_AUTOLOAD = { + :Matchers => "rspec/expectations", + :Expectations => "rspec/expectations", + :Mocks => "rspec/mocks" + } + def self.const_missing(name) - case name - when :Matchers - # Load rspec-expectations when RSpec::Matchers is referenced. This allows - # people to define custom matchers (using `RSpec::Matchers.define`) before - # rspec-core has loaded rspec-expectations (since it delays the loading of - # it to allow users to configure a different assertion/expectation - # framework). `autoload` can't be used since it works with ruby's built-in - # require (e.g. for files that are available relative to a load path dir), - # but not with rubygems' extended require. - require 'rspec/expectations' - ::RSpec::Matchers - else super - end + # Load rspec-expectations when RSpec::Matchers is referenced. This allows + # people to define custom matchers (using `RSpec::Matchers.define`) before + # rspec-core has loaded rspec-expectations (since it delays the loading of + # it to allow users to configure a different assertion/expectation + # framework). `autoload` can't be used since it works with ruby's built-in + # require (e.g. for files that are available relative to a load path dir), + # but not with rubygems' extended require. + # + # As of rspec 2.14.1, we no longer require `rspec/mocks` and + # `rspec/expectations` when `rspec` is required, so we want + # to make them available as an autoload. For more info, see: + require MODULES_TO_AUTOLOAD.fetch(name) { return super } + ::RSpec.const_get(name) end end diff --git a/spec/rspec/core_spec.rb b/spec/rspec/core_spec.rb index f668610c3c..e6a5c7d99a 100644 --- a/spec/rspec/core_spec.rb +++ b/spec/rspec/core_spec.rb @@ -52,4 +52,23 @@ expect(RSpec.world).not_to equal(world_before_reset) end end + + # This is hard to test :(. Best way I could come up with was starting + # fresh ruby process w/o this stuff already loaded. + it "loads mocks and expectations when the constants are referenced" do + code = "$LOAD_PATH.replace(#{$LOAD_PATH.inspect}); " + + 'require "rspec"; ' + + "puts RSpec::Mocks.name; " + + "puts RSpec::Expectations.name" + + result = `ruby -e '#{code}'`.chomp + expect(result.split("\n")).to eq(%w[ RSpec::Mocks RSpec::Expectations ]) + end + + it 'correctly raises an error when an invalid const is referenced' do + expect { + RSpec::NotAConst + }.to raise_error(NameError, /uninitialized constant RSpec::NotAConst/) + end end + From f24274b308611ec56e231dd86a5d67ea8522f244 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sun, 21 Jul 2013 22:16:03 -0700 Subject: [PATCH 5/9] Add changelog entries. [ci skip] --- Changelog.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Changelog.md b/Changelog.md index dc806edcf1..9bc6bd75b8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,22 @@ +### Dev +[full changelog](http://github.com/rspec/rspec-core/compare/v2.14.3...2-14-maintenance) + +Bug fixes + +* Fix regression in 2.14: ensure configured requires (via `-r` option) + are loaded before spec files are loaded. This allows the spec files + to programatically change the file pattern (Jon Rowe). +* Autoload `RSpec::Mocks` and `RSpec::Expectations` when referenced if + they are not already loaded (`RSpec::Matches` has been autoloaded + for a while). In the `rspec` gem, we changed it recently to stop + loading `rspec/mocks` and `rspec/expectations` by default, as some + users reported problems where they were intending to use mocha, + not rspec-mocks, but rspec-mocks was loaded and causing a conflict. + rspec-core loads mocks and expectations at the appropriate time, so + it seemed like a safe change -- but caused a problem for some authors + of libraries that integrate with RSpec. This fixes that problem. + (Myron Marston) + ### 2.14.3 / 2013-07-13 [full changelog](http://github.com/rspec/rspec-core/compare/v2.14.2...v2.14.3) From d84904c165f571e437e1e73fec256de6fb68690a Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Thu, 18 Jul 2013 16:04:45 +1000 Subject: [PATCH 6/9] Warn about non integer profile arguments fixes #998 --- lib/rspec/core/option_parser.rb | 5 +++++ spec/rspec/core/option_parser_spec.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/rspec/core/option_parser.rb b/lib/rspec/core/option_parser.rb index 4ef24b813c..815382a7a0 100644 --- a/lib/rspec/core/option_parser.rb +++ b/lib/rspec/core/option_parser.rb @@ -138,6 +138,11 @@ def parser(options) parser.on('-p', '--[no-]profile [COUNT]', 'Enable profiling of examples and list the slowest examples (default: 10).') do |argument| options[:profile_examples] = if argument.nil? true + elsif argument && !(argument =~ /^\d+$/) + Kernel.warn "Non integer specified as profile count, seperate " + + "your path from options with -- e.g. " + + "`rspec --profile -- #{argument}`" + true elsif argument == false false else diff --git a/spec/rspec/core/option_parser_spec.rb b/spec/rspec/core/option_parser_spec.rb index 4218819a93..8894b368f2 100644 --- a/spec/rspec/core/option_parser_spec.rb +++ b/spec/rspec/core/option_parser_spec.rb @@ -205,6 +205,32 @@ module RSpec::Core end end + describe '--profile' do + it 'sets profile_examples to true by default' do + options = Parser.parse!(%w[--profile]) + expect(options[:profile_examples]).to eq true + end + + it 'sets profile_examples to supplied int' do + options = Parser.parse!(%w[--profile 10]) + expect(options[:profile_examples]).to eq 10 + end + + it 'sets profile_examples to true when accidentally combined with path' do + allow(Kernel).to receive(:warn) + options = Parser.parse!(%w[--profile some/path]) + expect(options[:profile_examples]).to eq true + end + + it 'warns when accidentally combined with path' do + expect(Kernel).to receive(:warn) do |msg| + expect(msg).to match "Non integer specified as profile count" + end + options = Parser.parse!(%w[--profile some/path]) + expect(options[:profile_examples]).to eq true + end + end + describe '--warning' do it 'enables warnings' do options = Parser.parse!(%w[--warnings]) From bf7d797a616a6b3a84be971bc717bab9997f008e Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Fri, 19 Jul 2013 13:09:52 +1000 Subject: [PATCH 7/9] refactor to cast to Integer and rescue ArgumentError instead of using regexp --- lib/rspec/core/option_parser.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/rspec/core/option_parser.rb b/lib/rspec/core/option_parser.rb index 815382a7a0..4fad96fd77 100644 --- a/lib/rspec/core/option_parser.rb +++ b/lib/rspec/core/option_parser.rb @@ -138,15 +138,17 @@ def parser(options) parser.on('-p', '--[no-]profile [COUNT]', 'Enable profiling of examples and list the slowest examples (default: 10).') do |argument| options[:profile_examples] = if argument.nil? true - elsif argument && !(argument =~ /^\d+$/) - Kernel.warn "Non integer specified as profile count, seperate " + - "your path from options with -- e.g. " + - "`rspec --profile -- #{argument}`" - true elsif argument == false false else - argument.to_i + begin + Integer(argument) + rescue ArgumentError + Kernel.warn "Non integer specified as profile count, seperate " + + "your path from options with -- e.g. " + + "`rspec --profile -- #{argument}`" + true + end end end From c7df74716d792c1dd8ae416c0be38b276d281da6 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sun, 21 Jul 2013 22:45:15 -0700 Subject: [PATCH 8/9] Add changelog entry for #299. [ci skip] --- Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog.md b/Changelog.md index 9bc6bd75b8..41029c83a6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,10 @@ Bug fixes it seemed like a safe change -- but caused a problem for some authors of libraries that integrate with RSpec. This fixes that problem. (Myron Marston) +* Gracefully handle a command like `rspec --profile path/to/spec.rb`: + the `path/to/spec.rb` arg was being wrongly treated as the `profile` + integer arg, which got cast `0` using `to_i`, causing no profiled + examples to be printed. (Jon Rowe) ### 2.14.3 / 2013-07-13 [full changelog](http://github.com/rspec/rspec-core/compare/v2.14.2...v2.14.3) From 26451e9ef0f8c03a1846f79081979bc32fddd3e8 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sun, 21 Jul 2013 22:47:27 -0700 Subject: [PATCH 9/9] 2.14.4 release. --- Changelog.md | 4 ++-- lib/rspec/core/version.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 41029c83a6..6233f911f6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,5 @@ -### Dev -[full changelog](http://github.com/rspec/rspec-core/compare/v2.14.3...2-14-maintenance) +### 2.14.4 / 2013-07-21 +[full changelog](http://github.com/rspec/rspec-core/compare/v2.14.3...v2.14.4) Bug fixes diff --git a/lib/rspec/core/version.rb b/lib/rspec/core/version.rb index d59636bcc5..cb14b322e6 100644 --- a/lib/rspec/core/version.rb +++ b/lib/rspec/core/version.rb @@ -1,7 +1,7 @@ module RSpec module Core module Version - STRING = '2.14.3' + STRING = '2.14.4' end end end