Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Extract Rails extension to have matcher #5

Merged
merged 9 commits into from

4 participants

@soulcutter
Collaborator

I'm not sure this is the best way to conditionally load the matcher extension, but I figured it's at least a workable first pass.

This is half of rspec/rspec-rails#808

@soulcutter soulcutter referenced this pull request in rspec/rspec-rails
Merged

Remove the have extension #810

@soulcutter
Collaborator

Looks like this is failing on Travis - it was passing for me locally so I'm not immediately certain what is amiss. HMM.

lib/rspec/collection_matchers/rails.rb
@@ -0,0 +1,8 @@
+module RSpec
+ module CollectionMatchers
+ module Rails
@hugobarauna Owner

Do we need to define an empty module?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
rspec-collection_matchers.gemspec
@@ -21,4 +21,5 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency "rspec-expectations", ">= 2.99.0.pre"
spec.add_development_dependency "bundler", "~> 1.3"
+ spec.add_development_dependency(%q<activesupport>, [">= 3.0"])
@hugobarauna Owner

This is just style, but what do you think about changing that to:

 spec.add_development_dependency "activesupport" , ">= 3.0"
@hugobarauna Owner

By the way, can you just move that dependency definition to the Gemfile? I was following the convention of putting development dependencies in the Gemfile instead of using the gemspec for that.

@soulcutter Collaborator

Sure. I copied that over from rspec-rails' gemspec, which is where the funky string came from if you were wondering :smile:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@hugobarauna
Owner

@soulcutter Maybe it's failing because the Rails constant is not defined. If that's the problem, we could fix that by just stubing that constant using RSpec itself.

@soulcutter
Collaborator

It shouldn't have to do with the Rails constant - the spec explicitly requires the have extensions without checking the constant at all. I'm more thinking it may have to do with me testing against the master branches of everything vs travis building with the 2-99-maintenance branch.

@JonRowe
Owner

@soulcutter Although you've now linked this to master, it needs to work with 2-99-maintenance too, as otherwise there isn't a smooth upgrade path

Gemfile
@@ -7,12 +7,15 @@ gemspec
if File.exist?(library_path)
gem lib, :path => library_path
else
- gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => "2-99-maintenance"
+ gem lib, :git => "git://github.com/rspec/#{lib}.git", :branch => "master"
@JonRowe Owner
JonRowe added a note

We need to ensure this works against 2-99-maintenance and master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Gemfile
((6 lines not shown))
end
end
-gem "cucumber", "~> 1.1.9"
-gem "aruba", "~> 0.5"
-gem "rake", "~> 10.0.0"
+gem 'cucumber', '~> 1.1.9'
+gem 'aruba', '~> 0.5'
+gem 'rake', '~> 10.0.0'
@JonRowe Owner
JonRowe added a note

Despacing these is pretty pointliness, goes against what we do in other Gemfiles elsewhere, and is contrary to common practise.

@soulcutter Collaborator
@JonRowe Owner
JonRowe added a note

It's just an unnecessary change here, out of keeping with the rest of rspec, and yeah, I like lined up things, I find it easier to scan.

@JonRowe Owner
JonRowe added a note

(In my opinion :) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/rspec/collection_matchers/rails/have_extensions.rb
((2 lines not shown))
+
+require 'active_support/concern'
+require 'active_support/core_ext/module/aliasing'
+
+module RSpec
+ module CollectionMatchers
+ module Rails
+ module HaveExtensions
+ extend ActiveSupport::Concern
+
+ # @api private
+ #
+ # Enhances the failure message for `to have(n)` matchers
+ def failure_message_for_should_with_errors_on_extensions
+ return "expected #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}, got #{@actual}" if @collection_name == :errors_on
+ return "expected #{relativities[@relativity]}#{@expected} error on :#{@args[0]}, got #{@actual}" if @collection_name == :error_on
@JonRowe Owner
JonRowe added a note

Could we streamline these two by using interpolation? How about:

if [:errors_on,:error_on].include? @collection_name
  return "expected #{relativities[@relativity]}#{@expected} #{@collection_name.to_s.gsub('_',' ')} :#{@args[0]}, got #{@actual}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/rspec/collection_matchers/rails/have_extensions.rb
((11 lines not shown))
+
+ # @api private
+ #
+ # Enhances the failure message for `to have(n)` matchers
+ def failure_message_for_should_with_errors_on_extensions
+ return "expected #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}, got #{@actual}" if @collection_name == :errors_on
+ return "expected #{relativities[@relativity]}#{@expected} error on :#{@args[0]}, got #{@actual}" if @collection_name == :error_on
+ return failure_message_for_should_without_errors_on_extensions
+ end
+
+ # @api private
+ #
+ # Enhances the description for `to have(n)` matchers
+ def description_with_errors_on_extensions
+ return "have #{relativities[@relativity]}#{@expected} errors on :#{@args[0]}" if @collection_name == :errors_on
+ return "have #{relativities[@relativity]}#{@expected} error on :#{@args[0]}" if @collection_name == :error_on
@JonRowe Owner
JonRowe added a note

