Hello community, here is the log from the commit of package rubygem-rspec-expectations for openSUSE:Factory checked in at 2015-12-01 10:02:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-rspec-expectations (Old) and /work/SRC/openSUSE:Factory/.rubygem-rspec-expectations.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "rubygem-rspec-expectations" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-rspec-expectations/rubygem-rspec-expectations.changes 2015-07-20 11:19:56.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-rspec-expectations.new/rubygem-rspec-expectations.changes 2015-12-01 10:02:15.000000000 +0100 @@ -1,0 +2,32 @@ +Fri Nov 13 05:38:50 UTC 2015 - coolo@suse.com + +- updated to version 3.4.0 + see installed Changelog.md + + ### 3.4.0 / 2015-11-11 + [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.1...v3.4.0) + + Enhancements: + + * Warn when `RSpec::Matchers` is included in a superclass after it has + already been included in a subclass on MRI 1.9, since that situation + can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816) + * Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and + `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845) + * Add `#with_captures` to the + [match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/ma...) + which allows a user to specify expected captures when matching a regex + against a string. (Sam Phippen, #848) + * Always print compound failure messages in the multi-line form. Trying + to print it all on a single line didn't read very well. (Myron Marston, #859) + + Bug Fixes: + + * Fix failure message from dynamic predicate matchers when the object + does not respond to the predicate so that it is inspected rather + than relying upon it's `to_s` -- that way for `nil`, `"nil"` is + printed rather than an empty string. (Myron Marston, #841) + * Fix SystemStackError raised when diffing an Enumerable object + whose `#each` includes the object itself. (Yuji Nakayama, #857) + +------------------------------------------------------------------- Old: ---- rspec-expectations-3.3.1.gem New: ---- rspec-expectations-3.4.0.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-rspec-expectations.spec ++++++ --- /var/tmp/diff_new_pack.CcJTmj/_old 2015-12-01 10:02:16.000000000 +0100 +++ /var/tmp/diff_new_pack.CcJTmj/_new 2015-12-01 10:02:16.000000000 +0100 @@ -24,7 +24,7 @@ # Name: rubygem-rspec-expectations -Version: 3.3.1 +Version: 3.4.0 Release: 0 %define mod_name rspec-expectations %define mod_full_name %{mod_name}-%{version} @@ -50,7 +50,7 @@ %install %gem_install \ - --doc-files="Changelog.md License.txt README.md" \ + --doc-files="Changelog.md LICENSE.md README.md" \ -f %gem_packages ++++++ rspec-expectations-3.3.1.gem -> rspec-expectations-3.4.0.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.document new/.document --- old/.document 2015-07-15 19:09:01.000000000 +0200 +++ new/.document 2015-11-12 08:48:14.000000000 +0100 @@ -1,5 +1,5 @@ lib/**/*.rb - README.md -License.txt +LICENSE.md Changelog.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.yardopts new/.yardopts --- old/.yardopts 2015-07-15 19:09:01.000000000 +0200 +++ new/.yardopts 2015-11-12 08:48:14.000000000 +0100 @@ -3,4 +3,4 @@ --markup markdown - Changelog.md -License.txt +LICENSE.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Changelog.md new/Changelog.md --- old/Changelog.md 2015-07-15 19:09:01.000000000 +0200 +++ new/Changelog.md 2015-11-12 08:48:14.000000000 +0100 @@ -1,3 +1,29 @@ +### 3.4.0 / 2015-11-11 +[Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.1...v3.4.0) + +Enhancements: + +* Warn when `RSpec::Matchers` is included in a superclass after it has + already been included in a subclass on MRI 1.9, since that situation + can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816) +* Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and + `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845) +* Add `#with_captures` to the + [match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/ma...) + which allows a user to specify expected captures when matching a regex + against a string. (Sam Phippen, #848) +* Always print compound failure messages in the multi-line form. Trying + to print it all on a single line didn't read very well. (Myron Marston, #859) + +Bug Fixes: + +* Fix failure message from dynamic predicate matchers when the object + does not respond to the predicate so that it is inspected rather + than relying upon it's `to_s` -- that way for `nil`, `"nil"` is + printed rather than an empty string. (Myron Marston, #841) +* Fix SystemStackError raised when diffing an Enumerable object + whose `#each` includes the object itself. (Yuji Nakayama, #857) + ### 3.3.1 / 2015-07-15 [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.3.0...v3.3.1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/LICENSE.md new/LICENSE.md --- old/LICENSE.md 1970-01-01 01:00:00.000000000 +0100 +++ new/LICENSE.md 2015-11-12 08:48:14.000000000 +0100 @@ -0,0 +1,25 @@ +The MIT License (MIT) +===================== + +* Copyright © 2012 David Chelimsky, Myron Marston +* Copyright © 2006 David Chelimsky, The RSpec Development Team +* Copyright © 2005 Steven Baker + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/License.txt new/License.txt --- old/License.txt 2015-07-15 19:09:01.000000000 +0200 +++ new/License.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,24 +0,0 @@ -(The MIT License) - -Copyright (c) 2012 David Chelimsky, Myron Marston -Copyright (c) 2006 David Chelimsky, The RSpec Development Team -Copyright (c) 2005 Steven Baker - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2015-07-15 19:09:01.000000000 +0200 +++ new/README.md 2015-11-12 08:48:14.000000000 +0100 @@ -27,6 +27,20 @@ gem install rspec-expectations +## Contributing + +Once you've set up the environment, you'll need to cd into the working +directory of whichever repo you want to work in. From there you can run the +specs and cucumber features, and make patches. + +NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You +can treat each RSpec repo as an independent project. + +- [Build details](BUILD_DETAIL.md) +- [Code of Conduct](CODE_OF_CONDUCT.md) +- [Detailed contributing guide](CONTRIBUTING.md) +- [Development setup guide](DEVELOPMENT.md) + ## Basic usage Here's an example using rspec-core: @@ -283,7 +297,7 @@ ## Also see -* [http://github.com/rspec/rspec](http://github.com/rspec/rspec) -* [http://github.com/rspec/rspec-core](http://github.com/rspec/rspec-core) -* [http://github.com/rspec/rspec-mocks](http://github.com/rspec/rspec-mocks) -* [http://github.com/rspec/rspec-collection_matchers](https://github.com/rspec/rspec-collection_matchers) +* [https://github.com/rspec/rspec](https://github.com/rspec/rspec) +* [https://github.com/rspec/rspec-core](https://github.com/rspec/rspec-core) +* [https://github.com/rspec/rspec-mocks](https://github.com/rspec/rspec-mocks) +* [https://github.com/rspec/rspec-rails](https://github.com/rspec/rspec-rails) Files old/checksums.yaml.gz and new/checksums.yaml.gz differ Files old/checksums.yaml.gz.sig and new/checksums.yaml.gz.sig differ Files old/data.tar.gz.sig and new/data.tar.gz.sig differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/expectations/failure_aggregator.rb new/lib/rspec/expectations/failure_aggregator.rb --- old/lib/rspec/expectations/failure_aggregator.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/expectations/failure_aggregator.rb 2015-11-12 08:48:14.000000000 +0100 @@ -15,7 +15,7 @@ # of `failures` rather than letting it fall through and be categorized as part of # `other_errors`. failures << e - rescue Exception => e + rescue Support::AllExceptionsExceptOnesWeMustNotRescue => e # While it is normally a bad practice to rescue `Exception`, it's important we do # so here. It's low risk (`notify_aggregated_failures` below will re-raise the exception, # or raise a `MultipleExpectationsNotMetError` that includes the exception), and it's diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/expectations/version.rb new/lib/rspec/expectations/version.rb --- old/lib/rspec/expectations/version.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/expectations/version.rb 2015-11-12 08:48:14.000000000 +0100 @@ -2,7 +2,7 @@ module Expectations # @private module Version - STRING = '3.3.1' + STRING = '3.4.0' end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/base_matcher.rb new/lib/rspec/matchers/built_in/base_matcher.rb --- old/lib/rspec/matchers/built_in/base_matcher.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/base_matcher.rb 2015-11-12 08:48:14.000000000 +0100 @@ -8,8 +8,8 @@ # # ### Warning: # - # This class is for internal use, and subject to change without notice. We - # strongly recommend that you do not base your custom matchers on this + # This class is for internal use, and subject to change without notice. + # We strongly recommend that you do not base your custom matchers on this # class. If/when this changes, we will announce it and remove this warning. class BaseMatcher include RSpec::Matchers::Composable @@ -92,7 +92,7 @@ # @private def self.matcher_name - @matcher_name ||= underscore(name.split("::").last) + @matcher_name ||= underscore(name.split('::').last) end # @private @@ -101,7 +101,7 @@ word = camel_cased_word.to_s.dup word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') word.gsub!(/([a-z\d])([A-Z])/, '\1_\2') - word.tr!("-", "_") + word.tr!('-', '_') word.downcase! word end @@ -118,7 +118,7 @@ if RUBY_VERSION.to_f < 1.9 # :nocov: def present_ivars - instance_variables.map { |v| v.to_sym } + instance_variables.map(&:to_sym) end # :nocov: else @@ -168,7 +168,7 @@ # @private def self.has_default_failure_messages?(matcher) matcher.method(:failure_message).owner == self && - matcher.method(:failure_message_when_negated).owner == self + matcher.method(:failure_message_when_negated).owner == self rescue NameError false end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/be.rb new/lib/rspec/matchers/built_in/be.rb --- old/lib/rspec/matchers/built_in/be.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/be.rb 2015-11-12 08:48:14.000000000 +0100 @@ -267,7 +267,7 @@ def validity_message return nil if predicate_accessible? - msg = "expected #{@actual} to respond to `#{predicate}`" + msg = "expected #{actual_formatted} to respond to `#{predicate}`" if private_predicate? msg << " but `#{predicate}` is a private method" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/change.rb new/lib/rspec/matchers/built_in/change.rb --- old/lib/rspec/matchers/built_in/change.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/change.rb 2015-11-12 08:48:14.000000000 +0100 @@ -58,13 +58,15 @@ # @api private # @return [String] def failure_message - "expected #{@change_details.message} to have changed, but #{positive_failure_reason}" + "expected #{@change_details.message} to have changed, " \ + "but #{positive_failure_reason}" end # @api private # @return [String] def failure_message_when_negated - "expected #{@change_details.message} not to have changed, but #{negative_failure_reason}" + "expected #{@change_details.message} not to have changed, " \ + "but #{negative_failure_reason}" end # @api private @@ -96,7 +98,8 @@ def negative_failure_reason return "was not given a block" unless Proc === @event_proc - "did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}" + "did change from #{description_of @change_details.actual_before} " \ + "to #{description_of @change_details.actual_after}" end end @@ -112,7 +115,9 @@ # @private def failure_message - "expected #{@change_details.message} to have changed #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}, but #{failure_reason}" + "expected #{@change_details.message} to have changed " \ + "#{@relativity.to_s.tr('_', ' ')} " \ + "#{description_of @expected_delta}, but #{failure_reason}" end # @private @@ -125,12 +130,14 @@ # @private def does_not_match?(_event_proc) - raise NotImplementedError, "`expect { }.not_to change { }.#{@relativity}()` is not supported" + raise NotImplementedError, "`expect { }.not_to change " \ + "{ }.#{@relativity}()` is not supported" end # @private def description - "change #{@change_details.message} #{@relativity.to_s.gsub("_", " ")} #{description_of @expected_delta}" + "change #{@change_details.message} " \ + "#{@relativity.to_s.tr('_', ' ')} #{description_of @expected_delta}" end # @private @@ -195,23 +202,31 @@ end def before_value_failure - "expected #{@change_details.message} to have initially been #{description_of @expected_before}, but was #{description_of @change_details.actual_before}" + "expected #{@change_details.message} " \ + "to have initially been #{description_of @expected_before}, " \ + "but was #{description_of @change_details.actual_before}" end def after_value_failure - "expected #{@change_details.message} to have changed to #{description_of @expected_after}, but is now #{description_of @change_details.actual_after}" + "expected #{@change_details.message} " \ + "to have changed to #{description_of @expected_after}, " \ + "but is now #{description_of @change_details.actual_after}" end def did_not_change_failure - "expected #{@change_details.message} to have changed #{change_description}, but did not change" + "expected #{@change_details.message} " \ + "to have changed #{change_description}, but did not change" end def did_change_failure - "expected #{@change_details.message} not to have changed, but did change from #{description_of @change_details.actual_before} to #{description_of @change_details.actual_after}" + "expected #{@change_details.message} not to have changed, but " \ + "did change from #{description_of @change_details.actual_before} " \ + "to #{description_of @change_details.actual_after}" end def not_given_a_block_failure - "expected #{@change_details.message} to have changed #{change_description}, but was not given a block" + "expected #{@change_details.message} to have changed " \ + "#{change_description}, but was not given a block" end end @@ -235,7 +250,8 @@ # @private def does_not_match?(event_proc) if @description_suffix - raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported" + raise NotImplementedError, "`expect { }.not_to change { }.to()` " \ + "is not supported" end @event_proc = event_proc @@ -277,7 +293,8 @@ # @private def does_not_match?(_event_proc) - raise NotImplementedError, "`expect { }.not_to change { }.to()` is not supported" + raise NotImplementedError, "`expect { }.not_to change { }.to()` " \ + "is not supported" end private diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/compound.rb new/lib/rspec/matchers/built_in/compound.rb --- old/lib/rspec/matchers/built_in/compound.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/compound.rb 2015-11-12 08:48:14.000000000 +0100 @@ -24,7 +24,7 @@ # @api private # @return [String] def description - singleline_message(matcher_1.description, matcher_2.description) + "#{matcher_1.description} #{conjunction} #{matcher_2.description}" end def supports_block_expectations? @@ -84,30 +84,9 @@ end def compound_failure_message - message_1 = matcher_1.failure_message - message_2 = matcher_2.failure_message - - if multiline?(message_1) || multiline?(message_2) - multiline_message(message_1, message_2) - else - singleline_message(message_1, message_2) - end - end - - def multiline_message(message_1, message_2) - [ - indent_multiline_message(message_1.sub(/\n+\z/, '')), - "...#{conjunction}:", - indent_multiline_message(message_2.sub(/\A\n+/, '')) - ].join("\n\n") - end - - def multiline?(message) - message.lines.count > 1 - end - - def singleline_message(message_1, message_2) - [message_1, conjunction, message_2].join(' ') + "#{indent_multiline_message(matcher_1.failure_message.sub(/\n+\z/, ''))}" \ + "\n\n...#{conjunction}:" \ + "\n\n#{indent_multiline_message(matcher_2.failure_message.sub(/\A\n+/, ''))}" end def matcher_1_matches? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/contain_exactly.rb new/lib/rspec/matchers/built_in/contain_exactly.rb --- old/lib/rspec/matchers/built_in/contain_exactly.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/contain_exactly.rb 2015-11-12 08:48:14.000000000 +0100 @@ -9,11 +9,7 @@ # @return [String] def failure_message if Array === actual - message = "expected collection contained: #{description_of(safe_sort(surface_descriptions_in expected))}\n" - message += "actual collection contained: #{description_of(safe_sort(actual))}\n" - message += "the missing elements were: #{description_of(safe_sort(surface_descriptions_in missing_items))}\n" unless missing_items.empty? - message += "the extra elements were: #{description_of(safe_sort(extra_items))}\n" unless extra_items.empty? - message + generate_failure_message else "expected a collection that can be converted to an array with " \ "`#to_ary` or `#to_a`, but got #{actual_formatted}" @@ -36,6 +32,43 @@ private + def generate_failure_message + message = expected_collection_line + message += actual_collection_line + message += missing_elements_line unless missing_items.empty? + message += extra_elements_line unless extra_items.empty? + message + end + + def expected_collection_line + message_line('expected collection contained', expected, true) + end + + def actual_collection_line + message_line('actual collection contained', actual) + end + + def missing_elements_line + message_line('the missing elements were', missing_items, true) + end + + def extra_elements_line + message_line('the extra elements were', extra_items) + end + + def describe_collection(collection, surface_descriptions=false) + if surface_descriptions + "#{description_of(safe_sort(surface_descriptions_in collection))}\n" + else + "#{description_of(safe_sort(collection))}\n" + end + end + + def message_line(prefix, collection, surface_descriptions=false) + "%-32s%s" % [prefix + ':', + describe_collection(collection, surface_descriptions)] + end + def match(_expected, _actual) return false unless convert_actual_to_an_array match_when_sorted? || (extra_items.empty? && missing_items.empty?) @@ -61,7 +94,7 @@ def safe_sort(array) array.sort - rescue Exception + rescue Support::AllExceptionsExceptOnesWeMustNotRescue array end @@ -231,7 +264,7 @@ modified_expecteds.delete(expected_index) - modified_actuals = apply_pairing_to( + modified_actuals = apply_pairing_to( solution.indeterminate_actual_indexes, actual_to_expected_matched_indexes, expected_index) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/match.rb new/lib/rspec/matchers/built_in/match.rb --- old/lib/rspec/matchers/built_in/match.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/match.rb 2015-11-12 08:48:14.000000000 +0100 @@ -5,10 +5,19 @@ # Provides the implementation for `match`. # Not intended to be instantiated directly. class Match < BaseMatcher + def initialize(expected) + super(expected) + + @expected_captures = nil + end # @api private # @return [String] def description - "match #{surface_descriptions_in(expected).inspect}" + if @expected_captures && @expected.match(actual) + "match #{surface_descriptions_in(expected).inspect} with captures #{surface_descriptions_in(@expected_captures).inspect}" + else + "match #{surface_descriptions_in(expected).inspect}" + end end # @api private @@ -17,9 +26,17 @@ true end + # Used to specify the captures we match against + # @return [self] + def with_captures(*captures) + @expected_captures = captures + self + end + private def match(expected, actual) + return match_captures(expected, actual) if @expected_captures return true if values_match?(expected, actual) return false unless can_safely_call_match?(expected, actual) actual.match(expected) @@ -31,6 +48,58 @@ !(RSpec::Matchers.is_a_matcher?(expected) && (String === actual || Regexp === actual)) end + + def match_captures(expected, actual) + match = actual.match(expected) + if match + match = ReliableMatchData.new(match) + if match.names.empty? + values_match?(@expected_captures, match.captures) + else + expected_matcher = @expected_captures.last + values_match?(expected_matcher, Hash[match.names.zip(match.captures)]) || + values_match?(expected_matcher, Hash[match.names.map(&:to_sym).zip(match.captures)]) || + values_match?(@expected_captures, match.captures) + end + else + false + end + end + end + + # @api private + # Used to wrap match data and make it reliable for 1.8.7 + class ReliableMatchData + def initialize(match_data) + @match_data = match_data + end + + if RUBY_VERSION == "1.8.7" + # @api private + # Returns match data names for named captures + # @return Array + def names + [] + end + else + # @api private + # Returns match data names for named captures + # @return Array + def names + match_data.names + end + end + + # @api private + # returns an array of captures from the match data + # @return Array + def captures + match_data.captures + end + + protected + + attr_reader :match_data end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/raise_error.rb new/lib/rspec/matchers/built_in/raise_error.rb --- old/lib/rspec/matchers/built_in/raise_error.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/raise_error.rb 2015-11-12 08:48:14.000000000 +0100 @@ -5,6 +5,7 @@ # Provides the implementation for `raise_error`. # Not intended to be instantiated directly. # rubocop:disable ClassLength + # rubocop:disable RescueException class RaiseError include Composable @@ -15,11 +16,14 @@ case expected_error_or_message when nil - @expected_error, @expected_message = Exception, expected_message + @expected_error = Exception + @expected_message = expected_message when String - @expected_error, @expected_message = Exception, expected_error_or_message + @expected_error = Exception + @expected_message = expected_error_or_message else - @expected_error, @expected_message = expected_error_or_message, expected_message + @expected_error = expected_error_or_message + @expected_message = expected_message end end @@ -42,7 +46,6 @@ @eval_block = false @eval_block_passed = false - warn_about_bare_error if warning_about_bare_error && !negative_expectation return false unless Proc === given_proc begin @@ -55,6 +58,7 @@ end end + warn_about_bare_error if warning_about_bare_error && !negative_expectation eval_block if !negative_expectation && ready_to_eval_block? expectation_matched? @@ -156,6 +160,7 @@ "will match when Ruby raises a `NoMethodError`, `NameError` or " \ "`ArgumentError`, potentially allowing the expectation to pass " \ "without even executing the method you are intending to call. " \ + "#{warning}"\ "Instead consider providing a specific error class or message. " \ "This message can be supressed by setting: " \ "`RSpec::Expectations.configuration.warn_about_potential_false_positives = false`") @@ -207,9 +212,16 @@ end def raise_message_already_set - raise "`expect { }.to raise_error(message).with_message(message)` is not valid. The matcher only allows the expected message to be specified once" + raise "`expect { }.to raise_error(message).with_message(message)` is not valid. " \ + 'The matcher only allows the expected message to be specified once' + end + + def warning + warning = "Actual error raised was #{description_of(@actual_error)}. " + warning if @actual_error end end + # rubocop:enable RescueException # rubocop:enable ClassLength end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/built_in/yield.rb new/lib/rspec/matchers/built_in/yield.rb --- old/lib/rspec/matchers/built_in/yield.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/built_in/yield.rb 2015-11-12 08:48:14.000000000 +0100 @@ -1,4 +1,4 @@ -RSpec::Support.require_rspec_support "method_signature_verifier" +RSpec::Support.require_rspec_support 'method_signature_verifier' module RSpec module Matchers @@ -22,7 +22,8 @@ def initialize(block) @block = block @used = false - self.num_yields, self.yielded_args = 0, [] + self.num_yields = 0 + self.yielded_args = [] end def has_block? @@ -50,8 +51,8 @@ when 0 then false else raise "The #{matcher_name} matcher is not designed to be used with a " \ - "method that yields multiple times. Use the yield_successive_args " \ - "matcher for that case." + 'method that yields multiple times. Use the yield_successive_args ' \ + 'matcher for that case.' end end @@ -63,19 +64,19 @@ def assert_used! return if @used - raise "You must pass the argument yielded to your expect block on " \ - "to the method-under-test as a block. It acts as a probe that " \ - "allows the matcher to detect whether or not the method-under-test " \ - "yields, and, if so, how many times, and what the yielded arguments " \ - "are." + raise 'You must pass the argument yielded to your expect block on ' \ + 'to the method-under-test as a block. It acts as a probe that ' \ + 'allows the matcher to detect whether or not the method-under-test ' \ + 'yields, and, if so, how many times, and what the yielded arguments ' \ + 'are.' end if RUBY_VERSION.to_f > 1.8 def assert_valid_expect_block! block_signature = RSpec::Support::BlockSignature.new(@block) return if RSpec::Support::StrictSignatureVerifier.new(block_signature, [self]).valid? - raise "Your expect block must accept an argument to be used with this " \ - "matcher. Pass the argument as a block on to the method you are testing." + raise 'Your expect block must accept an argument to be used with this ' \ + 'matcher. Pass the argument as a block on to the method you are testing.' end else # :nocov: @@ -190,7 +191,7 @@ end def failure_reason - return " but was not a block" unless @probe.has_block? + return ' but was not a block' unless @probe.has_block? return '' unless @expected_yields_count " #{human_readable_expectation_type}#{human_readable_count(@expected_yields_count)}" \ " but yielded #{human_readable_count(@probe.num_yields)}" @@ -206,8 +207,8 @@ def human_readable_count(count) case count - when 1 then "once" - when 2 then "twice" + when 1 then 'once' + when 2 then 'twice' else "#{count} times" end end @@ -247,14 +248,14 @@ private def positive_failure_reason - return "was not a block" unless @probe.has_block? - return "did not yield" if @probe.num_yields.zero? + return 'was not a block' unless @probe.has_block? + return 'did not yield' if @probe.num_yields.zero? "yielded with arguments: #{description_of @probe.single_yield_args}" end def negative_failure_reason - return "was not a block" unless @probe.has_block? - "did" + return 'was not a block' unless @probe.has_block? + 'did' end end @@ -291,7 +292,7 @@ # @private def description - desc = "yield with args" + desc = 'yield with args' desc << "(#{expected_arg_description})" unless @expected.empty? desc end @@ -304,36 +305,36 @@ private def positive_failure_reason - return "was not a block" unless @probe.has_block? - return "did not yield" if @probe.num_yields.zero? + return 'was not a block' unless @probe.has_block? + return 'did not yield' if @probe.num_yields.zero? @positive_args_failure end def expected_arg_description - @expected.map { |e| description_of e }.join(", ") + @expected.map { |e| description_of e }.join(', ') end def negative_failure_reason if !@probe.has_block? - "was not a block" + 'was not a block' elsif all_args_match? - "yielded with expected arguments" \ - "\nexpected not: #{surface_descriptions_in(@expected).inspect}" + + 'yielded with expected arguments' \ + "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{actual_formatted}" else - "did" + 'did' end end def args_match? if @expected.empty? # expect {...}.to yield_with_args - @positive_args_failure = "yielded with no arguments" if @actual.empty? + @positive_args_failure = 'yielded with no arguments' if @actual.empty? return !@actual.empty? end unless (match = all_args_match?) - @positive_args_failure = "yielded with unexpected arguments" \ - "\nexpected: #{surface_descriptions_in(@expected).inspect}" + + @positive_args_failure = 'yielded with unexpected arguments' \ + "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{actual_formatted}" end @@ -367,19 +368,19 @@ # @private def failure_message - "expected given block to yield successively with arguments, but #{positive_failure_reason}" + 'expected given block to yield successively with arguments, ' \ + "but #{positive_failure_reason}" end # @private def failure_message_when_negated - "expected given block not to yield successively with arguments, but #{negative_failure_reason}" + 'expected given block not to yield successively with arguments, ' \ + "but #{negative_failure_reason}" end # @private def description - desc = "yield successive args" - desc << "(#{expected_arg_description})" - desc + "yield successive args(#{expected_arg_description})" end # @private @@ -394,21 +395,21 @@ end def expected_arg_description - @expected.map { |e| description_of e }.join(", ") + @expected.map { |e| description_of e }.join(', ') end def positive_failure_reason - return "was not a block" unless @probe.has_block? + return 'was not a block' unless @probe.has_block? - "yielded with unexpected arguments" \ + 'yielded with unexpected arguments' \ "\nexpected: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{actual_formatted}" end def negative_failure_reason - return "was not a block" unless @probe.has_block? + return 'was not a block' unless @probe.has_block? - "yielded with expected arguments" \ + 'yielded with expected arguments' \ "\nexpected not: #{surface_descriptions_in(@expected).inspect}" \ "\n got: #{actual_formatted}" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers/composable.rb new/lib/rspec/matchers/composable.rb --- old/lib/rspec/matchers/composable.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers/composable.rb 2015-11-12 08:48:14.000000000 +0100 @@ -100,14 +100,10 @@ DescribableItem.new(item) elsif Hash === item Hash[surface_descriptions_in(item.to_a)] - elsif Struct === item + elsif Struct === item || unreadable_io?(item) RSpec::Support::ObjectFormatter.format(item) elsif should_enumerate?(item) - begin - item.map { |subitem| surface_descriptions_in(subitem) } - rescue IOError # STDOUT is enumerable but `map` raises an error - RSpec::Support::ObjectFormatter.format(item) - end + item.map { |subitem| surface_descriptions_in(subitem) } else item end @@ -134,14 +130,10 @@ object.clone elsif Hash === object Hash[with_matchers_cloned(object.to_a)] - elsif Struct === object + elsif Struct === object || unreadable_io?(object) object elsif should_enumerate?(object) - begin - object.map { |subobject| with_matchers_cloned(subobject) } - rescue IOError # STDOUT is enumerable but `map` raises an error - object - end + object.map { |subobject| with_matchers_cloned(subobject) } else object end @@ -157,16 +149,25 @@ # @api private def should_enumerate?(item) return false if String === item - Enumerable === item && !(Range === item) + Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) } end # :nocov: else # @api private def should_enumerate?(item) - Enumerable === item && !(Range === item) + Enumerable === item && !(Range === item) && item.none? { |subitem| subitem.equal?(item) } end end - module_function :surface_descriptions_in, :should_enumerate? + + # @api private + def unreadable_io?(object) + return false unless IO === object + object.each {} # STDOUT is enumerable but raises an error + false + rescue IOError + true + end + module_function :surface_descriptions_in, :should_enumerate?, :unreadable_io? # Wraps an item in order to surface its `description` via `inspect`. # @api private diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rspec/matchers.rb new/lib/rspec/matchers.rb --- old/lib/rspec/matchers.rb 2015-07-15 19:09:01.000000000 +0200 +++ new/lib/rspec/matchers.rb 2015-11-12 08:48:14.000000000 +0100 @@ -1005,5 +1005,33 @@ def self.is_a_describable_matcher?(obj) is_a_matcher?(obj) && obj.respond_to?(:description) end + + if RSpec::Support::Ruby.mri? && RUBY_VERSION[0, 3] == '1.9' + # @api private + # Note that `included` doesn't work for this because it is triggered + # _after_ `RSpec::Matchers` is an ancestor of the inclusion host, rather + # than _before_, like `append_features`. It's important we check this before + # in order to find the cases where it was already previously included. + def self.append_features(mod) + return super if mod < self # `mod < self` indicates a re-inclusion. + + subclasses = ObjectSpace.each_object(Class).select { |c| c < mod && c < self } + return super unless subclasses.any? + + subclasses.reject! { |s| subclasses.any? { |s2| s < s2 } } # Filter to the root ancestor. + subclasses = subclasses.map { |s| "`#{s}`" }.join(", ") + + RSpec.warning "`#{self}` has been included in a superclass (`#{mod}`) " \ + "after previously being included in subclasses (#{subclasses}), " \ + "which can trigger infinite recursion from `super` due to an MRI 1.9 bug " \ + "(https://redmine.ruby-lang.org/issues/3351). To work around this, " \ + "either upgrade to MRI 2.0+, include a dup of the module (e.g. " \ + "`include #{self}.dup`), or find a way to include `#{self}` in `#{mod}` " \ + "before it is included in subclasses (#{subclasses}). See " \ + "https://github.com/rspec/rspec-expectations/issues/814 for more info" + + super + end + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-07-15 19:09:01.000000000 +0200 +++ new/metadata 2015-11-12 08:48:14.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: rspec-expectations version: !ruby/object:Gem::Version - version: 3.3.1 + version: 3.4.0 platform: ruby authors: - Steven Baker @@ -45,7 +45,7 @@ ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ F3MdtaDehhjC -----END CERTIFICATE----- -date: 2015-07-15 00:00:00.000000000 Z +date: 2015-11-12 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rspec-support @@ -53,14 +53,14 @@ requirements: - - "~>" - !ruby/object:Gem::Version - version: 3.3.0 + version: 3.4.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: 3.3.0 + version: 3.4.0 - !ruby/object:Gem::Dependency name: diff-lcs requirement: !ruby/object:Gem::Requirement @@ -115,14 +115,14 @@ requirements: - - "~>" - !ruby/object:Gem::Version - version: '0.6' + version: 0.6.2 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '0.6' + version: 0.6.2 - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement @@ -147,7 +147,7 @@ - ".document" - ".yardopts" - Changelog.md -- License.txt +- LICENSE.md - README.md - lib/rspec/expectations.rb - lib/rspec/expectations/configuration.rb @@ -220,6 +220,6 @@ rubygems_version: 2.2.2 signing_key: specification_version: 4 -summary: rspec-expectations-3.3.1 +summary: rspec-expectations-3.4.0 test_files: [] has_rdoc: Files old/metadata.gz.sig and new/metadata.gz.sig differ