Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

end_with takes the assumption that the receiver is a hash, or string. #1025

Open
envygeeks opened this issue Nov 20, 2017 · 3 comments
Open

Comments

@envygeeks
Copy link

[14] pry(<REMOVED>)> rtn.class # => Pathutil
[15] pry(<REMOVED>)> rtn.end_with?("/hello") # => true
[16] pry(<REMOVED>)> expect(rtn).to end_with("/hello")

RSpec::Expectations::ExpectationNotMetError
# => : expected #<Pathutil:/hello> to end with "/hello", but it cannot 
#   be indexed using #[]
envygeeks added a commit to envygeeks/jekyll-assets that referenced this issue Nov 20, 2017
@myronmarston
Copy link
Member

start_with and end_with don't assume the receiver is a hash; they assume the receiver is an object that implements the [] indexing operator so that the matcher can directly access the elements at the start (using [0], [0, 5], etc for start_with) or at the end (using [-1], [-5, 5], etc for end_with). In fact, the start_with and end_with matchers don't work on hashes, as there internal ordering, where it exists (e.g. MRI 1.9+), is not exposed by the [] operator.

Anyhow, if you want it to work with an object of your own, you can implement [] on it, and the matcher should "just work". start_with and end_with have never checked a predicate like start_with? or end_with?. I think it would be reasonable to do so. Do you want to open a PR adding that?

@TravisSpangle
Copy link

Something like ?

        # @api private
        # @return [String]
        def failure_message
          super.tap do |msg|
            if @actual_does_not_have_ordered_elements
              msg << ", but it does not have ordered elements"
            elsif !actual.respond_to?(:start_with?)
              msg << ", but #{actual.inspect} does not respond to start_with?"
            elsif !actual.respond_to?(:end_with?)
              msg << ", but #{actual.inspect} does not respond to end_with?"
            elsif !actual.respond_to?(:[])
              msg << ", but it cannot be indexed using #[]"
            end
          end
        end

@myronmarston
Copy link
Member

@TravisSpangle - the fix for this is going to require a change the match logic (so that if the object responds to the appropriate predicate method, it is used), as well as a change to failure_message so that when the predicate approach was used, the failure message mentions it.

(And sorry about the delayed response...)

bclayman-sq added a commit to bclayman-sq/rspec-expectations that referenced this issue Oct 13, 2021
This addresses issue rspec#1025.

With this change, the StartWith matcher will rely on an object's
start_with? method if available.  Similarly, the EndWith matcher
will rely on an object's end_with? method if available.

This is especially useful when a class implements start_with?
but not the indexing operator, or end_with? but not the indexing
operator.
bclayman-sq added a commit to bclayman-sq/rspec-expectations that referenced this issue Oct 13, 2021
This addresses issue rspec#1025.

With this change, the StartWith matcher will rely on an object's
start_with? method if available.  Similarly, the EndWith matcher
will rely on an object's end_with? method if available.

This is especially useful when a class implements start_with?
but not the indexing operator, or end_with? but not the indexing
operator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants