Skip to content

Commit

Permalink
feat(core): Refactor API (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseLion committed Nov 14, 2023
1 parent 6fdf740 commit 9ee0fd9
Show file tree
Hide file tree
Showing 11 changed files with 1,494 additions and 702 deletions.
123 changes: 83 additions & 40 deletions README.md

Large diffs are not rendered by default.

193 changes: 193 additions & 0 deletions src/main/java/io/github/joselion/maybe/CloseableHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package io.github.joselion.maybe;

import java.util.Optional;

import io.github.joselion.maybe.helpers.Commons;
import io.github.joselion.maybe.util.Either;
import io.github.joselion.maybe.util.function.ThrowingConsumer;
import io.github.joselion.maybe.util.function.ThrowingFunction;

/**
* CloseableHandler is an API that allows to solve or run an effect using an
* {@link AutoCloseable} resource. This resource will be automatically closed
* after the {@code solve} or the {@code effect} operation is finished.
*
* @param <T> The autoclosable type
* @param <E> The throwable type
*
* @author Jose Luis Leon
* @since v1.3.0
*/
public class CloseableHandler<T extends AutoCloseable, E extends Throwable> {

private final Either<E, T> value;

private CloseableHandler(final T resource) {
this.value = Either.ofRight(resource);
}

private CloseableHandler(final E error) {
this.value = Either.ofLeft(error);
}

/**
* Internal use method to instatiate a CloseableHandler from a given resource.
*
* @param <T> the type of the resource
* @param <E> the type of the error
* @param resource the resource to instantiate the CloseableHandler with
* @return a new instance of CloseableHandler with the given resource
*/
static <T extends AutoCloseable, E extends Throwable> CloseableHandler<T, E> from(final T resource) {
return new CloseableHandler<>(resource);
}

/**
* Internal use method to instatiate a failed CloseableHandler from an exception.
*
* @param <T> the type of the resource
* @param <E> the type of the error
* @param error the error to instantiate the failed CloseableHandler
* @return a new instance of the failed CloseableHandler with the error
*/
static <T extends AutoCloseable, E extends Throwable> CloseableHandler<T, E> failure(final E error) {
return new CloseableHandler<>(error);
}

/**
* Internal use only.
*
* @return the possible stored resource
*/
Optional<T> resource() {
return this.value.rightToOptional();
}

/**
* Internal use only.
*
* @return the possible propagated error
*/
Optional<E> error() {
return this.value.leftToOptional();
}

/**
* If the resource is present, solves the value of a throwing operation
* using a {@link ThrowingFunction} expression which has the previously
* prepared resource in the argument. The resource is automatically closed
* after the operation finishes, just like a common try-with-resources
* statement.
* <p>
* Returs a {@link SolveHandler} which allows to handle the possible error
* and return a safe value. The returned handler is {@code empty} if neither
* the resource nor the error is present.
*
* @param <S> the type of the value returned by the {@code solver}
* @param <X> the type of exception the {@code solver} may throw
* @param solver the checked function operation to solve
* @return a {@link SolveHandler} with either the value solved or the thrown
* exception to be handled
*/
public <S, X extends Throwable> SolveHandler<S, X> solve(
final ThrowingFunction<? super T, ? extends S, ? extends X> solver
) {
return this.value
.mapLeft(Commons::<X>cast)
.unwrap(
SolveHandler::ofError,
resource -> {
try (var res = resource) {
return SolveHandler.ofSuccess(solver.apply(res));
} catch (final Throwable e) { //NOSONAR
final var error = Commons.<X>cast(e);
return SolveHandler.ofError(error);
}
}
);
}

/**
* If the resource is present, solves the value of a throwing operation
* using a {@link ThrowingFunction} expression which has the previously
* prepared resource in the argument. The resource is automatically closed
* after the operation finishes, just like a common try-with-resources
* statement.
* <p>
* Returs a {@link SolveHandler} which allows to handle the possible error
* and return a safe value. The returned handler is {@code empty} if neither
* the resource nor the error is present.
*
* @param <S> the type of the value returned by the {@code solver}
* @param <X> the type of exception the {@code solver} may throw
* @param solver the checked function operation to solve
* @return a {@link SolveHandler} with either the value solved or the thrown
* exception to be handled
* @deprecated in favor of {@link #solve(ThrowingFunction)}
*/
@Deprecated(forRemoval = true, since = "3.4.0")
public <S, X extends Throwable> SolveHandler<S, X> resolveClosing(// NOSONAR
final ThrowingFunction<? super T, ? extends S, ? extends X> solver
) {
return this.solve(solver);
}

/**
* If the resource is present, runs an effect that may throw an exception
* using a {@link ThrowingConsumer} expression which has the previously
* prepared resource in the argument. The resource is automatically closed
* after the operation finishes, just like a common try-with-resources
* statement.
* <p>
* Returning then an {@link EffectHandler} which allows to handle the
* possible error. The returned handler is {@code empty} if neither the
* resource nor the error is present.
*
* @param <X> the type of exception the {@code effect} may throw
* @param effect the checked consumer operation to execute
* @return an {@link EffectHandler} with either the thrown exception to be
* handled or empty
*/
public <X extends Throwable> EffectHandler<X> effect(
final ThrowingConsumer<? super T, ? extends X> effect
) {
return this.value
.mapLeft(Commons::<X>cast)
.unwrap(
EffectHandler::ofError,
resource -> {
try (var res = resource) {
effect.accept(res);
return EffectHandler.empty();
} catch (final Throwable e) { // NOSONAR
final var error = Commons.<X>cast(e);
return EffectHandler.ofError(error);
}
}
);
}

/**
* If the resource is present, runs an effect that may throw an exception
* using a {@link ThrowingConsumer} expression which has the previously
* prepared resource in the argument. The resource is automatically closed
* after the operation finishes, just like a common try-with-resources
* statement.
* <p>
* Returning then an {@link EffectHandler} which allows to handle the
* possible error. The returned handler is {@code empty} if neither the
* resource nor the error is present.
*
* @param <X> the type of exception the {@code effect} may throw
* @param effect the checked consumer operation to execute
* @return an {@link EffectHandler} with either the thrown exception to be
* handled or empty
* @deprecated in favor of {@link #effect(ThrowingConsumer)}
*/
@Deprecated(forRemoval = true, since = "3.4.0")
public <X extends Throwable> EffectHandler<X> runEffectClosing(// NOSONAR
final ThrowingConsumer<? super T, ? extends X> effect
) {
return this.effect(effect);
}
}
47 changes: 42 additions & 5 deletions src/main/java/io/github/joselion/maybe/EffectHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,46 @@ public EffectHandler<E> catchError(final Consumer<? super E> handler) {
* @return a new {@link EffectHandler} representing the result of one of the
* invoked callback
*/
public <X extends Throwable> EffectHandler<X> runEffect(
public <X extends Throwable> EffectHandler<X> effect(
final ThrowingRunnable<? extends X> onSuccess,
final ThrowingConsumer<? super E, ? extends X> onError
) {
return this.error
.map(Maybe.<E, X>partialEffect(onError))
.orElseGet(() -> Maybe.fromEffect(onSuccess));
.map(Maybe.<E, X>partial(onError))
.orElseGet(() -> Maybe.from(onSuccess));
}

/**
* Chain another effect covering both cases of success or error of the
* previous effect in two different callbacks.
*
* @param <X> the type of the error the new effect may throw
* @param onSuccess a runnable checked function to run in case of succeess
* @param onError a runnable checked function to run in case of error
* @return a new {@link EffectHandler} representing the result of one of the
* invoked callback
* @deprecated in favor of {@link #effect(ThrowingRunnable, ThrowingConsumer)}
*/
@Deprecated(forRemoval = true, since = "3.4.0")
public <X extends Throwable> EffectHandler<X> runEffect(// NOSONAR
final ThrowingRunnable<? extends X> onSuccess,
final ThrowingConsumer<? super E, ? extends X> onError
) {
return this.effect(onSuccess, onError);
}

/**
* Chain another effect if the previous completed with no error. Otherwise,
* ignores the current error and return a new {@link EffectHandler} that is
* either empty or has a different error cause by the next effect.
*
* @param <X> the type of the error the new effect may throw
* @param effect a runnable checked function to run in case of succeess
* @return a new {@link EffectHandler} that is either empty or with the
* thrown error
*/
public <X extends Throwable> EffectHandler<X> effect(final ThrowingRunnable<? extends X> effect) {
return this.effect(effect, err -> { });
}

/**
Expand All @@ -174,9 +207,13 @@ public <X extends Throwable> EffectHandler<X> runEffect(
* @param effect a runnable checked function to run in case of succeess
* @return a new {@link EffectHandler} that is either empty or with the
* thrown error
* @deprecated in favor of {@link #effect(ThrowingRunnable)}
*/
public <X extends Throwable> EffectHandler<X> runEffect(final ThrowingRunnable<? extends X> effect) {
return this.runEffect(effect, err -> { });
@Deprecated(forRemoval = true, since = "3.4.0")
public <X extends Throwable> EffectHandler<X> runEffect(// NOSONAR
final ThrowingRunnable<? extends X> effect
) {
return this.effect(effect);
}

/**
Expand Down
Loading

0 comments on commit 9ee0fd9

Please sign in to comment.