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

Is there a type-safe matcher creator method that allows creation by lambda? #276

Open
cable729 opened this issue Oct 21, 2019 · 5 comments

Comments

@cable729
Copy link

I wrote the following, that I haven't seen anywhere else. I think it would be a good addition to Hamcrest. Usage is something like matcher("nonempty string", s -> s.length() > 0). This also Kotlin-friendly because the lambda is the last parameter. Usage in Kotlin would be something like matcher("nonempty string") { it.length() > 0 }. Here's the code:

  /** Allows creating a {@link Matcher} in lambda form. */
  public static <T> Matcher<T> matcher(String description, Predicate<T> matchesPredicate) {
    return new CustomTypeSafeMatcherFactory<>(description, matchesPredicate);
  }

  static final class CustomTypeSafeMatcherFactory<T> extends CustomTypeSafeMatcher<T> {
    private final Predicate<T> matchesPredicate;

    CustomTypeSafeMatcherFactory(String description, Predicate<T> matchesPredicate) {
      super(description);
      this.matchesPredicate = matchesPredicate;
    }

    @Override
    protected boolean matchesSafely(T item) {
      return matchesPredicate.apply(item);
    }
  }
@nibsi
Copy link

nibsi commented Oct 25, 2019

Seconded. I already have a method like this in a library I wrote. It looks like this:

  /**
   * Creates a requirement from a description and a predicate.
   *
   * @param <T>         the type of argument to validate.
   *
   * @param description a description of arguments that match the requirement.
   * @param predicate   a predicate that determines whether an argument matches the requirement.
   *                    {@code null} arguments will never match and the predicate is only applied
   *                    when the argument isn't {@code null}.
   *
   * @return a matcher with the given {@code description} that will match an argument if and only if
   *         the argument is not {@code null} and {@code predicate} returns {@code true} when applied to the argument.
   */
  public static <T> Matcher<T> createRequirement(String description, Predicate<? super T> predicate) {
    return new CustomTypeSafeMatcher<T>(description) {
      @Override
      protected boolean matchesSafely(T argument) {
        return predicate.test(argument);
      }
    };
  }

It appears my implementation is almost identical to that of @cable729, leading me to believe this would be a good addition to Hamcrest.

The fact that I used an anonymous class instead of a nested class is a matter of taste. The method name and documentation follows conventions in my project, and can be adapted to whatever is right for Hamcrest.

I strongly recommend however, that the predicate is contravariant instead of invariant.

Here is an example of where I use the method:

  /**
   * Creates the requirement that a string is stripped of leading and trailing whitespace.
   *
   * @return a matcher that will match a string if and only if the string is not {@code null}
   *         and is {@linkplain String#strip() stripped} of leading and trailing whitespace characters.
   */
  public static Matcher<String> strippedString() {
    return createRequirement(
      "a string stripped of leading and trailing whitespace",
      string -> string.strip().equals(string)
    );
  }

@Blackwolf291
Copy link

My only issue with this method is that it does not provide for specifying a mismatch. if that is not a concern in your project I can see how this would be very useful.

@62mkv
Copy link

62mkv commented Mar 26, 2020

has this received any attention from maintainers? here's another variation of the same theme, and, just as commenters under that page, I am a bit surprised that hamcrest does not provide for this out of the box.. http://tadams289.blogspot.com/2014/04/hamcrest-matching-with-lambdas.html (NB: the linked page is from 2014!!)

@nhojpatrick
Copy link
Member

At the moment, nope, i'm still trying to fully understand the internals in my spare time. I'm able to merge but I'm unsure who owns the domain name and who has the accounts/keys for a release so even if i approved and merged, i wouldn't be able to do a release...

@jglick
Copy link

jglick commented Aug 24, 2023

Similar to #300?

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

6 participants