These are similar to lines 16-17, prehaps it's worth extracting?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...pec/collection_matchers/rails/have_extensions_spec.rb
((23 lines not shown))
+ it "provides a failure message including the number actually given" do
+ lambda {
+ [1].should have(3).errors_on(:whatever)
+ }.should raise_error("expected 3 errors on :whatever, got 1")
+ end
+ end
+
+ describe "have something other than error_on or errors_on" do
+ it "has a standard rspec failure message" do
+ lambda {
+ [1,2,3].should have(2).elements
+ }.should raise_error("expected 2 elements, got 3")
+ end
+
+ it "has a standard rspec description" do
+ have(2).elements.description.should == "have 2 elements"
@JonRowe Owner
JonRowe added a note

I was a little bit WTF BBQ at the naked have(2) call, is it worth instantiating the matcher directly to make it more clear what it's doing in this circumstances?

@soulcutter Collaborator
@JonRowe Owner
JonRowe added a note

Taking the time to refactor when we can is a good thing:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@myronmarston

Bump..this needs to still be worked out.

@myronmarston myronmarston referenced this pull request
Closed

Cut a release #14

@hugobarauna
Owner

@soulcutter are you going to continue working on this? I can work on that if you're not going to.

@soulcutter
Collaborator

I think I solved the 2.99 compatibility issue, let's see what Travis says…

EDIT: Nope… looks like something is different in 1.8.x rubies.

@soulcutter soulcutter Fix Ruby 1.8.x compatibility
instance_methods returns an array of symbols in Ruby 1.9+
but before that it was an array of strings.
80b75a0
@soulcutter
Collaborator

Looks like the build works now. Any other feedback?

...pec/collection_matchers/rails/have_extensions_spec.rb
((29 lines not shown))
+
+ describe "have something other than error_on or errors_on" do
+ it "has a standard rspec failure message" do
+ lambda {
+ [1,2,3].should have(2).elements
+ }.should raise_error("expected 2 elements, got 3")
+ end
+
+ it "has a standard rspec description" do
+ RSpec::CollectionMatchers::Have
+ have(2).elements.description.should == "have 2 elements"
+ end
+ end
+ end
+end
+
@JonRowe Owner
JonRowe added a note

excess white space

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...pec/collection_matchers/rails/have_extensions_spec.rb
((19 lines not shown))
+ it "provides a description including the name of what the error is on" do
+ have(2).errors_on(:whatever).description.should == "have 2 errors on :whatever"
+ end
+
+ it "provides a failure message including the number actually given" do
+ lambda {
+ [1].should have(3).errors_on(:whatever)
+ }.should raise_error("expected 3 errors on :whatever, got 1")
+ end
+ end
+
+ describe "have something other than error_on or errors_on" do
+ it "has a standard rspec failure message" do
+ lambda {
+ [1,2,3].should have(2).elements
+ }.should raise_error("expected 2 elements, got 3")
@JonRowe Owner
JonRowe added a note

We should change these to expect {}.to raise_error given our preference for the new syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/rspec/collection_matchers.rb
@@ -1,3 +1,4 @@
require 'rspec/collection_matchers/version'
require 'rspec/collection_matchers/matchers'
require 'rspec/collection_matchers/have'
+require 'rspec/collection_matchers/rails' if defined? Rails
@JonRowe Owner
JonRowe added a note

Is this enough of a check?

@soulcutter Collaborator

Technically this will break if Rails is defined, but there's no activesupport for alias_method_chain (which is used in the impl).

In practice I'm not sure that will come up, but we could guard against that to be airtight. Otherwise it's not really a problem to include the matcher, even mistakenly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@soulcutter
Collaborator

@hugobarauna I'm all done with this one - care to comment / merge?

lib/rspec/collection_matchers/rails/have_extensions.rb
@@ -0,0 +1,58 @@
+require 'rspec/collection_matchers/have'
@hugobarauna Owner

I'm not sure if we need that require here, since we're already loading that file in lib/rspec/collection_matchers/rails

@soulcutter Collaborator

I'm not sure rails.rb really deserves to exist, honestly. It's not actually loaded there, though, it's really coming from lib/rspec/collection_matchers.rb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@hugobarauna
Owner

:shipit:

@soulcutter soulcutter merged commit a8024af into master
@soulcutter soulcutter deleted the rails-have-extensions branch
@alexrothenberg alexrothenberg referenced this pull request from a commit in alexrothenberg/rspec-rails
@soulcutter soulcutter Remove the have extension
This functionality was extracted into
rspec/rspec-collection_matchers#5

