package com.codepoetics.octarine.functional.extractors; import com.codepoetics.octarine.functional.functions.Partial; import java.util.Optional; import java.util.function.Function; import java.util.function.Predicate; public interface Extractor<S, T> extends Predicate<S>, Partial<S, T> { static <S, T> Extractor<S, T> from(Predicate<? super S> predicate, Function<? super S, ? extends T> f) { return new FromPredicate<S, T>() { @Override public boolean test(S input) { return predicate.test(input); } @Override public T extract(S input) { if (test(input)) { return f.apply(input); } throw new IllegalArgumentException(String.format("%s does not match predicate", input)); } }; } static <S, T> FromPartial<S, T> from(Function<? super S, Optional<T>> f) { return f::apply; } T extract(S input); default Extractor<S, T> is(T expected) { return is(Predicate.isEqual(expected)); } default Extractor<S, T> is(Predicate<T> expected) { return Extractors.join( target -> apply(target).map(expected::test).orElse(false), this); } default <T2> Extractor<S, T2> mappedWith(Function<T, T2> next) { return from(bind(next)); } default <T2> Extractor<S, T2> flatMappedWith(Function<T, Optional<T2>> next) { return from(bind(Partial.of(next))); } interface FromPredicate<S, T> extends Extractor<S, T> { @Override default Optional<T> apply(S input) { if (!test(input)) { return Optional.empty(); } return Optional.of(extract(input)); } } interface FromPartial<S, T> extends Extractor<S, T> { @Override default boolean test(S input) { return apply(input).isPresent(); } @Override default T extract(S input) { return apply(input).orElseThrow(() -> new IllegalArgumentException( String.format("%s does not have a value for this extractor", input))); } } }