Skip to content

Commit

Permalink
Merge pull request #29 from code77se/then-resolve
Browse files Browse the repository at this point in the history
Add Promise methods thenResolve, thenReject and tap
  • Loading branch information
code77se authored Feb 10, 2017
2 parents a88d105 + cbc1568 commit 086997d
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
1 change: 1 addition & 0 deletions jq/src/main/java/se/code77/jq/JQ.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public interface DeferredHandler<V> {
* operation is complete.
*
* @param <V> Type of the promise you want to convert to an empty (value) value.
* @deprecated Use {@link Promise#thenResolve(Object)} instead
*/
public static final class OnFulfilledVoidCallback<V> implements OnFulfilledCallback<V, Void> {
@Override
Expand Down
39 changes: 39 additions & 0 deletions jq/src/main/java/se/code77/jq/Promise.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,19 @@ public interface OnProgressedCallback {
void onProgressed(float progress);
}

/**
* Callback interface used for {@link #tap(OnTapCallback)} used to observe fulfilled promises
* without modifying the next promise.
* @param <V> Type of value carried by the promise
*/
public interface OnTapCallback<V> {
/**
* The promise has been fulfilled with the given value
* @param value Value
*/
void onTap(V value);
}

/**
* An exception thrown by a promise which is terminated without any
* rejection callback. A promise is terminated by calling
Expand Down Expand Up @@ -375,6 +388,32 @@ public <NV> Promise<NV> then(
*/
public <NV> Promise<NV> then(OnFulfilledCallback<V, NV> onFulfilled);

/**
* Convenience method, equivalent to adding a fulfillment callback that merely returns the given value.
*
* @param nextValue Value to resolve the next promise with
* @param <NV> Type of the value carried by the next promise
* @return A new promise that, provided the current promise is resolved, will be resolved with the given value.
*/
public <NV> Promise<NV> thenResolve(NV nextValue);

/**
* Convenience method, equivalent to adding a fulfillment callback that merely throws the given exception
* @param reason Exception to reject the next promise with
* @param <NV> Type of the value carried by the next promise
* @return A new promise that, provided the current promise is resolved, will be rejected with the given reason.
*/
public <NV> Promise<NV> thenReject(Exception reason, Class<NV> nextValueClass);

/**
* Observe the state of this promise by adding a handler that will be invoked when the promise
* is fulfilled, but without modifying the next promise.
*
* @param onTap Simple, observe-only fulfillment handler
* @return A new promise which will inherit the state of the current promise
*/
public Promise<V> tap(OnTapCallback<V> onTap);

/**
* Like {@link Promise#then(OnFulfilledCallback, OnRejectedCallback)} but only for promised List values. The
* elements in the list will be spread as individual arguments on the supplied callback, which
Expand Down
35 changes: 35 additions & 0 deletions jq/src/main/java/se/code77/jq/PromiseImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,41 @@ public <NV> Promise<NV> then(OnFulfilledCallback<V, NV> onFulfilled) {
return then(onFulfilled, null);
}

@Override
public <NV> Promise<NV> thenResolve(final NV nextValue) {
return then(new OnFulfilledCallback<V, NV>() {
@Override
public Future<NV> onFulfilled(V value) throws Exception {
return Value.wrap(nextValue);
}
});
}

@Override
public <NV> Promise<NV> thenReject(final Exception reason, Class<NV> nextValueClass) {
return then(new OnFulfilledCallback<V, NV>() {
@Override
public Future<NV> onFulfilled(V value) throws Exception {
throw reason;
}
});
}

@Override
public Promise<V> tap(final OnTapCallback<V> onTap) {
return then(new OnFulfilledCallback<V, V>() {
@Override
public Future<V> onFulfilled(V value) throws Exception {
try {
onTap.onTap(value);
} catch (RuntimeException e) {
// Swallow
}
return Value.wrap(value);
}
});
}

@Override
public <NV> Promise<NV> spread(final OnFulfilledSpreadCallback<V, NV> onFulfilled, OnRejectedCallback<NV> onRejected) {
if (onFulfilled == null) {
Expand Down
69 changes: 69 additions & 0 deletions jq/src/test/java/se/code77/jq/PromiseTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -1022,4 +1022,73 @@ public Future<Void> onFulfilled(Double e1, Integer e2) throws Exception {
assertData(spread, 500);
}

@Test
public void thenResolve() {
final Promise<String> p = JQ.resolve(1).thenResolve(TEST_VALUE1);
final BlockingDataHolder<String> then1 = new BlockingDataHolder<>();

p.then(new DataFulfilledCallback<String, Void>(then1));

assertData(then1, 2000, TEST_VALUE1);
assertResolved(p, TEST_VALUE1);
}

@Test
public void thenReject() {
final Promise<String> p = JQ.resolve(1).thenReject(TEST_REASON1, String.class);
final BlockingDataHolder<Exception> fail1 = new BlockingDataHolder<>();

p.fail(new DataRejectedCallback<String>(fail1));

assertData(fail1, 2000, TEST_REASON1);
assertRejected(p, TEST_REASON1);
}

@Test
public void tap_isResolved() {
final Promise<String> p = JQ.resolve(TEST_VALUE1);
final BlockingDataHolder<String> tap1 = new BlockingDataHolder<>();

p.tap(new Promise.OnTapCallback<String>() {
@Override
public void onTap(String value) {
tap1.set(value);
}
});

assertData(tap1, 2000, TEST_VALUE1);
assertResolved(p, TEST_VALUE1);
}

@Test
public void tap_isRejected() {
final Promise<String> p = JQ.reject(TEST_REASON1);
final BlockingDataHolder<String> tap1 = new BlockingDataHolder<>();

p.tap(new Promise.OnTapCallback<String>() {
@Override
public void onTap(String value) {
tap1.set(value);
}
});

assertNoData(tap1, 2000);
assertRejected(p, TEST_REASON1);
}

@Test
public void tap_isTapExceptionIgnored() {
final Promise<String> p = JQ.resolve(TEST_VALUE1);
final BlockingDataHolder<String> then1 = new BlockingDataHolder<>();

p.tap(new Promise.OnTapCallback<String>() {
@Override
public void onTap(String value) {
throw new RuntimeException("Should be ignored");
}
}).then(new DataFulfilledCallback<>(then1));

assertData(then1, 2000, TEST_VALUE1);
assertResolved(p, TEST_VALUE1);
}
}

0 comments on commit 086997d

Please sign in to comment.