Fixes #808
7fd43e9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
5 Gemfile
@@ -12,13 +12,16 @@ gemspec
end
end
-# only the master branche is supported on rspec-support
+# only the master branch is supported on rspec-support
gem "rspec-support", :git => "git://github.com/rspec/rspec-support.git"
gem "cucumber", "~> 1.1.9"
gem "aruba", "~> 0.5"
gem "rake", "~> 10.0.0"
+# for optional rails support
+gem 'activesupport', RUBY_VERSION < "1.9.3" ? '~> 3.0' : '>= 3.0'
+
platform :rbx do
gem 'rubysl'
end
View
6 lib/rspec/collection_matchers.rb
@@ -1,3 +1,9 @@
require 'rspec/collection_matchers/version'
require 'rspec/collection_matchers/matchers'
require 'rspec/collection_matchers/have'
+
+begin
+ require 'rspec/collection_matchers/rails/have_extensions'
+rescue LoadError
+ # must not have rails
+end
View
56 lib/rspec/collection_matchers/rails/have_extensions.rb
@@ -0,0 +1,56 @@
+require 'active_support/concern'
+require 'active_support/core_ext/module/aliasing'
+
+module RSpec
+ module CollectionMatchers
+ module Rails
+ module HaveExtensions
+ extend ActiveSupport::Concern
+
+ # @api private
+ #
+ # Enhances the failure message for `to have(n)` matchers
+ def failure_message_with_errors_on_extensions
+ return errors_on_message(:expected, ", got #{@actual}") if is_errors_on?
+ failure_message_without_errors_on_extensions
+ end
+
+ # @api private
+ #
+ # Enhances the description for `to have(n)` matchers
+ def description_with_errors_on_extensions
+ return errors_on_message(:have) if is_errors_on?
+ description_without_errors_on_extensions
+ end
+
+ included do
+ alias_method_chain :failure_message, :errors_on_extensions
+ alias_method_chain :description, :errors_on_extensions
+
+ ## For RSpec 2.99 compatibility
+ rspec_2x_matcher_failure_method = :failure_message_for_should
+ rspec_2x_matcher_failure_method = rspec_2x_matcher_failure_method.to_s if RUBY_VERSION < '1.9'
+ if instance_methods.include? rspec_2x_matcher_failure_method
+ alias failure_message_for_should_with_errors_on_extensions failure_message_with_errors_on_extensions
+ alias_method_chain :failure_message_for_should, :errors_on_extensions
+ alias failure_message_without_errors_on_extensions failure_message_for_should_without_errors_on_extensions
+ end
+ end
+
+ # @api private
+ def is_errors_on?
+ [:errors_on, :error_on].include? @collection_name
+ end
+
+ # @api private
+ def errors_on_message(prefix, suffix = nil)
+ "#{prefix} #{relative_expectation} #{@collection_name.to_s.gsub('_', ' ')} :#{@args[0]}#{suffix}"
+ end
+ end
+ end
+ end
+end
+
+RSpec::CollectionMatchers::Have.class_eval do
+ include RSpec::CollectionMatchers::Rails::HaveExtensions
+end
View
42 spec/rspec/collection_matchers/rails/have_extensions_spec.rb
@@ -0,0 +1,42 @@
+require "spec_helper"
+require 'rspec/collection_matchers/rails/have_extensions'
+
+module RSpec::CollectionMatchers::Rails
+ describe HaveExtensions do
+ describe "error_on" do
+ it "provides a description including the name of what the error is on" do
+ expect(have(1).error_on(:whatever).description).to eq "have 1 error on :whatever"
+ end
+
+ it "provides a failure message including the number actually given" do
+ expect {
+ [].should have(1).error_on(:whatever)
+ }.to raise_error("expected 1 error on :whatever, got 0")
+ end
+ end
+
+ describe "errors_on" do
+ it "provides a description including the name of what the error is on" do
+ expect(have(2).errors_on(:whatever).description).to eq "have 2 errors on :whatever"
+ end
+
+ it "provides a failure message including the number actually given" do
+ expect {
+ [1].should have(3).errors_on(:whatever)
+ }.to raise_error("expected 3 errors on :whatever, got 1")
+ end
+ end
+
+ describe "have something other than error_on or errors_on" do
+ it "has a standard rspec failure message" do
+ expect {
+ [1,2,3].should have(2).elements
+ }.to raise_error("expected 2 elements, got 3")
+ end
+
+ it "has a standard rspec description" do
+ expect(have(2).elements.description).to eq "have 2 elements"
+ end
+ end
+ end
+end
Something went wrong with that request. Please try again.