From 6e1a1f71f2142559daaf1fc861ac798dc9e8f4ed Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 2 Jul 2013 22:04:09 -0700 Subject: [PATCH 01/22] Make rxjava-core typesafe Conflicts: rxjava-core/src/main/java/rx/Observable.java rxjava-core/src/main/java/rx/observables/BlockingObservable.java rxjava-core/src/main/java/rx/subjects/PublishSubject.java --- .../java/rx/observables/SwingObservable.java | 2 - .../swing/sources/AbstractButtonSource.java | 6 +- .../java/rx/swing/sources/KeyEventSource.java | 14 +- rxjava-core/src/main/java/rx/Observable.java | 1279 +---------------- .../rx/observables/BlockingObservable.java | 207 --- .../rx/operators/OperationCombineLatest.java | 22 +- .../main/java/rx/subjects/AsyncSubject.java | 11 +- .../main/java/rx/subjects/PublishSubject.java | 27 +- .../main/java/rx/subjects/ReplaySubject.java | 8 +- 9 files changed, 57 insertions(+), 1519 deletions(-) diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java index fa9ecd3095..a2facde800 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java @@ -15,8 +15,6 @@ */ package rx.observables; -import static rx.Observable.filter; - import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/AbstractButtonSource.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/AbstractButtonSource.java index 22a2ce78fc..ef3612b080 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/AbstractButtonSource.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/AbstractButtonSource.java @@ -69,7 +69,7 @@ public void testObservingActionEvents() { @SuppressWarnings("unchecked") Action1 action = mock(Action1.class); @SuppressWarnings("unchecked") - Action1 error = mock(Action1.class); + Action1 error = mock(Action1.class); Action0 complete = mock(Action0.class); final ActionEvent event = new ActionEvent(this, 1, "command"); @@ -85,7 +85,7 @@ void testAction() { Subscription sub = fromActionOf(button).subscribe(action, error, complete); verify(action, never()).call(Matchers.any()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); button.testAction(); @@ -97,7 +97,7 @@ void testAction() { sub.unsubscribe(); button.testAction(); verify(action, times(2)).call(Matchers.any()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); } } diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java index d6f294cebe..3716b599f9 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java @@ -113,7 +113,7 @@ public void testObservingKeyEvents() { @SuppressWarnings("unchecked") Action1 action = mock(Action1.class); @SuppressWarnings("unchecked") - Action1 error = mock(Action1.class); + Action1 error = mock(Action1.class); Action0 complete = mock(Action0.class); final KeyEvent event = mock(KeyEvent.class); @@ -121,7 +121,7 @@ public void testObservingKeyEvents() { Subscription sub = fromKeyEventsOf(comp).subscribe(action, error, complete); verify(action, never()).call(Matchers.any()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); fireKeyEvent(event); @@ -133,7 +133,7 @@ public void testObservingKeyEvents() { sub.unsubscribe(); fireKeyEvent(event); verify(action, times(2)).call(Matchers.any()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); } @@ -142,19 +142,19 @@ public void testObservingPressedKeys() { @SuppressWarnings("unchecked") Action1> action = mock(Action1.class); @SuppressWarnings("unchecked") - Action1 error = mock(Action1.class); + Action1 error = mock(Action1.class); Action0 complete = mock(Action0.class); Subscription sub = currentlyPressedKeysOf(comp).subscribe(action, error, complete); InOrder inOrder = inOrder(action); inOrder.verify(action, times(1)).call(Collections.emptySet()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); fireKeyEvent(keyEvent(1, KeyEvent.KEY_PRESSED)); inOrder.verify(action, times(1)).call(new HashSet(asList(1))); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); fireKeyEvent(keyEvent(2, KeyEvent.KEY_PRESSED)); @@ -173,7 +173,7 @@ public void testObservingPressedKeys() { fireKeyEvent(keyEvent(1, KeyEvent.KEY_PRESSED)); inOrder.verify(action, never()).call(Matchers.>any()); - verify(error, never()).call(Matchers.any()); + verify(error, never()).call(Matchers.any()); verify(complete, never()).call(); } diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index f6431926e9..62f8c89ddf 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -288,7 +288,7 @@ public Subscription subscribe(final Map callbacks) { return protectivelyWrapAndSubscribe(new Observer() { @Override - public void onCompleted() { + public void onCompleted() { Object onComplete = callbacks.get("onCompleted"); if (onComplete != null) { Functions.from(onComplete).call(); @@ -307,61 +307,17 @@ public void onError(Throwable e) { } @Override - public void onNext(Object args) { + public void onNext(Object args) { onNext.call(args); } - }); + }); } public Subscription subscribe(final Map callbacks, Scheduler scheduler) { return subscribeOn(scheduler).subscribe(callbacks); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Subscription subscribe(final Object o) { - if (o instanceof Observer) { - // in case a dynamic language is not correctly handling the overloaded methods and we receive an Observer just forward to the correct method. - return subscribe((Observer) o); - } - - if (o == null) { - throw new IllegalArgumentException("onNext can not be null"); - } - - // lookup and memoize onNext - final FuncN onNext = Functions.from(o); - - /** - * Wrapping since raw functions provided by the user are being invoked. - * - * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" - */ - return protectivelyWrapAndSubscribe(new Observer() { - - @Override - public void onCompleted() { - // do nothing - } - - @Override - public void onError(Throwable e) { - handleError(e); - throw new OnErrorNotImplementedException(e); - } - - @Override - public void onNext(Object args) { - onNext.call(args); - } - - }); - } - - public Subscription subscribe(final Object o, Scheduler scheduler) { - return subscribeOn(scheduler).subscribe(o); - } - public Subscription subscribe(final Action1 onNext) { if (onNext == null) { throw new IllegalArgumentException("onNext can not be null"); @@ -397,48 +353,6 @@ public Subscription subscribe(final Action1 onNext, Scheduler scheduler) { return subscribeOn(scheduler).subscribe(onNext); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Subscription subscribe(final Object onNext, final Object onError) { - if (onNext == null) { - throw new IllegalArgumentException("onNext can not be null"); - } - if (onError == null) { - throw new IllegalArgumentException("onError can not be null"); - } - - // lookup and memoize onNext - final FuncN onNextFunction = Functions.from(onNext); - - /** - * Wrapping since raw functions provided by the user are being invoked. - * - * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" - */ - return protectivelyWrapAndSubscribe(new Observer() { - - @Override - public void onCompleted() { - // do nothing - } - - @Override - public void onError(Throwable e) { - handleError(e); - Functions.from(onError).call(e); - } - - @Override - public void onNext(Object args) { - onNextFunction.call(args); - } - - }); - } - - public Subscription subscribe(final Object onNext, final Object onError, Scheduler scheduler) { - return subscribeOn(scheduler).subscribe(onNext, onError); - } - public Subscription subscribe(final Action1 onNext, final Action1 onError) { if (onNext == null) { throw new IllegalArgumentException("onNext can not be null"); @@ -477,51 +391,6 @@ public Subscription subscribe(final Action1 onNext, final Action1 return subscribeOn(scheduler).subscribe(onNext, onError); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Subscription subscribe(final Object onNext, final Object onError, final Object onComplete) { - if (onNext == null) { - throw new IllegalArgumentException("onNext can not be null"); - } - if (onError == null) { - throw new IllegalArgumentException("onError can not be null"); - } - if (onComplete == null) { - throw new IllegalArgumentException("onComplete can not be null"); - } - - // lookup and memoize onNext - final FuncN onNextFunction = Functions.from(onNext); - - /** - * Wrapping since raw functions provided by the user are being invoked. - * - * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" - */ - return protectivelyWrapAndSubscribe(new Observer() { - - @Override - public void onCompleted() { - Functions.from(onComplete).call(); - } - - @Override - public void onError(Throwable e) { - handleError(e); - Functions.from(onError).call(e); - } - - @Override - public void onNext(Object args) { - onNextFunction.call(args); - } - - }); - } - - public Subscription subscribe(final Object onNext, final Object onError, final Object onComplete, Scheduler scheduler) { - return subscribeOn(scheduler).subscribe(onNext, onError, onComplete); - } - public Subscription subscribe(final Action1 onNext, final Action1 onError, final Action0 onComplete) { if (onNext == null) { throw new IllegalArgumentException("onNext can not be null"); @@ -886,49 +755,6 @@ public static Observable create(Func1, Subscription> func) { return new Observable(func); } - /** - * Creates an Observable that will execute the given function when an {@link Observer} - * subscribes to it. - *

- * - *

- * This method accepts {@link Object} to allow different languages to pass in methods using - * {@link FunctionLanguageAdaptor}. - *

- * Write the function you pass to create so that it behaves as an Observable: It - * should invoke the Observer's {@link Observer#onNext onNext}, - * {@link Observer#onError onError}, and {@link Observer#onCompleted onCompleted} methods - * appropriately. - *

- * A well-formed Observable must invoke either the Observer's onCompleted method - * exactly once or its onError method exactly once. - *

- * See Rx Design Guidelines (PDF) - * for detailed information. - * - * @param - * the type of the items that this Observable emits - * @param func - * a function that accepts an {@code Observer}, invokes its - * {@code onNext}, {@code onError}, and {@code onCompleted} methods - * as appropriate, and returns a {@link Subscription} that allows the Observer to - * cancel the subscription - * @return an Observable that, when an {@link Observer} subscribes to it, will execute the given - * function - */ - public static Observable create(final Object func) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(func); - return create(new Func1, Subscription>() { - - @Override - public Subscription call(Observer t1) { - return (Subscription) _f.call(t1); - } - - }); - } - /** * Returns an Observable that emits no data to the {@link Observer} and immediately invokes * its {@link Observer#onCompleted onCompleted} method. @@ -981,33 +807,7 @@ public static Observable filter(Observable that, Func1 pre /** * Filters an Observable by discarding any items it emits that do not satisfy some predicate *

- * - * - * @param that - * the Observable to filter - * @param function - * a function that evaluates an item emitted by the source Observable, and - * returns {@code true} if it passes the filter - * @return an Observable that emits only those items emitted by the source Observable for which the - * predicate function evaluates to {@code true} - */ - public static Observable filter(Observable that, final Object function) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(function); - return filter(that, new Func1() { - - @Override - public Boolean call(T t1) { - return (Boolean) _f.call(t1); - - } - - }); - } - - /** - * Filters an Observable by discarding any items it emits that do not satisfy some predicate - *

+ * * * * @param that @@ -1146,39 +946,6 @@ public static Observable defer(Func0> observableFactory) { return create(OperationDefer.defer(observableFactory)); } - /** - * Returns an Observable that calls an Observable factory to create its Observable for each - * new Observer that subscribes. - *

- * - *

- * The defer operator allows you to defer or delay emitting items from an Observable - * until such time as an {@link Observer} subscribes to the Observable. This allows an Observer - * to easily obtain an updates or refreshed version of the sequence. - * - * @param observableFactory - * the Observable factory function to invoke for each {@link Observer} that - * subscribes to the resulting Observable - * @param - * the type of the items emitted by the Observable - * @return an Observable whose {@link Observer}s trigger an invocation of the given Observable - * factory function - */ - public static Observable defer(Object observableFactory) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(observableFactory); - - return create(OperationDefer.defer(new Func0>() { - - @Override - @SuppressWarnings("unchecked") - public Observable call() { - return (Observable) _f.call(); - } - - })); - } - /** * Returns an Observable that emits a single item and then completes. *

@@ -1226,37 +993,6 @@ public static Observable map(Observable sequence, Func1 func) return create(OperationMap.map(sequence, func)); } - /** - * Returns an Observable that applies the given function to each item emitted by an - * Observable and emits the result. - *

- * - * - * @param sequence - * the source Observable - * @param func - * a function to apply to each item emitted by the source Observable - * @param - * the type of items emitted by the the source Observable - * @param - * the type of items to be emitted by the resulting Observable - * @return an Observable that emits the items from the source Observable as transformed by the - * given function - */ - public static Observable map(Observable sequence, final Object func) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(func); - return map(sequence, new Func1() { - - @SuppressWarnings("unchecked") - @Override - public R call(T t1) { - return (R) _f.call(t1); - } - - }); - } - /** * Creates a new Observable by applying a function that you supply to each item emitted by * the source Observable, where that function returns an Observable, and then merging those @@ -1285,43 +1021,6 @@ public static Observable mapMany(Observable sequence, Func1 - * - *

- * Note: {@code mapMany} and {@code flatMap} are equivalent. - * - * @param sequence - * the source Observable - * @param func - * a function that, when applied to each item emitted by the source Observable, - * generates an Observable - * @param - * the type of items emitted by the source Observable - * @param - * the type of items emitted by the Observables that are returned from - * {@code func} - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation - */ - public static Observable mapMany(Observable sequence, final Object func) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(func); - return mapMany(sequence, new Func1() { - - @SuppressWarnings("unchecked") - @Override - public R call(T t1) { - return (R) _f.call(t1); - } - - }); - } - /** * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} * emissions, and marks them with their original notification types within {@link Notification} @@ -1498,38 +1197,8 @@ public static Observable flatMap(Observable sequence, Func1 - * *

- * Note: {@code mapMany} and {@code flatMap} are equivalent. - * - * @param sequence - * the source Observable - * @param func - * a function that, when applied to each item emitted by the source Observable, - * generates an Observable - * @param - * the type of items emitted by the source Observable - * @param - * the type of items emitted by the Observables that are returned from - * {@code func} - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation - * @see #mapMany(Observable, Func1) - */ - public static Observable flatMap(Observable sequence, final Object func) { - return mapMany(sequence, func); - } - - /** - * Groups the items emitted by an Observable according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. - *

- * + * * * @param source * an Observable whose items you want to group @@ -1552,51 +1221,6 @@ public static Observable> groupBy(Observable - * - * - * @param source - * an Observable whose items you want to group - * @param keySelector - * a function that extracts the key for each item omitted by the source Observable - * @param elementSelector - * a function to map each item emitted by the source Observable to an item emitted - * by a {@link GroupedObservable} - * @param - * the key type - * @param - * the type of items emitted by the source Observable - * @param - * the type of items to be emitted by the resulting {@link GroupedObservable}s - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - @SuppressWarnings("rawtypes") - public static Observable> groupBy(Observable source, final Object keySelector, final Object elementSelector) { - final FuncN _k = Functions.from(keySelector); - final FuncN _e = Functions.from(elementSelector); - - return groupBy(source, new Func1() { - - @SuppressWarnings("unchecked") - @Override - public K call(T t1) { - return (K) _k.call(t1); - } - }, new Func1() { - - @SuppressWarnings("unchecked") - @Override - public R call(T t1) { - return (R) _e.call(t1); - } - }); - } - /** * Groups the items emitted by an Observable according to a specified criterion, and emits these * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. @@ -1619,38 +1243,6 @@ public static Observable> groupBy(Observable s return create(OperationGroupBy.groupBy(source, keySelector)); } - /** - * Groups the items emitted by an Observable according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. - *

- * - * - * @param source - * an Observable whose items you want to group - * @param keySelector - * a function that extracts the key for each item emitted by the source Observable - * @param - * the key type - * @param - * the type of items to be emitted by the resulting {@link GroupedObservable}s - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - @SuppressWarnings("rawtypes") - public static Observable> groupBy(Observable source, final Object keySelector) { - final FuncN _k = Functions.from(keySelector); - - return groupBy(source, new Func1() { - - @SuppressWarnings("unchecked") - @Override - public K call(T t1) { - return (K) _k.call(t1); - } - }); - } - /** * This behaves like {@link #merge(java.util.List)} except that if any of the merged Observables * notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will @@ -1772,45 +1364,6 @@ public static Observable onErrorResumeNext(final Observable that, fina return create(OperationOnErrorResumeNextViaFunction.onErrorResumeNextViaFunction(that, resumeFunction)); } - /** - * Instruct an Observable to pass control to another Observable (the return value of a function) - * rather than invoking {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its Observer, the Observable invokes its {@link Observer}'s - * methods. The {@code onErrorResumeNext} method changes this behavior. If you pass a - * function that returns an Observable ({@code resumeFunction}) to - * {@code onErrorResumeNext}, if the source Observable encounters an error, instead of - * invoking its Observer's {@code onError} function, it will instead relinquish control to - * this new Observable, which will invoke the Observer's {@link Observer#onNext onNext} method - * if it is able to do so. In such a case, because no Observable necessarily invokes - * {@code onError}, the Observer may never know that an error happened. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param that - * the source Observable - * @param resumeFunction - * a function that returns an Observable that will take over if the source Observable - * encounters an error - * @return an Observable, identical to the source Observable with its behavior modified as described - */ - public static Observable onErrorResumeNext(final Observable that, final Object resumeFunction) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(resumeFunction); - return onErrorResumeNext(that, new Func1>() { - - @SuppressWarnings("unchecked") - @Override - public Observable call(Throwable e) { - return (Observable) _f.call(e); - } - }); - } - /** * Instruct an Observable to pass control to another Observable rather than invoking * {@link Observer#onError onError} if it encounters an error. @@ -1982,28 +1535,6 @@ public static Observable reduce(Observable sequence, Func2 ac } /** - * A version of {@code reduce()} for use by dynamic languages. - *

- * - * - * @see #reduce(Observable, Func2) - */ - public static Observable reduce(final Observable sequence, final Object accumulator) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(accumulator); - return reduce(sequence, new Func2() { - - @SuppressWarnings("unchecked") - @Override - public T call(T t1, T t2) { - return (T) _f.call(t1, t2); - } - - }); - } - - /** - * Synonymous with {@code reduce()} *

* * @@ -2013,17 +1544,6 @@ public static Observable aggregate(Observable sequence, Func2 return reduce(sequence, accumulator); } - /** - * A version of {@code aggregate()} for use by dynamic languages. - *

- * - * - * @see #reduce(Observable, Func2) - */ - public static Observable aggregate(Observable sequence, Object accumulator) { - return reduce(sequence, accumulator); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -2058,26 +1578,6 @@ public static Observable reduce(Observable sequence, R initialValue } /** - * A version of {@code reduce()} for use by dynamic languages. - *

- * - * - * @see #reduce(Observable, Object, Func2) - */ - public static Observable reduce(final Observable sequence, final R initialValue, final Object accumulator) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(accumulator); - return reduce(sequence, initialValue, new Func2() { - @SuppressWarnings("unchecked") - @Override - public R call(R r, T t) { - return (R) _f.call(r, t); - } - }); - } - - /** - * Synonymous with {@code reduce()}. *

* * @@ -2087,17 +1587,6 @@ public static Observable aggregate(Observable sequence, R initialVa return reduce(sequence, initialValue, accumulator); } - /** - * A version of {@code aggregate()} for use by dynamic languages. - *

- * - * - * @see #reduce(Observable, Object, Func2) - */ - public static Observable aggregate(Observable sequence, R initialValue, Object accumulator) { - return reduce(sequence, initialValue, accumulator); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -2122,27 +1611,6 @@ public static Observable scan(Observable sequence, Func2 accu return create(OperationScan.scan(sequence, accumulator)); } - /** - * A version of {@code scan()} for use by dynamic languages. - *

- * - * - * @see #scan(Observable, Func2) - */ - public static Observable scan(final Observable sequence, final Object accumulator) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(accumulator); - return scan(sequence, new Func2() { - - @SuppressWarnings("unchecked") - @Override - public T call(T t1, T t2) { - return (T) _f.call(t1, t2); - } - - }); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -2175,27 +1643,6 @@ public static Observable scan(Observable sequence, R initialValue, } /** - * A version of {@code scan()} for use by dynamic languages. - *

- * - * - * @see #scan(Observable, Object, Func2) - */ - public static Observable scan(final Observable sequence, final R initialValue, final Object accumulator) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(accumulator); - return scan(sequence, initialValue, new Func2() { - - @SuppressWarnings("unchecked") - @Override - public R call(R r, T t) { - return (R) _f.call(r, t); - } - }); - } - - /** - * Returns an Observable that emits a single Boolean value that indicates whether all items emitted by a * source Observable satisfy a condition. *

* @@ -2214,34 +1661,6 @@ public static Observable all(final Observable sequence, final Fu } /** - * Returns an Observable that emits a single Boolean value that indicates whether all items emitted by a - * source Observable satisfy a condition. - *

- * - * - * @param sequence - * an Observable whose emitted items you are evaluating - * @param predicate - * a function that evaluates each emitted item and returns a Boolean - * @param - * the type of items emitted by the source Observable - * @return an Observable that emits {@code true} if all items emitted by the source - * Observable satisfy the predicate; otherwise, {@code false} - */ - public static Observable all(final Observable sequence, Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return all(sequence, new Func1() { - @Override - public Boolean call(T t) { - return (Boolean) _f.call(t); - } - }); - } - - /** - * Returns an Observable that skips the first {@code num} items emitted by the source * Observable and emits the remaining items. *

* @@ -2358,31 +1777,6 @@ public static Observable takeWhile(final Observable items, Func1 - * - * - * @param items - * the source Observable - * @param predicate - * a function to test each item emitted by the source Observable for a condition - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return {@code true} for each item, then completes - */ - public static Observable takeWhile(final Observable items, Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return takeWhile(items, new Func1() { - @Override - public Boolean call(T t) { - return (Boolean) _f.call(t); - } - }); - } - /** * Returns an Observable that emits the items emitted by a source Observable so long as a given * predicate remains true, where the predicate can operate on both the item and its index @@ -2402,35 +1796,6 @@ public static Observable takeWhileWithIndex(final Observable items, Fu return create(OperationTakeWhile.takeWhileWithIndex(items, predicate)); } - /** - * Returns an Observable that emits the items emitted by a source Observable so long as a given - * predicate remains true, where the predicate can operate on both the item and its index - * relative to the complete sequence. - *

- * - * - * @param items - * the source Observable - * @param predicate - * a function to test each item emitted by the source Observable for a condition; - * the second parameter of the function represents the index of the source item - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return {@code true} for each item, then completes - */ - public static Observable takeWhileWithIndex(final Observable items, Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return create(OperationTakeWhile.takeWhileWithIndex(items, new Func2() - { - @Override - public Boolean call(T t, Integer integer) - { - return (Boolean) _f.call(t, integer); - } - })); - } - /** * Wraps each item emitted by a source Observable in a {@link Timestamped} object. *

@@ -2646,46 +2011,18 @@ public static Observable> toSortedList(Observable sequence, Func2 } /** - * Return an Observable that emits a single list of the items emitted by the source Observable, sorted - * by the given comparison function. *

- * - * - * @param sequence - * the source Observable - * @param sortFunction - * a function that compares two items emitted by the source Observable and returns - * an Integer that indicates their sort order - * @return an Observable that emits a single, sorted list of the items from the source Observable - */ - public static Observable> toSortedList(Observable sequence, final Object sortFunction) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(sortFunction); - return create(OperationToObservableSortedList.toSortedList(sequence, new Func2() { - - @Override - public Integer call(T t1, T t2) { - return (Integer) _f.call(t1, t2); - } - - })); - } - - /** - * Returns an Observable that emits the results of a function of your choosing applied to pairs - * of items emitted, in sequence, by two other Observables. - *

- * - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * {@code w0} and the first item emitted by {@code w1}; the second item emitted by - * the new Observable will be the result of the function applied to the second item emitted by - * {@code w0} and the second item emitted by {@code w1}; and so forth. - *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations - * of the source Observable that emits the fewest items. + * + *

+ * {@code zip} applies this function in strict sequence, so the first item emitted by the + * new Observable will be the result of the function applied to the first item emitted by + * {@code w0} and the first item emitted by {@code w1}; the second item emitted by + * the new Observable will be the result of the function applied to the second item emitted by + * {@code w0} and the second item emitted by {@code w1}; and so forth. + *

+ * The resulting {@code Observable} returned from {@code zip} will invoke + * {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations + * of the source Observable that emits the fewest items. * * @param w0 * one source Observable @@ -2747,68 +2084,6 @@ public static Observable sequenceEqual(Observable first, Observa return zip(first, second, equality); } - /** - * Returns an Observable that emits Boolean values that indicate whether the pairs of items - * emitted by two source Observables are equal based on the results of a specified equality - * function. - *

- * - * - * @param first - * one Observable to compare - * @param second - * the second Observable to compare - * @param equality - * a function used to compare items emitted by both Observables - * @param - * the type of items emitted by each Observable - * @return an Observable that emits Booleans that indicate whether the corresponding items - * emitted by the source Observables are equal - */ - public static Observable sequenceEqual(Observable first, Observable second, Object equality) { - return zip(first, second, equality); - } - - /** - * Returns an Observable that emits the results of a function of your choosing applied to pairs - * of items emitted, in sequence, by two other Observables. - *

- * - *

- * zip applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * w0 and the first item emitted by w1; the second item emitted by - * the new Observable will be the result of the function applied to the second item emitted by - * w0 and the second item emitted by w1; and so forth. - *

- * The resulting Observable<R> returned from zip will invoke - * {@link Observer#onNext onNext} as many times as the number of onNext invocations - * of the source Observable that emits the fewest items. - * - * @param w0 - * one source Observable - * @param w1 - * another source Observable - * @param function - * a function that, when applied to a pair of items, each emitted by one of the two - * source Observables, results in an item that will be emitted by the resulting - * Observable - * @return an Observable that emits the zipped results - */ - public static Observable zip(Observable w0, Observable w1, final Object function) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(function); - return zip(w0, w1, new Func2() { - - @SuppressWarnings("unchecked") - @Override - public R call(T0 t0, T1 t1) { - return (R) _f.call(t0, t1); - } - - }); - } - /** * Returns an Observable that emits the results of a function of your choosing applied to * combinations of three items emitted, in sequence, by three other Observables. @@ -2841,48 +2116,6 @@ public static Observable zip(Observable w0, Observable - * - *

- * zip applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * w0, the first item emitted by w1, and the first item emitted by - * w2; the second item emitted by the new Observable will be the result of the - * function applied to the second item emitted by w0, the second item emitted by - * w1, and the second item emitted by w2; and so forth. - *

- * The resulting Observable<R> returned from zip will invoke - * {@link Observer#onNext onNext} as many times as the number of onNext invocations - * of the source Observable that emits the fewest items. - * - * @param w0 - * one source Observable - * @param w1 - * another source Observable - * @param w2 - * a third source Observable - * @param function - * a function that, when applied to an item emitted by each of the source - * Observables, results in an item that will be emitted by the resulting Observable - * @return an Observable that emits the zipped results - */ - public static Observable zip(Observable w0, Observable w1, Observable w2, final Object function) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(function); - return zip(w0, w1, w2, new Func3() { - - @SuppressWarnings("unchecked") - @Override - public R call(T0 t0, T1 t1, T2 t2) { - return (R) _f.call(t0, t1, t2); - } - - }); - } - /** * Returns an Observable that emits the results of a function of your choosing applied to * combinations of four items emitted, in sequence, by four other Observables. @@ -2917,50 +2150,6 @@ public static Observable zip(Observable w0, Observabl return create(OperationZip.zip(w0, w1, w2, w3, reduceFunction)); } - /** - * Returns an Observable that emits the results of a function of your choosing applied to - * combinations of four items emitted, in sequence, by four other Observables. - *

- * - *

- * zip applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * w0, the first item emitted by w1, the first item emitted by - * w2, and the first item emitted by w3; the second item emitted by - * the new Observable will be the result of the function applied to the second item emitted by - * each of those Observables; and so forth. - *

- * The resulting Observable<R> returned from zip will invoke - * {@link Observer#onNext onNext} as many times as the number of onNext invocations - * of the source Observable that emits the fewest items. - * - * @param w0 - * one source Observable - * @param w1 - * another source Observable - * @param w2 - * a third source Observable - * @param w3 - * a fourth source Observable - * @param function - * a function that, when applied to an item emitted by each of the source - * Observables, results in an item that will be emitted by the resulting Observable - * @return an Observable that emits the zipped results - */ - public static Observable zip(Observable w0, Observable w1, Observable w2, Observable w3, final Object function) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(function); - return zip(w0, w1, w2, w3, new Func4() { - - @SuppressWarnings("unchecked") - @Override - public R call(T0 t0, T1 t1, T2 t2, T3 t3) { - return (R) _f.call(t0, t1, t2, t3); - } - - }); - } - /** * Creates an Observable which produces buffers of collected values. * @@ -3199,34 +2388,6 @@ public Observable call(List> wsList) { }); } - /** - * Returns an Observable that emits the results of a function of your choosing applied to - * combinations of four items emitted, in sequence, by four other Observables. - *

- * zip applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * all of the Observalbes; the second item emitted by the new Observable will be the result of - * the function applied to the second item emitted by each of those Observables; and so forth. - *

- * The resulting Observable returned from zip will invoke - * onNext as many times as the number of onNext invocations of the - * source Observable that emits the fewest items. - *

- * - * - * @param ws - * An Observable of source Observables - * @param function - * a function that, when applied to an item emitted by each of the source - * Observables, results in an item that will be emitted by the resulting Observable - * @return an Observable that emits the zipped results - */ - public static Observable zip(Observable> ws, final Object function) { - @SuppressWarnings({ "unchecked" }) - final FuncN _f = Functions.from(function); - return zip(ws, _f); - } - /** * Returns an Observable that emits the results of a function of your choosing applied to * combinations of four items emitted, in sequence, by four other Observables. @@ -3253,68 +2414,7 @@ public static Observable zip(Collection> ws, FuncN reduc return create(OperationZip.zip(ws, reduceFunction)); } - /** - * Returns an Observable that emits the results of a function of your choosing applied to - * combinations of four items emitted, in sequence, by four other Observables. - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * all of the Observalbes; the second item emitted by the new Observable will be the result of - * the function applied to the second item emitted by each of those Observables; and so forth. - *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@code onNext} as many times as the number of {@code onNext} invocations of the - * source Observable that emits the fewest items. - *

- * - * - * @param ws - * A collection of source Observables - * @param function - * a function that, when applied to an item emitted by each of the source - * Observables, results in an item that will be emitted by the resulting Observable - * @return an Observable that emits the zipped results - */ - public static Observable zip(Collection> ws, final Object function) { - @SuppressWarnings({ "unchecked" }) - final FuncN _f = Functions.from(function); - return zip(ws, _f); - } - - /** - * Combines the given observables, emitting an event containing an aggregation of the latest values of each of the source observables - * each time an event is received from one of the source observables, where the aggregation is defined by the given function. - *

- * - * - * @param w0 - * The first source observable. - * @param w1 - * The second source observable. - * @param combineFunction - * The aggregation function used to combine the source observable values. - * @return An Observable that combines the source Observables with the given combine function - */ - public static Observable combineLatest(Observable w0, Observable w1, Func2 combineFunction) { - return create(OperationCombineLatest.combineLatest(w0, w1, combineFunction)); - } - - /** - * @see #combineLatest(Observable, Observable, Func2) - */ - public static Observable combineLatest(Observable w0, Observable w1, Observable w2, Func3 combineFunction) { - return create(OperationCombineLatest.combineLatest(w0, w1, w2, combineFunction)); - } - - /** - * @see #combineLatest(Observable, Observable, Func2) - */ - public static Observable combineLatest(Observable w0, Observable w1, Observable w2, Observable w3, Func4 combineFunction) { - return create(OperationCombineLatest.combineLatest(w0, w1, w2, w3, combineFunction)); - } - - /** - * Filters an Observable by discarding any of its items that do not satisfy the given predicate. + /** *

* * @@ -3344,29 +2444,6 @@ public Observable finallyDo(Action0 action) { return create(OperationFinally.finallyDo(this, action)); } - /** - * Filters an Observable by discarding any of its items that do not satisfy the given predicate. - *

- * - * - * @param callback - * a function that evaluates an item emitted by the source Observable, returning - * {@code true} if it passes the filter - * @return an Observable that emits only those items in the original Observable that the filter - * evaluates as {@code true} - */ - public Observable filter(final Object callback) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(callback); - return filter(this, new Func1() { - - @Override - public Boolean call(T t1) { - return (Boolean) _f.call(t1); - } - }); - } - /** * Creates a new Observable by applying a function that you supply to each item emitted by * the source Observable, where that function returns an Observable, and then merging those @@ -3389,28 +2466,6 @@ public Observable flatMap(Func1> func) { } /** - * Creates a new Observable by applying a function that you supply to each item emitted by - * the source Observable, where that function returns an Observable, and then merging those - * resulting Observables and emitting the results of this merger. - *

- * - *

- * Note: mapMany and flatMap are equivalent. - * - * @param callback - * a function that, when applied to an item emitted by the source Observable, returns - * an Observable - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation. - * @see #mapMany(Object) - */ - public Observable flatMap(final Object callback) { - return mapMany(callback); - } - - /** - * Filters an Observable by discarding any items it emits that do not satisfy the given predicate *

* * @@ -3440,30 +2495,6 @@ public Observable map(Func1 func) { return map(this, func); } - /** - * Returns an Observable that applies the given function to each item emitted by an - * Observable and emits the result. - *

- * - * - * @param callback - * a function to apply to each item emitted by the Observable - * @return an Observable that emits the items from the source Observable, transformed by the - * given function - */ - public Observable map(final Object callback) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(callback); - return map(this, new Func1() { - - @Override - @SuppressWarnings("unchecked") - public R call(T t1) { - return (R) _f.call(t1); - } - }); - } - /** * Creates a new Observable by applying a function that you supply to each item emitted by * the source Observable, where that function returns an Observable, and then merging those @@ -3485,36 +2516,6 @@ public Observable mapMany(Func1> func) { return mapMany(this, func); } - /** - * Creates a new Observable by applying a function that you supply to each item emitted by - * the source Observable, where that function returns an Observable, and then merging those - * resulting Observables and emitting the results of this merger. - *

- * - *

- * Note: mapMany and flatMap are equivalent. - * - * @param callback - * a function that, when applied to an item emitted by the source Observable, returns - * an Observable - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation. - * @see #flatMap(Object) - */ - public Observable mapMany(final Object callback) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(callback); - return mapMany(this, new Func1>() { - - @Override - @SuppressWarnings("unchecked") - public Observable call(T t1) { - return (Observable) _f.call(t1); - } - }); - } - /** * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} * emissions, and marks them with their original notification types within {@link Notification} @@ -3606,42 +2607,6 @@ public Observable onErrorResumeNext(final Func1> res return onErrorResumeNext(this, resumeFunction); } - /** - * Instruct an Observable to emit an item (returned by a specified function) rather than - * invoking {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorReturn method changes this behavior. If you pass a function - * (resumeFunction) to an Observable's onErrorReturn method, if the - * original Observable encounters an error, instead of invoking its Observer's - * onError function, it will instead pass the return value of - * resumeFunction to the Observer's {@link Observer#onNext onNext} method. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param resumeFunction - * a function that returns an item that the Observable will emit if the source - * Observable encounters an error - * @return the original Observable with appropriately modified behavior - */ - public Observable onErrorResumeNext(final Object resumeFunction) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(resumeFunction); - return onErrorResumeNext(this, new Func1>() { - - @Override - @SuppressWarnings("unchecked") - public Observable call(Throwable e) { - return (Observable) _f.call(e); - } - }); - } - /** * Instruct an Observable to pass control to another Observable rather than invoking * {@link Observer#onError onError} if it encounters an error. @@ -3731,42 +2696,6 @@ public Observable onErrorReturn(Func1 resumeFunction) { return onErrorReturn(this, resumeFunction); } - /** - * Instruct an Observable to emit a particular item rather than invoking - * {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * onError method, and then quits without invoking any more of its Observer's - * methods. The onErrorReturn method changes this behavior. If you pass a function - * (resumeFunction) to an Observable's onErrorReturn method, if the - * original Observable encounters an error, instead of invoking its Observer's - * onError function, it will instead pass the return value of - * resumeFunction to the Observer's {@link Observer#onNext onNext} method. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param resumeFunction - * a function that returns an item that the new Observable will emit if the source - * Observable encounters an error - * @return the original Observable with appropriately modified behavior - */ - public Observable onErrorReturn(final Object resumeFunction) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(resumeFunction); - return onErrorReturn(this, new Func1() { - - @Override - @SuppressWarnings("unchecked") - public T call(Throwable e) { - return (T) _f.call(e); - } - }); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -3840,17 +2769,6 @@ public ConnectableObservable publish() { return publish(this); } - /** - * A version of reduce() for use by dynamic languages. - *

- * - * - * @see #reduce(Func2) - */ - public Observable reduce(Object accumulator) { - return reduce(this, accumulator); - } - /** * Synonymous with reduce(). *

@@ -3862,17 +2780,6 @@ public Observable aggregate(Func2 accumulator) { return aggregate(this, accumulator); } - /** - * A version of aggregate() for use by dynamic languages. - *

- * - * - * @see #reduce(Func2) - */ - public Observable aggregate(Object accumulator) { - return aggregate(this, accumulator); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -3900,17 +2807,6 @@ public Observable reduce(R initialValue, Func2 accumulator) { return reduce(this, initialValue, accumulator); } - /** - * A version of reduce() for use by dynamic languages. - *

- * - * - * @see #reduce(Object, Func2) - */ - public Observable reduce(R initialValue, Object accumulator) { - return reduce(this, initialValue, accumulator); - } - /** * Synonymous with reduce(). *

@@ -3922,17 +2818,6 @@ public Observable aggregate(R initialValue, Func2 accumulator) { return aggregate(this, initialValue, accumulator); } - /** - * A version of aggregate() for use by dynamic languages. - *

- * - * - * @see #reduce(Object, Func2) - */ - public Observable aggregate(R initialValue, Object accumulator) { - return aggregate(this, initialValue, accumulator); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -3993,17 +2878,6 @@ public Observable sample(long period, TimeUnit unit, Scheduler scheduler) { return create(OperationSample.sample(this, period, unit, scheduler)); } - /** - * A version of scan() for use by dynamic languages. - *

- * - * - * @see #scan(Func2) - */ - public Observable scan(final Object accumulator) { - return scan(this, accumulator); - } - /** * Returns an Observable that applies a function of your choosing to the first item emitted by a * source Observable, then feeds the result of that function along with the second item emitted @@ -4031,17 +2905,6 @@ public Observable scan(R initialValue, Func2 accumulator) { return scan(this, initialValue, accumulator); } - /** - * A version of scan() for use by dynamic languages. - *

- * - * - * @see #scan(Object, Func2) - */ - public Observable scan(final R initialValue, final Object accumulator) { - return scan(this, initialValue, accumulator); - } - /** * Returns an Observable that emits a Boolean that indicates whether all of the items emitted by * the source Observable satisfy a condition. @@ -4057,21 +2920,6 @@ public Observable all(Func1 predicate) { return all(this, predicate); } - /** - * Returns an Observable that emits a Boolean that indicates whether all of the items emitted by - * the source Observable satisfy a condition. - *

- * - * - * @param predicate - * a function that evaluates an item and returns a Boolean - * @return an Observable that emits true if all items emitted by the source - * Observable satisfy the predicate; otherwise, false - */ - public Observable all(Object predicate) { - return all(this, predicate); - } - /** * Returns an Observable that skips the first num items emitted by the source * Observable and emits the remainder. @@ -4126,22 +2974,6 @@ public Observable takeWhile(final Func1 predicate) { return takeWhile(this, predicate); } - /** - * Returns an Observable that emits items emitted by the source Observable so long as a - * specified condition is true. - *

- * - * - * @param predicate - * a function that evaluates an item emitted by the source Observable and returns a - * Boolean - * @return an Observable that emits the items from the source Observable so long as each item - * satisfies the condition defined by predicate - */ - public Observable takeWhile(final Object predicate) { - return takeWhile(this, predicate); - } - /** * Returns an Observable that emits the items emitted by a source Observable so long as a given * predicate remains true, where the predicate can operate on both the item and its index @@ -4159,24 +2991,6 @@ public Observable takeWhileWithIndex(final Func2 predica return takeWhileWithIndex(this, predicate); } - /** - * Returns an Observable that emits the items emitted by a source Observable so long as a given - * predicate remains true, where the predicate can operate on both the item and its index - * relative to the complete sequence. - *

- * - * - * @param predicate - * a function that evaluates an item emitted by the source Observable and returns a - * Boolean; the second parameter of the function represents the index of the source - * item - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return true for each item, then completes - */ - public Observable takeWhileWithIndex(final Object predicate) { - return takeWhileWithIndex(this, predicate); - } - /** * Returns an Observable that emits only the last count items emitted by the source * Observable. @@ -4265,21 +3079,6 @@ public Observable> toSortedList(Func2 sortFunction) { return toSortedList(this, sortFunction); } - /** - * Return an Observable that emits the items emitted by the source Observable, in a sorted - * order based on a specified comparison function - *

- * - * - * @param sortFunction - * a function that compares two items emitted by the source Observable and returns - * an Integer that indicates their sort order - * @return an Observable that emits the items from the source Observable in sorted order - */ - public Observable> toSortedList(final Object sortFunction) { - return toSortedList(this, sortFunction); - } - /** * Emit a specified set of items before beginning to emit items from the source Observable. *

@@ -4316,28 +3115,6 @@ public Observable> groupBy(final Func1 keyS return groupBy(this, keySelector, elementSelector); } - /** - * Groups the items emitted by an Observable according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. - *

- * - * - * @param keySelector - * a function that extracts the key from an item - * @param elementSelector - * a function to map a source item to an item in a {@link GroupedObservable} - * @param - * the key type - * @param - * the type of items emitted by the resulting {@link GroupedObservable}s - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - public Observable> groupBy(final Object keySelector, final Object elementSelector) { - return groupBy(this, keySelector, elementSelector); - } - /** * Groups the items emitted by an Observable according to a specified criterion, and emits these * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. @@ -4356,24 +3133,6 @@ public Observable> groupBy(final Func1 keySele return groupBy(this, keySelector); } - /** - * Groups the items emitted by an Observable according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. - *

- * - * - * @param keySelector - * a function that extracts the key for each item - * @param - * the key type - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - public Observable> groupBy(final Object keySelector) { - return groupBy(this, keySelector); - } - /** * Converts an Observable into a {@link BlockingObservable} (an Observable with blocking * operators). @@ -4905,10 +3664,10 @@ public void run() { }).start(); return Subscriptions.empty(); } - }).subscribe(new Action1() { + }).subscribe(new Action1() { @Override - public void call(Object t1) { + public void call(String t1) { } diff --git a/rxjava-core/src/main/java/rx/observables/BlockingObservable.java b/rxjava-core/src/main/java/rx/observables/BlockingObservable.java index 2d826a8fea..eb16260d2b 100644 --- a/rxjava-core/src/main/java/rx/observables/BlockingObservable.java +++ b/rxjava-core/src/main/java/rx/observables/BlockingObservable.java @@ -117,22 +117,6 @@ public static T last(final Observable source, final Func1 pre return last(source.filter(predicate)); } - /** - * Returns the last item emitted by an {@link Observable} that matches a given predicate. - *

- * - * - * @param source - * the source {@link Observable} - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the last item emitted by the {@link Observable} for which the predicate function - * returns true - */ - public static T last(final Observable source, final Object predicate) { - return last(source.filter(predicate)); - } - /** * Returns the last item emitted by an {@link Observable}, or a default value if no item is * emitted. @@ -173,35 +157,6 @@ public static T lastOrDefault(Observable source, T defaultValue, Func1 - * - * - * @param source - * the source {@link Observable} - * @param defaultValue - * a default value to return if the {@link Observable} emits no matching items - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @param - * the type of items emitted by the {@link Observable} - * @return the last item emitted by an {@link Observable} that matches the predicate, or the - * default value if no matching item is emitted - */ - public static T lastOrDefault(Observable source, T defaultValue, Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return lastOrDefault(source, defaultValue, new Func1() { - @Override - public Boolean call(T args) { - return (Boolean) _f.call(args); - } - }); - } - /** * Returns an {@link Iterable} that always returns the item most recently emitted by an * {@link Observable}. @@ -293,24 +248,6 @@ public static T single(Observable source, Func1 predicate) { return from(source).single(predicate); } - /** - * If the {@link Observable} completes after emitting a single item that matches a given - * predicate, return that item, otherwise throw an exception. - * - * - * @param source - * the source {@link Observable} - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the single item emitted by the source {@link Observable} that matches the predicate - * @throws IllegalStateException - * if the {@link Observable} does not emit exactly one item that matches the - * predicate - */ - public static T single(Observable source, Object predicate) { - return from(source).single(predicate); - } - /** * If the {@link Observable} completes after emitting a single item, return that item, otherwise * return a default value. @@ -347,25 +284,6 @@ public static T singleOrDefault(Observable source, T defaultValue, Func1< return from(source).singleOrDefault(defaultValue, predicate); } - /** - * If the {@link Observable} completes after emitting a single item that matches a given - * predicate, return that item, otherwise return a default value. - *

- * - * - * @param source - * the source {@link Observable} - * @param defaultValue - * a default value to return if the {@link Observable} emits no matching items - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the single item emitted by the source {@link Observable} that matches the predicate, - * or a default value if no such value is emitted - */ - public static T singleOrDefault(Observable source, T defaultValue, Object predicate) { - return from(source).singleOrDefault(defaultValue, predicate); - } - /** * Returns a {@link Future} representing the single value emitted by an {@link Observable}. *

@@ -476,45 +394,6 @@ public void onNext(T args) { } } - /** - * Invoke a method on each item emitted by the {@link Observable}; block until the Observable - * completes. - *

- * NOTE: This will block even if the Observable is asynchronous. - *

- * This is similar to {@link #subscribe(Observer)}, but it blocks. Because it blocks it does - * not need the {@link Observer#onCompleted()} or {@link Observer#onError(Throwable)} methods. - *

- * - * - * @param o - * the {@link Action1} to invoke for every item emitted by the {@link Observable} - * @throws RuntimeException - * if an error occurs - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void forEach(final Object o) { - if (o instanceof Action1) { - // in case a dynamic language is not correctly handling the overloaded methods and we receive an Action1 just forward to the correct method. - forEach((Action1) o); - } - - // lookup and memoize onNext - if (o == null) { - throw new RuntimeException("onNext must be implemented"); - } - final FuncN onNext = Functions.from(o); - - forEach(new Action1() { - - @Override - public void call(Object args) { - onNext.call(args); - } - - }); - } - /** * Returns an {@link Iterator} that iterates over all items emitted by a specified * {@link Observable}. @@ -555,27 +434,6 @@ public T last(final Func1 predicate) { return last(this, predicate); } - /** - * Returns the last item emitted by a specified {@link Observable} that matches a predicate. - *

- * - * - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the last item emitted by the {@link Observable} that matches the predicate - */ - public T last(final Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return last(this, new Func1() { - @Override - public Boolean call(T args) { - return (Boolean) _f.call(args); - } - }); - } - /** * Returns the last item emitted by a specified {@link Observable}, or a default value if no * items are emitted. @@ -620,23 +478,6 @@ public T lastOrDefault(T defaultValue, Func1 predicate) { return lastOrDefault(this, defaultValue, predicate); } - /** - * Returns the last item emitted by a specified {@link Observable} that matches a predicate, or - * a default value if no such items are emitted. - *

- * - * - * @param defaultValue - * a default value to return if the {@link Observable} emits no matching items - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the last item emitted by the {@link Observable} that matches the predicate, or the - * default value if no matching items are emitted - */ - public T lastOrDefault(T defaultValue, Object predicate) { - return lastOrDefault(this, defaultValue, predicate); - } - /** * Returns an {@link Iterable} that always returns the item most recently emitted by an * {@link Observable}. @@ -692,28 +533,6 @@ public T single(Func1 predicate) { return _singleOrDefault(from(this.filter(predicate)), false, null); } - /** - * If the {@link Observable} completes after emitting a single item that matches a given - * predicate, return that item, otherwise throw an exception. - *

- * - * - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the single item emitted by the source {@link Observable} that matches the predicate - */ - public T single(Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return single(new Func1() { - @Override - public Boolean call(T t) { - return (Boolean) _f.call(t); - } - }); - } - /** * If the {@link Observable} completes after emitting a single item, return that item; if it * emits more than one item, throw an exception; if it emits no items, return a default value. @@ -747,32 +566,6 @@ public T singleOrDefault(T defaultValue, Func1 predicate) { return _singleOrDefault(from(this.filter(predicate)), true, defaultValue); } - /** - * If the {@link Observable} completes after emitting a single item that matches a predicate, - * return that item; if it emits more than one such item, throw an exception; if it emits no - * items, return a default value. - *

- * - * - * @param defaultValue - * a default value to return if the {@link Observable} emits no matching items - * @param predicate - * a predicate function to evaluate items emitted by the {@link Observable} - * @return the single item emitted by the {@link Observable} that matches the predicate, or the - * default value if no such items are emitted - */ - public T singleOrDefault(T defaultValue, final Object predicate) { - @SuppressWarnings("rawtypes") - final FuncN _f = Functions.from(predicate); - - return singleOrDefault(defaultValue, new Func1() { - @Override - public Boolean call(T t) { - return (Boolean) _f.call(t); - } - }); - } - /** * Returns a {@link Future} representing the single value emitted by an {@link Observable}. *

diff --git a/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java b/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java index 089a850e99..f11af77898 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java +++ b/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java @@ -62,7 +62,7 @@ public class OperationCombineLatest { * The aggregation function used to combine the source observable values. * @return A function from an observer to a subscription. This can be used to create an observable from. */ - public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction) { + public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction) { Aggregator a = new Aggregator(Functions.fromFunc(combineLatestFunction)); a.addObserver(new CombineObserver(a, w0)); a.addObserver(new CombineObserver(a, w1)); @@ -72,7 +72,7 @@ public static Func1, Subscription> combineLatest /** * @see #combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction) */ - public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Observable w2, Func3 combineLatestFunction) { + public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Observable w2, Func3 combineLatestFunction) { Aggregator a = new Aggregator(Functions.fromFunc(combineLatestFunction)); a.addObserver(new CombineObserver(a, w0)); a.addObserver(new CombineObserver(a, w1)); @@ -83,7 +83,7 @@ public static Func1, Subscription> combineLa /** * @see #combineLatest(Observable w0, Observable w1, Func2 combineLatestFunction) */ - public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Observable w2, Observable w3, Func4 combineLatestFunction) { + public static Func1, Subscription> combineLatest(Observable w0, Observable w1, Observable w2, Observable w3, Func4 combineLatestFunction) { Aggregator a = new Aggregator(Functions.fromFunc(combineLatestFunction)); a.addObserver(new CombineObserver(a, w0)); a.addObserver(new CombineObserver(a, w1)); @@ -93,11 +93,11 @@ public static Func1, Subscription> combi } private static class CombineObserver implements Observer { - final Observable w; - final Aggregator a; + final Observable w; + final Aggregator a; private Subscription subscription; - public CombineObserver(Aggregator a, Observable w) { + public CombineObserver(Aggregator a, Observable w) { this.a = a; this.w = w; } @@ -130,9 +130,9 @@ public void onNext(T args) { * whenever we have received an event from one of the observables, as soon as each Observable has received * at least one event. */ - private static class Aggregator implements Func1, Subscription> { + private static class Aggregator implements Func1, Subscription> { - private volatile Observer observer; + private volatile Observer observer; private final FuncN combineLatestFunction; private final AtomicBoolean running = new AtomicBoolean(true); @@ -169,7 +169,7 @@ void addObserver(CombineObserver w) { * * @param w The observer that has completed. */ - void complete(CombineObserver w) { + void complete(CombineObserver w) { int completed = numCompleted.incrementAndGet(); // if all CombineObservers are completed, we mark the whole thing as completed if (completed == observers.size()) { @@ -199,7 +199,7 @@ void error(Throwable e) { * @param w * @param arg */ - void next(CombineObserver w, T arg) { + void next(CombineObserver w, T arg) { if (observer == null) { throw new RuntimeException("This shouldn't be running if an Observer isn't registered"); } @@ -232,7 +232,7 @@ void next(CombineObserver w, T arg) { } @Override - public Subscription call(Observer observer) { + public Subscription call(Observer observer) { if (this.observer != null) { throw new IllegalStateException("Only one Observer can subscribe to this Observable."); } diff --git a/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java index b154702ff8..c25ea56dee 100644 --- a/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java @@ -130,9 +130,8 @@ public static class UnitTest { @Test public void testNeverCompleted() { - AsyncSubject subject = AsyncSubject.create(); + AsyncSubject subject = AsyncSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -152,9 +151,8 @@ private void assertNeverCompletedObserver(Observer aObserver) @Test public void testCompleted() { - AsyncSubject subject = AsyncSubject.create(); + AsyncSubject subject = AsyncSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -175,9 +173,8 @@ private void assertCompletedObserver(Observer aObserver) @Test public void testError() { - AsyncSubject subject = AsyncSubject.create(); + AsyncSubject subject = AsyncSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -201,7 +198,7 @@ private void assertErrorObserver(Observer aObserver) @Test public void testUnsubscribeBeforeCompleted() { - AsyncSubject subject = AsyncSubject.create(); + AsyncSubject subject = AsyncSubject.create(); @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); diff --git a/rxjava-core/src/main/java/rx/subjects/PublishSubject.java b/rxjava-core/src/main/java/rx/subjects/PublishSubject.java index 5fccdb86d2..467771758d 100644 --- a/rxjava-core/src/main/java/rx/subjects/PublishSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/PublishSubject.java @@ -195,12 +195,12 @@ public static class UnitTest { @Test public void test() { PublishSubject subject = PublishSubject.create(); - final AtomicReference>> actualRef = new AtomicReference>>(); + final AtomicReference>> actualRef = new AtomicReference>>(); Observable>> wNotificationsList = subject.materialize().toList(); - wNotificationsList.subscribe(new Action1>>() { + wNotificationsList.subscribe(new Action1>>() { @Override - public void call(List> actual) { + public void call(List> actual) { actualRef.set(actual); } }); @@ -245,9 +245,8 @@ public void unsubscribe() { @Test public void testCompleted() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -256,7 +255,6 @@ public void testCompleted() { subject.onNext("three"); subject.onCompleted(); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -286,9 +284,8 @@ private void assertNeverObserver(Observer aObserver) @Test public void testError() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -297,7 +294,6 @@ public void testError() { subject.onNext("three"); subject.onError(testException); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -320,9 +316,8 @@ private void assertErrorObserver(Observer aObserver) @Test public void testSubscribeMidSequence() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -331,7 +326,6 @@ public void testSubscribeMidSequence() { assertObservedUntilTwo(aObserver); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -353,9 +347,8 @@ private void assertCompletedStartingWithThreeObserver(Observer aObserver @Test public void testUnsubscribeFirstObserver() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); - @SuppressWarnings("unchecked") Observer aObserver = mock(Observer.class); Subscription subscription = subject.subscribe(aObserver); @@ -365,7 +358,6 @@ public void testUnsubscribeFirstObserver() { subscription.unsubscribe(); assertObservedUntilTwo(aObserver); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -397,9 +389,8 @@ private void assertObservedUntilTwo(Observer aObserver) */ @Test public void testUnsubscribeAfterOnCompleted() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); - @SuppressWarnings("unchecked") Observer anObserver = mock(Observer.class); subject.subscribe(anObserver); @@ -426,7 +417,7 @@ public void testUnsubscribeAfterOnCompleted() { @Test public void testUnsubscribeAfterOnError() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); RuntimeException exception = new RuntimeException("failure"); @SuppressWarnings("unchecked") diff --git a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java index b6711c15c4..2d852f5bb0 100644 --- a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java +++ b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java @@ -186,7 +186,7 @@ public static class UnitTest { @SuppressWarnings("unchecked") @Test public void testCompleted() { - ReplaySubject subject = ReplaySubject.create(); + ReplaySubject subject = ReplaySubject.create(); Observer o1 = mock(Observer.class); subject.subscribe(o1); @@ -223,7 +223,7 @@ private void assertCompletedObserver(Observer aObserver) @SuppressWarnings("unchecked") @Test public void testError() { - ReplaySubject subject = ReplaySubject.create(); + ReplaySubject subject = ReplaySubject.create(); Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -256,7 +256,7 @@ private void assertErrorObserver(Observer aObserver) @SuppressWarnings("unchecked") @Test public void testSubscribeMidSequence() { - ReplaySubject subject = ReplaySubject.create(); + ReplaySubject subject = ReplaySubject.create(); Observer aObserver = mock(Observer.class); subject.subscribe(aObserver); @@ -280,7 +280,7 @@ public void testSubscribeMidSequence() { @SuppressWarnings("unchecked") @Test public void testUnsubscribeFirstObserver() { - ReplaySubject subject = ReplaySubject.create(); + ReplaySubject subject = ReplaySubject.create(); Observer aObserver = mock(Observer.class); Subscription subscription = subject.subscribe(aObserver); From ba768a9328d19f0e66625191cfa4489014a8422b Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 17:20:44 -0700 Subject: [PATCH 02/22] Reworked Scala adaptor to use implicits in RxImplicits, rather than code generation --- build.gradle | 47 +- gradle/wrapper/gradle-wrapper.properties | 2 +- language-adaptors/rxjava-scala/build.gradle | 43 +- .../scala/rx/lang/scala/RxImplicits.scala | 592 ++++++++++++++++++ .../scala/rx/lang/scala/ScalaAdaptor.scala | 204 ------ rxjava-core/build.gradle | 23 +- 6 files changed, 653 insertions(+), 258 deletions(-) create mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/RxImplicits.scala delete mode 100644 language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ScalaAdaptor.scala diff --git a/build.gradle b/build.gradle index 9073b716ee..c7378d469a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,9 @@ +apply from: file('gradle/convention.gradle') +apply from: file('gradle/maven.gradle') +//apply from: file('gradle/check.gradle') +apply from: file('gradle/license.gradle') +apply from: file('gradle/release.gradle') + ext.githubProjectName = rootProject.name buildscript { @@ -9,20 +15,51 @@ allprojects { repositories { mavenCentral() } } -apply from: file('gradle/convention.gradle') -apply from: file('gradle/maven.gradle') -//apply from: file('gradle/check.gradle') -apply from: file('gradle/license.gradle') -apply from: file('gradle/release.gradle') subprojects { + apply plugin: 'java' + apply plugin: 'eclipse' + apply plugin: 'idea' group = "com.netflix.${githubProjectName}" + // make 'examples' use the same classpath + configurations { + examplesCompile.extendsFrom compile + examplesRuntime.extendsFrom runtime + } + sourceSets.test.java.srcDir 'src/main/java' tasks.withType(Javadoc).each { it.classpath = sourceSets.main.compileClasspath } + + //include /src/examples folder + sourceSets { + examples + } + + //include 'examples' in build task + tasks.build { + dependsOn(examplesClasses) + } + + eclipse { + classpath { + // include 'provided' dependencies on the classpath + plusConfigurations += configurations.provided + + downloadSources = true + downloadJavadoc = true + } + } + + idea { + module { + // include 'provided' dependencies on the classpath + scopes.PROVIDED.plus += configurations.provided + } + } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e230e2b1c4..2abe81ceda 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip +distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip diff --git a/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 43704248d6..576158a64c 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -1,11 +1,10 @@ apply plugin: 'scala' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'osgi' tasks.withType(ScalaCompile) { scalaCompileOptions.fork = true scalaCompileOptions.unchecked = true + scalaCompileOptions.setAdditionalParameters(['-feature']) configure(scalaCompileOptions.forkOptions) { memoryMaximumSize = '1g' @@ -13,46 +12,38 @@ tasks.withType(ScalaCompile) { } } +sourceSets { + test { + scala { + srcDir 'src/main/scala' + } + } +} + dependencies { - // Scala compiler and related tools - scalaTools 'org.scala-lang:scala-compiler:2.10+' - scalaTools 'org.scala-lang:scala-library:2.10+' - provided 'org.scalatest:scalatest_2.10:1.9.1' + compile 'org.scala-lang:scala-library:2.10+' compile project(':rxjava-core') + provided 'junit:junit-dep:4.10' provided 'org.mockito:mockito-core:1.8.5' + provided 'org.scalatest:scalatest_2.10:1.9.1' +} - testCompile 'org.scalatest:scalatest_2.10:1.9.1' +tasks.compileScala { + classpath = classpath + (configurations.compile + configurations.provided) } task test(overwrite: true, dependsOn: testClasses) << { ant.taskdef(name: 'scalatest', classname: 'org.scalatest.tools.ScalaTestAntTask', - classpath: sourceSets.test.runtimeClasspath.asPath + classpath: configurations.provided.asPath + ':' + configurations.testRuntime.asPath + ":" + compileScala.destinationDir ) - ant.scalatest(runpath: sourceSets.test.classesDir, + ant.scalatest(runpath: sourceSets.test.output.classesDir, haltonfailure: 'true', fork: 'false') {reporter(type: 'stdout')} } -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - jar { manifest { name = 'rxjava-scala' diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/RxImplicits.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/RxImplicits.scala new file mode 100644 index 0000000000..67fd4ec0f1 --- /dev/null +++ b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/RxImplicits.scala @@ -0,0 +1,592 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.lang.scala + +object RxImplicits { + import java.{ lang => jlang } + import language.implicitConversions + + import rx.Observable + import rx.observables.BlockingObservable + import rx.util.functions._ + + /** + * Converts 0-arg function to Rx Action0 + */ + implicit def scalaFunction0ProducingUnitToAction0(f: (() => Unit)): Action0 = + new Action0 { + def call(): Unit = f() + } + + /** + * Converts 1-arg function to Rx Action1 + */ + implicit def scalaFunction1ProducingUnitToAction1[A](f: (A => Unit)): Action1[A] = + new Action1[A] { + def call(a: A): Unit = f(a) + } + + /** + * Converts 1-arg predicate to Rx Func1[A, java.lang.Boolean] + */ + implicit def scalaBooleanFunction1ToRxBooleanFunc1[A](f: (A => Boolean)): Func1[A, jlang.Boolean] = + new Func1[A, jlang.Boolean] { + def call(a: A): jlang.Boolean = f(a).booleanValue + } + + /** + * Converts a specific function shape (used in takeWhile) to the equivalent Java types with an Rx Func2 + */ + implicit def convertTakeWhileFuncToRxFunc2[A](f: (A, Int) => Boolean): Func2[A, jlang.Integer, jlang.Boolean] = + new Func2[A, jlang.Integer, jlang.Boolean] { + def call(a: A, b: jlang.Integer): jlang.Boolean = f(a, b).booleanValue + } + + /** + * Converts a function shaped ilke compareTo into the equivalent Rx Func2 + */ + implicit def convertComparisonFuncToRxFunc2[A](f: (A, A) => Int): Func2[A, A, jlang.Integer] = + new Func2[A, A, jlang.Integer] { + def call(a1: A, a2: A): jlang.Integer = f(a1, a2).intValue + } + + /* + * This implicit allows Scala code to use any exception type and still work + * with invariant Func1 interface + */ + implicit def exceptionFunction1ToRxExceptionFunc1[A <: Exception, B](f: (A => B)): Func1[Exception, B] = + new Func1[Exception, B] { + def call(ex: Exception): B = f(ex.asInstanceOf[A]) + } + + /** + * The following implicits convert functions of different arities into the Rx equivalents + */ + implicit def scalaFunction0ToRxFunc0[A](f: () => A): Func0[A] = + new Func0[A] { + def call(): A = f() + } + + implicit def scalaFunction1ToRxFunc1[A, B](f: (A => B)): Func1[A, B] = + new Func1[A, B] { + def call(a: A): B = f(a) + } + + implicit def scalaFunction2ToRxFunc2[A, B, C](f: (A, B) => C): Func2[A, B, C] = + new Func2[A, B, C] { + def call(a: A, b: B) = f(a, b) + } + + implicit def scalaFunction3ToRxFunc3[A, B, C, D](f: (A, B, C) => D): Func3[A, B, C, D] = + new Func3[A, B, C, D] { + def call(a: A, b: B, c: C) = f(a, b, c) + } + + implicit def scalaFunction4ToRxFunc4[A, B, C, D, E](f: (A, B, C, D) => E): Func4[A, B, C, D, E] = + new Func4[A, B, C, D, E] { + def call(a: A, b: B, c: C, d: D) = f(a, b, c, d) + } + + /** + * This implicit class implements all of the methods necessary for including Observables in a + * for-comprehension. Note that return type is always Observable, so that the ScalaObservable + * type never escapes the for-comprehension + */ + implicit class ScalaObservable[A](wrapped: Observable[A]) { + def map[B](f: A => B): Observable[B] = wrapped.map(f) + def flatMap[B](f: A => Observable[B]): Observable[B] = wrapped.mapMany(f) + def foreach(f: A => Unit): Unit = wrapped.toBlockingObservable.forEach(f) + def withFilter(p: A => Boolean): WithFilter = new WithFilter(p) + + class WithFilter(p: A => Boolean) { + def map[B](f: A => B): Observable[B] = wrapped.filter(p).map(f) + def flatMap[B](f: A => Observable[B]): Observable[B] = wrapped.filter(p).flatMap(f) + def foreach(f: A => Unit): Unit = wrapped.filter(p).toBlockingObservable.forEach(f) + def withFilter(p: A => Boolean): Observable[A] = wrapped.filter(p) + } + } +} + +import org.scalatest.junit.JUnitSuite + +class UnitTestSuite extends JUnitSuite { + import rx.lang.scala.RxImplicits._ + + import org.junit.{ Before, Test } + import org.junit.Assert._ + import org.mockito.Matchers.any + import org.mockito.Mockito._ + import org.mockito.{ MockitoAnnotations, Mock } + import rx.{ Notification, Observer, Observable, Subscription } + import rx.observables.GroupedObservable + import collection.mutable.ArrayBuffer + import collection.JavaConverters._ + + @Mock private[this] + val observer: Observer[Any] = null + + @Mock private[this] + val subscription: Subscription = null + + val isOdd = (i: Int) => i % 2 == 1 + val isEven = (i: Int) => i % 2 == 0 + + class ObservableWithException(s: Subscription, values: String*) extends Observable[String] { + var t: Thread = null + + override def subscribe(observer: Observer[String]): Subscription = { + println("ObservableWithException subscribed to ...") + t = new Thread(new Runnable() { + override def run() { + try { + println("running ObservableWithException thread") + values.toList.foreach(v => { + println("ObservableWithException onNext: " + v) + observer.onNext(v) + }) + throw new RuntimeException("Forced Failure") + } catch { + case ex: Exception => observer.onError(ex) + } + } + }) + println("starting ObservableWithException thread") + t.start() + println("done starting ObservableWithException thread") + s + } + } + + @Before def before { + MockitoAnnotations.initMocks(this) + } + + // tests of static methods + + @Test def testSingle { + assertEquals(1, Observable.from(1).toBlockingObservable.single) + } + + @Test def testSinglePredicate { + val found = Observable.from(1, 2, 3).toBlockingObservable.single(isEven) + assertEquals(2, found) + } + + @Test def testSingleOrDefault { + assertEquals(0, Observable.from[Int]().toBlockingObservable.singleOrDefault(0)) + assertEquals(1, Observable.from(1).toBlockingObservable.singleOrDefault(0)) + try { + Observable.from(1, 2, 3).toBlockingObservable.singleOrDefault(0) + fail("Did not catch any exception, expected IllegalStateException") + } catch { + case ex: IllegalStateException => println("Caught expected IllegalStateException") + case ex: Throwable => fail("Caught unexpected exception " + ex.getCause + ", expected IllegalStateException") + } + } + + @Test def testSingleOrDefaultPredicate { + assertEquals(2, Observable.from(1, 2, 3).toBlockingObservable.singleOrDefault(0, isEven)) + assertEquals(0, Observable.from(1, 3).toBlockingObservable.singleOrDefault(0, isEven)) + try { + Observable.from(1, 2, 3).toBlockingObservable.singleOrDefault(0, isOdd) + fail("Did not catch any exception, expected IllegalStateException") + } catch { + case ex: IllegalStateException => println("Caught expected IllegalStateException") + case ex: Throwable => fail("Caught unexpected exception " + ex.getCause + ", expected IllegalStateException") + } + } + + @Test def testFromJavaInterop { + val observable = Observable.from(List(1, 2, 3).asJava) + assertSubscribeReceives(observable)(1, 2, 3) + } + + @Test def testSubscribe { + val observable = Observable.from("1", "2", "3") + assertSubscribeReceives(observable)("1", "2", "3") + } + + //should not compile - adapted from https://gist.github.com/jmhofer/5195589 + /*@Test def testSubscribeOnInt() { + val observable = Observable.from("1", "2", "3") + observable.subscribe((arg: Int) => { + println("testSubscribe: arg = " + arg) + }) + }*/ + + @Test def testDefer { + val lazyObservableFactory = () => Observable.from(1, 2) + val observable = Observable.defer(lazyObservableFactory) + assertSubscribeReceives(observable)(1, 2) + } + + @Test def testJust { + val observable = Observable.just("foo") + assertSubscribeReceives(observable)("foo") + } + + @Test def testMerge { + val observable1 = Observable.from(1, 2, 3) + val observable2 = Observable.from(4, 5, 6) + val observableList = List(observable1, observable2).asJava + val merged = Observable.merge(observableList) + assertSubscribeReceives(merged)(1, 2, 3, 4, 5, 6) + } + + @Test def testFlattenMerge { + val observable = Observable.from(Observable.from(1, 2, 3)) + val merged = Observable.merge(observable) + assertSubscribeReceives(merged)(1, 2, 3) + } + + @Test def testSequenceMerge { + val observable1 = Observable.from(1, 2, 3) + val observable2 = Observable.from(4, 5, 6) + val merged = Observable.merge(observable1, observable2) + assertSubscribeReceives(merged)(1, 2, 3, 4, 5, 6) + } + + @Test def testConcat { + val observable1 = Observable.from(1, 2, 3) + val observable2 = Observable.from(4, 5, 6) + val concatenated = Observable.concat(observable1, observable2) + assertSubscribeReceives(concatenated)(1, 2, 3, 4, 5, 6) + } + + @Test def testSynchronize { + val observable = Observable.from(1, 2, 3) + val synchronized = Observable.synchronize(observable) + assertSubscribeReceives(synchronized)(1, 2, 3) + } + + @Test def testZip3() { + val numbers = Observable.from(1, 2, 3) + val colors = Observable.from("red", "green", "blue") + val names = Observable.from("lion-o", "cheetara", "panthro") + + case class Character(id: Int, color: String, name: String) + + val liono = Character(1, "red", "lion-o") + val cheetara = Character(2, "green", "cheetara") + val panthro = Character(3, "blue", "panthro") + + val characters = Observable.zip(numbers, colors, names, Character.apply _) + assertSubscribeReceives(characters)(liono, cheetara, panthro) + } + + @Test def testZip4() { + val numbers = Observable.from(1, 2, 3) + val colors = Observable.from("red", "green", "blue") + val names = Observable.from("lion-o", "cheetara", "panthro") + val isLeader = Observable.from(true, false, false) + + case class Character(id: Int, color: String, name: String, isLeader: Boolean) + + val liono = Character(1, "red", "lion-o", true) + val cheetara = Character(2, "green", "cheetara", false) + val panthro = Character(3, "blue", "panthro", false) + + val characters = Observable.zip(numbers, colors, names, isLeader, Character.apply _) + assertSubscribeReceives(characters)(liono, cheetara, panthro) + } + + //tests of instance methods + + // missing tests for : takeUntil, groupBy, next, mostRecent + + @Test def testFilter { + val numbers = Observable.from(1, 2, 3, 4, 5, 6, 7, 8, 9) + val observable = numbers.filter(isEven) + assertSubscribeReceives(observable)(2, 4, 6, 8) + } + + @Test def testLast { + val observable = Observable.from(1, 2, 3, 4).toBlockingObservable + assertEquals(4, observable.toBlockingObservable.last) + } + + @Test def testLastPredicate { + val observable = Observable.from(1, 2, 3, 4) + assertEquals(3, observable.toBlockingObservable.last(isOdd)) + } + + @Test def testLastOrDefault { + val observable = Observable.from(1, 2, 3, 4) + assertEquals(4, observable.toBlockingObservable.lastOrDefault(5)) + assertEquals(5, Observable.from[Int]().toBlockingObservable.lastOrDefault(5)) + } + + @Test def testLastOrDefaultPredicate { + val observable = Observable.from(1, 2, 3, 4) + assertEquals(3, observable.toBlockingObservable.lastOrDefault(5, isOdd)) + assertEquals(5, Observable.from[Int]().toBlockingObservable.lastOrDefault(5, isOdd)) + } + + @Test def testMap { + val numbers = Observable.from(1, 2, 3, 4, 5, 6, 7, 8, 9) + val mappedNumbers = ArrayBuffer.empty[Int] + numbers.map((x: Int) => x * x).subscribe((squareVal: Int) => { + mappedNumbers.append(squareVal) + }) + assertEquals(List(1, 4, 9, 16, 25, 36, 49, 64, 81), mappedNumbers.toList) + } + + @Test def testMapMany { + val numbers = Observable.from(1, 2, 3, 4) + val f = (i: Int) => Observable.from(List(i, -i).asJava) + val mappedNumbers = ArrayBuffer.empty[Int] + numbers.mapMany(f).subscribe((i: Int) => { + mappedNumbers.append(i) + }) + assertEquals(List(1, -1, 2, -2, 3, -3, 4, -4), mappedNumbers.toList) + } + + @Test def testMaterialize { + val observable = Observable.from(1, 2, 3, 4) + val expectedNotifications: List[Notification[Int]] = + ((1.to(4).map(i => new Notification(i))) :+ new Notification()).toList + val actualNotifications: ArrayBuffer[Notification[Int]] = ArrayBuffer.empty + observable.materialize.subscribe((n: Notification[Int]) => { + actualNotifications.append(n) + }) + assertEquals(expectedNotifications, actualNotifications.toList) + } + + @Test def testDematerialize { + val notifications: List[Notification[Int]] = + ((1.to(4).map(i => new Notification(i))) :+ new Notification()).toList + val observableNotifications: Observable[Notification[Int]] = + Observable.from(notifications.asJava) + val observable: Observable[Int] = + observableNotifications.dematerialize() + assertSubscribeReceives(observable)(1, 2, 3, 4) + } + + @Test def testOnErrorResumeNextObservableNoError { + val observable = Observable.from(1, 2, 3, 4) + val resumeObservable = Observable.from(5, 6, 7, 8) + val observableWithErrorHandler = observable.onErrorResumeNext(resumeObservable) + assertSubscribeReceives(observableWithErrorHandler)(1, 2, 3, 4) + } + + @Test def testOnErrorResumeNextObservableErrorOccurs { + val observable = new ObservableWithException(subscription, "foo", "bar") + val resumeObservable = Observable.from("a", "b", "c", "d") + val observableWithErrorHandler = observable.onErrorResumeNext(resumeObservable) + observableWithErrorHandler.subscribe(observer.asInstanceOf[Observer[String]]) + + try { + observable.t.join() + } catch { + case ex: InterruptedException => fail(ex.getMessage) + } + + List("foo", "bar", "a", "b", "c", "d").foreach(t => verify(observer, times(1)).onNext(t)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + } + + @Test def testOnErrorResumeNextFuncNoError { + val observable = Observable.from(1, 2, 3, 4) + val resumeFunc = (ex: Throwable) => Observable.from(5, 6, 7, 8) + val observableWithErrorHandler = observable.onErrorResumeNext(resumeFunc) + assertSubscribeReceives(observableWithErrorHandler)(1, 2, 3, 4) + } + + @Test def testOnErrorResumeNextFuncErrorOccurs { + val observable = new ObservableWithException(subscription, "foo", "bar") + val resumeFunc = (ex: Throwable) => Observable.from("a", "b", "c", "d") + val observableWithErrorHandler = observable.onErrorResumeNext(resumeFunc) + observableWithErrorHandler.subscribe(observer.asInstanceOf[Observer[String]]) + + try { + observable.t.join() + } catch { + case ex: InterruptedException => fail(ex.getMessage) + } + + List("foo", "bar", "a", "b", "c", "d").foreach(t => verify(observer, times(1)).onNext(t)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + } + + @Test def testOnErrorReturnFuncNoError { + val observable = Observable.from(1, 2, 3, 4) + val returnFunc = (ex: Throwable) => 87 + val observableWithErrorHandler = observable.onErrorReturn(returnFunc) + assertSubscribeReceives(observableWithErrorHandler)(1, 2, 3, 4) + } + + @Test def testOnErrorReturnFuncErrorOccurs { + val observable = new ObservableWithException(subscription, "foo", "bar") + val returnFunc = (ex: Throwable) => "baz" + val observableWithErrorHandler = observable.onErrorReturn(returnFunc) + observableWithErrorHandler.subscribe(observer.asInstanceOf[Observer[String]]) + + try { + observable.t.join() + } catch { + case ex: InterruptedException => fail(ex.getMessage) + } + + List("foo", "bar", "baz").foreach(t => verify(observer, times(1)).onNext(t)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + } + + @Test def testReduce { + val observable = Observable.from(1, 2, 3, 4) + assertEquals(10, observable.reduce((a: Int, b: Int) => a + b).toBlockingObservable.single) + } + + @Test def testSkip { + val observable = Observable.from(1, 2, 3, 4) + val skipped = observable.skip(2) + assertSubscribeReceives(skipped)(3, 4) + } + + /** + * Both testTake and testTakeWhileWithIndex exposed a bug with unsubscribes not properly propagating. + * observable.take(2) produces onNext(first), onNext(second), and 4 onCompleteds + * it should produce onNext(first), onNext(second), and 1 onCompleted + * + * Switching to Observable.create(OperationTake.take(observable, 2)) works as expected + */ + @Test def testTake { + import rx.operators._ + + val observable = Observable.from(1, 2, 3, 4, 5) + val took = Observable.create(OperationTake.take(observable, 2)) + assertSubscribeReceives(took)(1, 2) + } + + @Test def testTakeWhile { + val observable = Observable.from(1, 3, 5, 6, 7, 9, 11) + val took = observable.takeWhile(isOdd) + assertSubscribeReceives(took)(1, 3, 5) + } + + /*@Test def testTakeWhileWithIndex { + val observable = Observable.from(1, 3, 5, 6, 7, 9, 11, 12, 13, 15, 17) + val took = observable.takeWhileWithIndex((i: Int, idx: Int) => isOdd(i) && idx > 4) + assertSubscribeReceives(took)(9, 11) + }*/ + + @Test def testTakeLast { + val observable = Observable.from(1, 2, 3, 4, 5, 6, 7, 8, 9) + val tookLast = observable.takeLast(3) + assertSubscribeReceives(tookLast)(7, 8, 9) + } + + @Test def testToList { + val observable = Observable.from(1, 2, 3, 4) + val toList = observable.toList + assertSubscribeReceives(toList)(List(1, 2, 3, 4).asJava) + } + + @Test def testToSortedList { + val observable = Observable.from(1, 3, 4, 2) + val toSortedList = observable.toSortedList + assertSubscribeReceives(toSortedList)(List(1, 2, 3, 4).asJava) + } + + @Test def testToArbitrarySortedList { + val observable = Observable.from("a", "aaa", "aaaa", "aa") + val sortByLength = (s1: String, s2: String) => s1.length.compareTo(s2.length) + val toSortedList = observable.toSortedList(sortByLength) + assertSubscribeReceives(toSortedList)(List("a", "aa", "aaa", "aaaa").asJava) + } + + @Test def testToIterable { + val observable = Observable.from(1, 2) + val it = observable.toBlockingObservable.toIterable.iterator + assertTrue(it.hasNext) + assertEquals(1, it.next) + assertTrue(it.hasNext) + assertEquals(2, it.next) + assertFalse(it.hasNext) + } + + @Test def testStartWith { + val observable = Observable.from(1, 2, 3, 4) + val newStart = observable.startWith(-1, 0) + assertSubscribeReceives(newStart)(-1, 0, 1, 2, 3, 4) + } + + @Test def testOneLineForComprehension { + val mappedObservable = for { + i: Int <- Observable.from(1, 2, 3, 4) + } yield i + 1 + assertSubscribeReceives(mappedObservable)(2, 3, 4, 5) + assertFalse(mappedObservable.isInstanceOf[ScalaObservable[_]]) + } + + @Test def testSimpleMultiLineForComprehension { + val flatMappedObservable = for { + i: Int <- Observable.from(1, 2, 3, 4) + j: Int <- Observable.from(1, 10, 100, 1000) + } yield i + j + assertSubscribeReceives(flatMappedObservable)(2, 12, 103, 1004) + assertFalse(flatMappedObservable.isInstanceOf[ScalaObservable[_]]) + } + + @Test def testMultiLineForComprehension { + val doubler = (i: Int) => Observable.from(i, i) + val flatMappedObservable = for { + i: Int <- Observable.from(1, 2, 3, 4) + j: Int <- doubler(i) + } yield j + //can't use assertSubscribeReceives since each number comes in 2x + flatMappedObservable.subscribe(observer.asInstanceOf[Observer[Int]]) + List(1, 2, 3, 4).foreach(i => verify(observer, times(2)).onNext(i)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + assertFalse(flatMappedObservable.isInstanceOf[ScalaObservable[_]]) + } + + @Test def testFilterInForComprehension { + val doubler = (i: Int) => Observable.from(i, i) + val filteredObservable = for { + i: Int <- Observable.from(1, 2, 3, 4) + j: Int <- doubler(i) if isOdd(i) + } yield j + //can't use assertSubscribeReceives since each number comes in 2x + filteredObservable.subscribe(observer.asInstanceOf[Observer[Int]]) + List(1, 3).foreach(i => verify(observer, times(2)).onNext(i)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + assertFalse(filteredObservable.isInstanceOf[ScalaObservable[_]]) + } + + @Test def testForEachForComprehension { + val doubler = (i: Int) => Observable.from(i, i) + val intBuffer = ArrayBuffer.empty[Int] + val forEachComprehension = for { + i: Int <- Observable.from(1, 2, 3, 4) + j: Int <- doubler(i) if isEven(i) + } { + intBuffer.append(j) + } + assertEquals(List(2, 2, 4, 4), intBuffer.toList) + } + + private def assertSubscribeReceives[T](o: Observable[T])(values: T*) = { + o.subscribe(observer.asInstanceOf[Observer[T]]) + values.toList.foreach(t => verify(observer, times(1)).onNext(t)) + verify(observer, never()).onError(any(classOf[Exception])) + verify(observer, times(1)).onCompleted() + } +} diff --git a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ScalaAdaptor.scala b/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ScalaAdaptor.scala deleted file mode 100644 index 12418d516d..0000000000 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ScalaAdaptor.scala +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.lang.scala - -import rx.util.functions.FunctionLanguageAdaptor -import org.junit.{Assert, Before, Test} -import rx.Observable -import org.scalatest.junit.JUnitSuite -import org.mockito.Mockito._ -import org.mockito.{MockitoAnnotations, Mock} - -import scala.collection.JavaConverters._ -import collection.mutable.ArrayBuffer - -class ScalaAdaptor extends FunctionLanguageAdaptor { - - val ON_NEXT = "onNext" - val ON_ERROR = "onError" - val ON_COMPLETED = "onCompleted" - - def getFunctionClass: Array[Class[_]] = { - return Array(classOf[Map[String, _]], classOf[(AnyRef) => Object], classOf[(AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef) => Object], classOf[(AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) =>Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object], - classOf[(AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object]) - } - - def call(function: AnyRef, args: Array[AnyRef]) : Object = { - function match { - case (func: Map[String, _]) => return matchOption(func.get(ON_NEXT), args) - case _ => return matchFunction(function, args) - } - } - - private def matchOption(funcOption: Option[_], args: Array[AnyRef]) : Object = { - funcOption match { - case Some(func: AnyRef) => return matchFunction(func, args) - case _ => return None - } - } - - private def matchFunction(function: AnyRef, args: Array[AnyRef]) : Object = function match { - case (f: ((AnyRef) => Object)) => return f(args(0)) - case (f: ((AnyRef, AnyRef) => Object)) => return f(args(0), args(1)) - case (f: ((AnyRef, AnyRef, AnyRef) => Object)) => return f(args(0), args(1), args(2)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20)) - case (f: ((AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef, AnyRef) => Object)) => - return f(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21)) - - } -} - -class UnitTestSuite extends JUnitSuite { - @Mock private[this] - val assertion: ScriptAssertion = null - - @Before def before { - MockitoAnnotations.initMocks(this) - } - - @Test def testTake() { - Observable.from("1", "2", "3").take(1).subscribe(Map( - "onNext" -> ((callback: String) => { - print("testTake: callback = " + callback) - assertion.received(callback) - }) - )) - verify(assertion, times(1)).received("1") - } - - @Test def testClosureVersusMap() { - // using closure - Observable.from("1", "2", "3") - .take(2) - .subscribe((callback: String) => { - println(callback) - }) - - // using Map of closures - Observable.from("1", "2", "3") - .take(2) - .subscribe(Map( - "onNext" -> ((callback: String) => { - println(callback) - }))) - } - - @Test def testFilterWithToList() { - val numbers = Observable.from[Int](1, 2, 3, 4, 5, 6, 7, 8, 9) - numbers.filter((x: Int) => 0 == (x % 2)).toList().subscribe( - (callback: java.util.List[Int]) => { - val lst = callback.asScala.toList - println("filter onNext -> got " + lst) - assertion.received(lst) - } - ) - verify(assertion, times(1)).received(List(2,4,6,8)) - } - - @Test def testTakeLast() { - val numbers = Observable.from[Int](1, 2, 3, 4, 5, 6, 7, 8, 9) - numbers.takeLast(1).subscribe((callback: Int) => { - println("testTakeLast: onNext -> got " + callback) - assertion.received(callback) - }) - verify(assertion, times(1)).received(9) - } - - @Test def testMap() { - val numbers = Observable.from(1, 2, 3, 4, 5, 6, 7, 8, 9) - val mappedNumbers = new ArrayBuffer[Int]() - numbers.map(((x: Int)=> { x * x })).subscribe(((squareVal: Int) => { - println("square is " + squareVal ) - mappedNumbers += squareVal - })) - Assert.assertEquals(List(1,4,9,16,25,36,49,64,81), mappedNumbers.toList) - - } - - @Test def testZip() { - val numbers = Observable.from(1, 2, 3) - val colors = Observable.from("red", "green", "blue") - val characters = Observable.from("lion-o", "cheetara", "panthro") - - Observable.zip(numbers.toList, colors.toList, characters.toList, ((n: java.util.List[Int], c: java.util.List[String], t: java.util.List[String]) => { Map( - "numbers" -> n, - "colors" -> c, - "thundercats" -> t - )})).subscribe((m: Map[String, _]) => { - println("zipped map is " + m.toString()) - }) - - - } - - trait ScriptAssertion { - def error(ex: Exception) - - def received(obj: Any) - } -} diff --git a/rxjava-core/build.gradle b/rxjava-core/build.gradle index 72a984c88d..1732de3017 100644 --- a/rxjava-core/build.gradle +++ b/rxjava-core/build.gradle @@ -1,6 +1,4 @@ -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' +apply plugin: 'maven' apply plugin: 'osgi' sourceCompatibility = JavaVersion.VERSION_1_6 @@ -11,23 +9,6 @@ dependencies { provided 'org.mockito:mockito-core:1.8.5' } -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - javadoc { // we do not want the org.rx.operations package include exclude '**/operations/**' @@ -48,7 +29,5 @@ jar { instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava' instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' } - // commenting out for now as it's breaking the rxjava-scala build and I can't figure out why - // exclude('**/*$UnitTest*') } From 0188a7cdf7e8c456d4096dce391e15960943cf81 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 11:49:09 -0700 Subject: [PATCH 03/22] Removing JRuby adaptor (temporarily) --- language-adaptors/rxjava-jruby/README.md | 38 --- language-adaptors/rxjava-jruby/build.gradle | 38 --- .../main/java/rx/lang/jruby/JRubyAdaptor.java | 225 ------------------ settings.gradle | 1 - 4 files changed, 302 deletions(-) delete mode 100644 language-adaptors/rxjava-jruby/README.md delete mode 100644 language-adaptors/rxjava-jruby/build.gradle delete mode 100644 language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyAdaptor.java diff --git a/language-adaptors/rxjava-jruby/README.md b/language-adaptors/rxjava-jruby/README.md deleted file mode 100644 index 9aec635da3..0000000000 --- a/language-adaptors/rxjava-jruby/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# JRuby Adaptor for RxJava - - -This adaptor allows `org.jruby.RubyProc` lambda functions to be used and RxJava will know how to invoke them. - -This enables code such as: - -```ruby - Observable.from("one", "two", "three") - .take(2) - .subscribe(lambda { |arg| puts arg }) -``` - -# Binaries - -Binaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22rxjava-jruby%22). - -Example for Maven: - -```xml - - com.netflix.rxjava - rxjava-jruby - x.y.z - -``` - -and for Ivy: - -```xml - -``` - -and for JBundler: - -```ruby -jar 'com.netflix.rxjava:rxjava-ruby', 'x.y.z' -``` diff --git a/language-adaptors/rxjava-jruby/build.gradle b/language-adaptors/rxjava-jruby/build.gradle deleted file mode 100644 index cf7d9533e2..0000000000 --- a/language-adaptors/rxjava-jruby/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'osgi' - -dependencies { - compile project(':rxjava-core') - provided 'org.jruby:jruby:1.6+' - provided 'junit:junit-dep:4.10' - provided 'org.mockito:mockito-core:1.8.5' -} - -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - -jar { - manifest { - name = 'rxjava-jruby' - instruction 'Bundle-Vendor', 'Netflix' - instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava' - instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' - instruction 'Fragment-Host', 'com.netflix.rxjava.core' - } -} \ No newline at end of file diff --git a/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyAdaptor.java b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyAdaptor.java deleted file mode 100644 index d66dc16acf..0000000000 --- a/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyAdaptor.java +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.lang.jruby; - -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; - -import org.jruby.Ruby; -import org.jruby.RubyProc; -import org.jruby.embed.ScriptingContainer; -import org.jruby.javasupport.JavaEmbedUtils; -import org.jruby.runtime.builtin.IRubyObject; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import rx.Notification; -import rx.Observable; -import rx.Observer; -import rx.Subscription; -import rx.util.functions.Func1; -import rx.util.functions.FunctionLanguageAdaptor; - -public class JRubyAdaptor implements FunctionLanguageAdaptor { - - @Override - public Object call(Object function, Object[] args) { - RubyProc rubyProc = ((RubyProc) function); - Ruby ruby = rubyProc.getRuntime(); - IRubyObject rubyArgs[] = new IRubyObject[args.length]; - for (int i = 0; i < args.length; i++) { - rubyArgs[i] = JavaEmbedUtils.javaToRuby(ruby, args[i]); - } - return rubyProc.getBlock().call(ruby.getCurrentContext(), rubyArgs); - } - - @Override - public Class[] getFunctionClass() { - return new Class[] { RubyProc.class }; - } - - public static class UnitTest { - - @Mock - ScriptAssertion assertion; - - @Mock - Observer w; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testCreateViaGroovy() { - runGroovyScript("Observable.create(lambda{|it| it.onNext('hello');it.onCompleted();}).subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(1)).received("hello"); - } - - @Test - public void testFilterViaGroovy() { - runGroovyScript("Observable.filter(Observable.from(1, 2, 3), lambda{|it| it >= 2}).subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(0)).received(1L); - verify(assertion, times(1)).received(2L); - verify(assertion, times(1)).received(3L); - } - - @Test - public void testLast() { - String script = "mockApiCall.getObservable().takeLast(1).subscribe(lambda{|result| a.received(result)})"; - runGroovyScript(script); - verify(assertion, times(1)).received("hello_1"); - } - - @Test - public void testMap() { - String script = "mockApiCall.getObservable().map(lambda{|v| 'say' + v}).subscribe(lambda{|result| a.received(result)});"; - runGroovyScript(script); - verify(assertion, times(1)).received("sayhello_1"); - } - - @Test - public void testMaterializeViaGroovy() { - runGroovyScript("Observable.materialize(Observable.from(1, 2, 3)).subscribe(lambda{|result| a.received(result)});"); - // we expect 4 onNext calls: 3 for 1, 2, 3 ObservableNotification.OnNext and 1 for ObservableNotification.OnCompleted - verify(assertion, times(4)).received(any(Notification.class)); - verify(assertion, times(0)).error(any(Exception.class)); - } - - @Test - public void testScriptWithMaterialize() { - String script = "mockApiCall.getObservable().materialize().subscribe(lambda{|result| a.received(result)});"; - runGroovyScript(script); - // 2 times: once for hello_1 and once for onCompleted - verify(assertion, times(2)).received(any(Notification.class)); - } - - @Test - public void testScriptWithMerge() { - String script = "Observable.merge(mockApiCall.getObservable(), mockApiCall.getObservable()).subscribe(lambda{|result| a.received(result)});"; - runGroovyScript(script); - verify(assertion, times(1)).received("hello_1"); - verify(assertion, times(1)).received("hello_2"); - } - - @Test - public void testScriptWithOnNext() { - String script = "mockApiCall.getObservable().subscribe(lambda{|result| a.received(result)})"; - runGroovyScript(script); - verify(assertion).received("hello_1"); - } - - @Test - public void testSkipTakeViaGroovy() { - runGroovyScript("Observable.skip(Observable.from(1, 2, 3), 1).take(1).subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(0)).received(1); - verify(assertion, times(1)).received(2L); - verify(assertion, times(0)).received(3); - } - - @Test - public void testSkipViaGroovy() { - runGroovyScript("Observable.skip(Observable.from(1, 2, 3), 2).subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(0)).received(1); - verify(assertion, times(0)).received(2); - verify(assertion, times(1)).received(3L); - } - - @Test - public void testTakeViaGroovy() { - runGroovyScript("Observable.take(Observable.from(1, 2, 3), 2).subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(1)).received(1L); - verify(assertion, times(1)).received(2L); - verify(assertion, times(0)).received(3); - } - - @Test - public void testToSortedList() { - runGroovyScript("mockApiCall.getNumbers().toSortedList().subscribe(lambda{|result| a.received(result)});"); - verify(assertion, times(1)).received(Arrays.asList(1, 2, 3, 4, 5)); - } - - private void runGroovyScript(String script) { - ScriptingContainer container = new ScriptingContainer(); - container.put("mockApiCall", new TestFactory()); - container.put("a", assertion); - - StringBuilder b = new StringBuilder(); - // force JRuby to always use subscribe(Object) - b.append("import \"rx.Observable\"").append("\n"); - b.append("class Observable").append("\n"); - b.append(" java_alias :subscribe, :subscribe, [java.lang.Object]").append("\n"); - b.append("end").append("\n"); - b.append(script); - - container.runScriptlet(b.toString()); - } - - private static interface ScriptAssertion { - public void error(Exception o); - - public void received(Object o); - } - - public static class TestFactory { - int counter = 1; - - public Observable getNumbers() { - return Observable.from(1, 3, 2, 5, 4); - } - - public TestObservable getObservable() { - return new TestObservable(counter++); - } - } - - private static class TestObservable extends Observable { - private final int count; - - public TestObservable(int count) { - super(new Func1, Subscription>() { - - @Override - public Subscription call(Observer t1) { - // do nothing, override subscribe for test - return null; - } - }); - this.count = count; - } - - public Subscription subscribe(Observer observer) { - - observer.onNext("hello_" + count); - observer.onCompleted(); - - return new Subscription() { - - public void unsubscribe() { - // unregister ... will never be called here since we are executing synchronously - } - - }; - } - } - } - -} diff --git a/settings.gradle b/settings.gradle index 5d33717f7a..5c7140dc5c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,6 @@ rootProject.name='rxjava' include 'rxjava-core', \ 'language-adaptors:rxjava-groovy', \ -'language-adaptors:rxjava-jruby', \ 'language-adaptors:rxjava-clojure', \ 'language-adaptors:rxjava-scala', \ 'rxjava-contrib:rxjava-swing', \ From 6020f105ea0fb4bc68c7622c5996702a956a9299 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 11:59:28 -0700 Subject: [PATCH 04/22] Removing Java ClojureAdaptor - will be replaced by an idiomatic Clojure version --- language-adaptors/rxjava-clojure/build.gradle | 46 +------ .../java/rx/lang/clojure/ClojureAdaptor.java | 128 ------------------ 2 files changed, 7 insertions(+), 167 deletions(-) delete mode 100644 language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureAdaptor.java diff --git a/language-adaptors/rxjava-clojure/build.gradle b/language-adaptors/rxjava-clojure/build.gradle index 0ea7feb27c..fc8af32d0b 100644 --- a/language-adaptors/rxjava-clojure/build.gradle +++ b/language-adaptors/rxjava-clojure/build.gradle @@ -1,17 +1,15 @@ -apply plugin: 'java' apply plugin: 'clojure' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'osgi' dependencies { compile project(':rxjava-core') - provided 'org.clojure:clojure:1.4.+' + provided 'junit:junit-dep:4.10' provided 'org.mockito:mockito-core:1.8.5' // clojure - testCompile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http + compile 'org.clojure:clojure:1.4.+' + compile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http } /* @@ -26,7 +24,6 @@ buildscript { } repositories { - mavenCentral() clojarsRepo() } @@ -37,45 +34,16 @@ eclipse { project { natures "ccw.nature" } - classpath { - plusConfigurations += configurations.provided - downloadSources = true - downloadJavadoc = true - } } -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } +tasks.clojureTest { + classpath = classpath + configurations.provided } - -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } +tasks.compileExamplesClojure { + classpath = classpath + configurations.provided } -// include /src/examples folder -sourceSets { - examples -} - -// make 'examples' use the same classpath -configurations { - examplesCompile.extendsFrom compile - examplesRuntime.extendsFrom runtime -} - -// include 'examples' in build task -build.dependsOn examplesClasses - jar { manifest { name = 'rxjava-clojure' diff --git a/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureAdaptor.java b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureAdaptor.java deleted file mode 100644 index 4420f7c919..0000000000 --- a/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureAdaptor.java +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.lang.clojure; - -import java.util.Arrays; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import rx.Observer; -import rx.util.functions.FunctionLanguageAdaptor; - -import clojure.lang.IFn; -import clojure.lang.RT; -import clojure.lang.Var; - -public class ClojureAdaptor implements FunctionLanguageAdaptor { - - @Override - public Object call(Object function, Object[] args) { - if (args.length == 0) { - return ((IFn) function).invoke(); - } else if (args.length == 1) { - return ((IFn) function).invoke(args[0]); - } else if (args.length == 2) { - return ((IFn) function).invoke(args[0], args[1]); - } else if (args.length == 3) { - return ((IFn) function).invoke(args[0], args[1], args[2]); - } else if (args.length == 4) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3]); - } else if (args.length == 5) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4]); - } else if (args.length == 6) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5]); - } else if (args.length == 7) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } else if (args.length == 8) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); - } else if (args.length == 9) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - } else if (args.length == 10) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); - } else if (args.length == 11) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); - } else if (args.length == 12) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]); - } else if (args.length == 13) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]); - } else if (args.length == 14) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]); - } else if (args.length == 15) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]); - } else if (args.length == 16) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]); - } else if (args.length == 17) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16]); - } else if (args.length == 18) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17]); - } else if (args.length == 19) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18]); - } else if (args.length == 20) { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19]); - } else { - return ((IFn) function).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], Arrays.copyOfRange(args, 20, args.length)); - } - } - - @Override - public Class[] getFunctionClass() { - return new Class[] { IFn.class }; - } - - public static class UnitTest { - - @Mock - ScriptAssertion assertion; - - @Mock - Observer w; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testTake() { - runClojureScript("(-> (rx.Observable/toObservable [\"one\" \"two\" \"three\"]) (.take 2) (.subscribe (fn [arg] (println arg))))"); - } - - // commented out for now as I can't figure out how to set the var 'a' with the 'assertion' instance when running the code from java - // @Test - // public void testFilter() { - // runClojureScript("(-> (org.rx.reactive.Observable/toObservable [1 2 3]) (.filter (fn [v] (>= v 2))) (.subscribe (fn [result] (a.received(result)))))"); - // verify(assertion, times(0)).received(1); - // verify(assertion, times(1)).received(2); - // verify(assertion, times(1)).received(3); - // } - - private static interface ScriptAssertion { - public void error(Exception o); - - public void received(Object o); - } - - private void runClojureScript(String script) { - Object code = RT.var("clojure.core", "read-string").invoke(script); - Var eval = RT.var("clojure.core", "eval"); - Object result = eval.invoke(code); - System.out.println("Result: " + result); - } - } -} From d2631ec621aee0878d3b5950c81546a7d43417d9 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 12:14:31 -0700 Subject: [PATCH 05/22] Removing Java GroovyAdaptor - will be replaced by Groovy idiomatic version --- language-adaptors/rxjava-groovy/build.gradle | 36 +------------------ .../java/rx/lang/groovy/GroovyAdaptor.java | 31 ---------------- 2 files changed, 1 insertion(+), 66 deletions(-) delete mode 100644 language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyAdaptor.java diff --git a/language-adaptors/rxjava-groovy/build.gradle b/language-adaptors/rxjava-groovy/build.gradle index 91c060193d..c26a383a34 100644 --- a/language-adaptors/rxjava-groovy/build.gradle +++ b/language-adaptors/rxjava-groovy/build.gradle @@ -1,47 +1,13 @@ -apply plugin: 'java' apply plugin: 'groovy' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'osgi' dependencies { compile project(':rxjava-core') - groovy 'org.codehaus.groovy:groovy-all:2.+' + compile 'org.codehaus.groovy:groovy-all:2.+' provided 'junit:junit-dep:4.10' provided 'org.mockito:mockito-core:1.8.5' } -// include /src/examples folder -sourceSets { - examples -} - -// make 'examples' use the same classpath -configurations { - examplesCompile.extendsFrom compile - examplesRuntime.extendsFrom runtime -} - -// include 'examples' in build task -build.dependsOn examplesClasses - -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - jar { manifest { name = 'rxjava-groovy' diff --git a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyAdaptor.java b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyAdaptor.java deleted file mode 100644 index 70cef9c18e..0000000000 --- a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyAdaptor.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.lang.groovy; - -import groovy.lang.Closure; -import rx.util.functions.FunctionLanguageAdaptor; - -public class GroovyAdaptor implements FunctionLanguageAdaptor { - - @Override - public Object call(Object function, Object[] args) { - return ((Closure) function).call(args); - } - - public Class[] getFunctionClass() { - return new Class[] { Closure.class }; - } -} From e98ae37ba45075458a7c92d12364b537e96c4fa8 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 12:15:00 -0700 Subject: [PATCH 06/22] Cleaning up rxjava-swing --- rxjava-contrib/rxjava-swing/build.gradle | 20 ------------------- .../java/rx/observables/SwingObservable.java | 1 + 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/rxjava-contrib/rxjava-swing/build.gradle b/rxjava-contrib/rxjava-swing/build.gradle index 986f7ca6b9..ea863813a2 100644 --- a/rxjava-contrib/rxjava-swing/build.gradle +++ b/rxjava-contrib/rxjava-swing/build.gradle @@ -1,6 +1,3 @@ -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'osgi' sourceCompatibility = JavaVersion.VERSION_1_6 @@ -12,23 +9,6 @@ dependencies { provided 'org.mockito:mockito-core:1.8.5' } -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - javadoc { options { doclet = "org.benjchristensen.doclet.DocletExclude" diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java index a2facde800..174c529d2d 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java @@ -26,6 +26,7 @@ import javax.swing.AbstractButton; import rx.Observable; +import static rx.Observable.filter; import rx.swing.sources.AbstractButtonSource; import rx.swing.sources.ComponentEventSource; import rx.swing.sources.KeyEventSource; From 9fd3f3ed6ab9f70b0d61fc930b52c6b16d28faad Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 12:52:48 -0700 Subject: [PATCH 07/22] Remove FunctionLanguageAdaptor from rxjava-core --- rxjava-core/src/main/java/rx/Observable.java | 1 - .../functions/FunctionLanguageAdaptor.java | 39 ---- .../java/rx/util/functions/Functions.java | 177 ------------------ 3 files changed, 217 deletions(-) delete mode 100644 rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index 62f8c89ddf..ae3042ba1b 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -100,7 +100,6 @@ import rx.util.functions.Func4; import rx.util.functions.FuncN; import rx.util.functions.Function; -import rx.util.functions.FunctionLanguageAdaptor; import rx.util.functions.Functions; /** diff --git a/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java b/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java deleted file mode 100644 index 6ec87f358a..0000000000 --- a/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.util.functions; - -public interface FunctionLanguageAdaptor { - - /** - * Invoke the function and return the results. - * - * @param function - * @param args - * @return Object results from function execution - */ - Object call(Object function, Object[] args); - - /** - * The Class of the Function that this adaptor serves. - *

- * Example: groovy.lang.Closure - *

- * This should not return classes of java.* packages. - * - * @return Class[] of classes that this adaptor should be invoked for. - */ - public Class[] getFunctionClass(); -} diff --git a/rxjava-core/src/main/java/rx/util/functions/Functions.java b/rxjava-core/src/main/java/rx/util/functions/Functions.java index 4486e7bd26..bae9c466ca 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Functions.java +++ b/rxjava-core/src/main/java/rx/util/functions/Functions.java @@ -18,65 +18,8 @@ import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; -/** - * Allows execution of functions from multiple different languages. - *

- * Language support is provided via implementations of {@link FunctionLanguageAdaptor}. - *

- * This class will dynamically look for known language adaptors on the classpath at startup or new ones can be registered using {@link #registerLanguageAdaptor(Class[], FunctionLanguageAdaptor)}. - */ public class Functions { - private final static ConcurrentHashMap, FunctionLanguageAdaptor> languageAdaptors = new ConcurrentHashMap, FunctionLanguageAdaptor>(); - - static { - /* optimistically look for supported languages if they are in the classpath */ - loadLanguageAdaptor("Groovy"); - loadLanguageAdaptor("JRuby"); - loadLanguageAdaptor("Clojure"); - loadLanguageAdaptor("Scala"); - // as new languages arise we can add them here but this does not prevent someone from using 'registerLanguageAdaptor' directly - } - - private static boolean loadLanguageAdaptor(String name) { - String className = "rx.lang." + name.toLowerCase() + "." + name + "Adaptor"; - try { - Class c = Class.forName(className); - FunctionLanguageAdaptor a = (FunctionLanguageAdaptor) c.newInstance(); - registerLanguageAdaptor(a.getFunctionClass(), a); - /* - * Using System.err/System.out as this is the only place in the library where we do logging and it's only at startup. - * I don't want to include SL4J/Log4j just for this and no one uses Java Logging. - */ - System.out.println("RxJava => Successfully loaded function language adaptor: " + name + " with path: " + className); - } catch (ClassNotFoundException e) { - System.err.println("RxJava => Could not find function language adaptor: " + name + " with path: " + className); - return false; - } catch (Throwable e) { - System.err.println("RxJava => Failed trying to initialize function language adaptor: " + className); - e.printStackTrace(); - return false; - } - return true; - } - - public static void registerLanguageAdaptor(Class[] functionClasses, FunctionLanguageAdaptor adaptor) { - for (Class functionClass : functionClasses) { - if (functionClass.getPackage().getName().startsWith("java.")) { - throw new IllegalArgumentException("FunctionLanguageAdaptor implementations can not specify java.lang.* classes."); - } - languageAdaptors.put(functionClass, adaptor); - } - } - - public static void removeLanguageAdaptor(Class functionClass) { - languageAdaptors.remove(functionClass); - } - - public static Collection getRegisteredLanguageAdaptors() { - return languageAdaptors.values(); - } - /** * Utility method for determining the type of closure/function and executing it. * @@ -91,131 +34,11 @@ public static FuncN from(final Object function) { /* check for typed Rx Function implementation first */ if (function instanceof Function) { return fromFunction((Function) function); - } else { - /* not an Rx Function so try language adaptors */ - - // check for language adaptor - for (final Class c : languageAdaptors.keySet()) { - if (c.isInstance(function)) { - final FunctionLanguageAdaptor la = languageAdaptors.get(c); - // found the language adaptor so wrap in FuncN and return - return new FuncN() { - - @Override - public Object call(Object... args) { - return la.call(function, args); - } - - }; - } - } - // no language adaptor found } - // no support found throw new RuntimeException("Unsupported closure type: " + function.getClass().getSimpleName()); } - // - // @SuppressWarnings("unchecked") - // private static R executionRxFunction(Function function, Object... args) { - // // check Func* classes - // if (function instanceof Func0) { - // Func0 f = (Func0) function; - // if (args.length != 0) { - // throw new RuntimeException("The closure was Func0 and expected no arguments, but we received: " + args.length); - // } - // return (R) f.call(); - // } else if (function instanceof Func1) { - // Func1 f = (Func1) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func1 and expected 1 argument, but we received: " + args.length); - // } - // return f.call(args[0]); - // } else if (function instanceof Func2) { - // Func2 f = (Func2) function; - // if (args.length != 2) { - // throw new RuntimeException("The closure was Func2 and expected 2 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1]); - // } else if (function instanceof Func3) { - // Func3 f = (Func3) function; - // if (args.length != 3) { - // throw new RuntimeException("The closure was Func3 and expected 3 arguments, but we received: " + args.length); - // } - // return (R) f.call(args[0], args[1], args[2]); - // } else if (function instanceof Func4) { - // Func4 f = (Func4) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func4 and expected 4 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3]); - // } else if (function instanceof Func5) { - // Func5 f = (Func5) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func5 and expected 5 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3], args[4]); - // } else if (function instanceof Func6) { - // Func6 f = (Func6) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func6 and expected 6 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3], args[4], args[5]); - // } else if (function instanceof Func7) { - // Func7 f = (Func7) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func7 and expected 7 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - // } else if (function instanceof Func8) { - // Func8 f = (Func8) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func8 and expected 8 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); - // } else if (function instanceof Func9) { - // Func9 f = (Func9) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Func9 and expected 9 arguments, but we received: " + args.length); - // } - // return f.call(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - // } else if (function instanceof FuncN) { - // FuncN f = (FuncN) function; - // return f.call(args); - // } else if (function instanceof Action0) { - // Action0 f = (Action0) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Action0 and expected 0 arguments, but we received: " + args.length); - // } - // f.call(); - // return null; - // } else if (function instanceof Action1) { - // Action1 f = (Action1) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Action1 and expected 1 argument, but we received: " + args.length); - // } - // f.call(args[0]); - // return null; - // } else if (function instanceof Action2) { - // Action2 f = (Action2) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Action2 and expected 2 argument, but we received: " + args.length); - // } - // f.call(args[0], args[1]); - // return null; - // } else if (function instanceof Action3) { - // Action3 f = (Action3) function; - // if (args.length != 1) { - // throw new RuntimeException("The closure was Action1 and expected 1 argument, but we received: " + args.length); - // } - // f.call(args[0], args[1], args[2]); - // return null; - // } - // - // throw new RuntimeException("Unknown implementation of Function: " + function.getClass().getSimpleName()); - // } - @SuppressWarnings({ "unchecked", "rawtypes" }) private static FuncN fromFunction(Function function) { // check Func* classes From ccf0d7df41673961a8fc7c3488649b6a29ef660b Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 27 Aug 2013 12:54:41 -0700 Subject: [PATCH 08/22] Cleaning up rxjava-android build.gradle --- rxjava-contrib/rxjava-android/build.gradle | 23 ---------------------- 1 file changed, 23 deletions(-) diff --git a/rxjava-contrib/rxjava-android/build.gradle b/rxjava-contrib/rxjava-android/build.gradle index 96bbb27267..f3b7745c81 100644 --- a/rxjava-contrib/rxjava-android/build.gradle +++ b/rxjava-contrib/rxjava-android/build.gradle @@ -1,11 +1,5 @@ -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'osgi' -sourceCompatibility = JavaVersion.VERSION_1_6 -targetCompatibility = JavaVersion.VERSION_1_6 - dependencies { compile project(':rxjava-core') provided 'junit:junit-dep:4.10' @@ -14,23 +8,6 @@ dependencies { provided 'com.google.android:android:4.0.1.2' } -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - javadoc { options { doclet = "org.benjchristensen.doclet.DocletExclude" From 2721eadf651b4d31a6c80546a9bbd3312803a7fe Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 13:05:58 -0700 Subject: [PATCH 09/22] Action interfacesAction Marker Interface --- .../src/main/java/rx/util/functions/Action.java | 10 ++++++++++ .../src/main/java/rx/util/functions/Action0.java | 2 +- .../src/main/java/rx/util/functions/Action1.java | 2 +- .../src/main/java/rx/util/functions/Action2.java | 2 +- .../src/main/java/rx/util/functions/Action3.java | 2 +- .../src/main/java/rx/util/functions/Function.java | 2 +- 6 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 rxjava-core/src/main/java/rx/util/functions/Action.java diff --git a/rxjava-core/src/main/java/rx/util/functions/Action.java b/rxjava-core/src/main/java/rx/util/functions/Action.java new file mode 100644 index 0000000000..c1d43eede6 --- /dev/null +++ b/rxjava-core/src/main/java/rx/util/functions/Action.java @@ -0,0 +1,10 @@ +package rx.util.functions; + +/** + * All Action interfaces extend from this. + *

+ * Marker interface to allow instanceof checks. + */ +public interface Action { + +} diff --git a/rxjava-core/src/main/java/rx/util/functions/Action0.java b/rxjava-core/src/main/java/rx/util/functions/Action0.java index 62d57bd563..7b6e742699 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action0.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action0.java @@ -15,6 +15,6 @@ */ package rx.util.functions; -public interface Action0 extends Function { +public interface Action0 extends Function, Action { public void call(); } \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/util/functions/Action1.java b/rxjava-core/src/main/java/rx/util/functions/Action1.java index 14fa7ced8c..e21fd4e38b 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action1.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action1.java @@ -15,6 +15,6 @@ */ package rx.util.functions; -public interface Action1 extends Function { +public interface Action1 extends Function, Action { public void call(T1 t1); } \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/util/functions/Action2.java b/rxjava-core/src/main/java/rx/util/functions/Action2.java index 8a17875a9e..76c48d3eaf 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action2.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action2.java @@ -15,6 +15,6 @@ */ package rx.util.functions; -public interface Action2 extends Function { +public interface Action2 extends Function, Action { public void call(T1 t1, T2 t2); } \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/util/functions/Action3.java b/rxjava-core/src/main/java/rx/util/functions/Action3.java index 2b613b621e..0bb6932792 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action3.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action3.java @@ -15,6 +15,6 @@ */ package rx.util.functions; -public interface Action3 extends Function { +public interface Action3 extends Function, Action { public void call(T1 t1, T2 t2, T3 t3); } \ No newline at end of file diff --git a/rxjava-core/src/main/java/rx/util/functions/Function.java b/rxjava-core/src/main/java/rx/util/functions/Function.java index cfe85a221f..60ad4b5239 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Function.java +++ b/rxjava-core/src/main/java/rx/util/functions/Function.java @@ -3,7 +3,7 @@ /** * All Func and Action interfaces extend from this. *

- * Marker interface to allow isntanceof checks. + * Marker interface to allow instanceof checks. */ public interface Function { From 1531e21caae02ba295cab5875f59dc3c56910f3f Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 20:38:12 -0700 Subject: [PATCH 10/22] Remove repetitive Scheduler overloads. --- rxjava-core/src/main/java/rx/Scheduler.java | 114 ------------------ .../rx/operators/OperationSubscribeOn.java | 9 +- .../java/rx/operators/OperatorTester.java | 44 ------- 3 files changed, 6 insertions(+), 161 deletions(-) diff --git a/rxjava-core/src/main/java/rx/Scheduler.java b/rxjava-core/src/main/java/rx/Scheduler.java index 22735209cd..bcfd48bf68 100644 --- a/rxjava-core/src/main/java/rx/Scheduler.java +++ b/rxjava-core/src/main/java/rx/Scheduler.java @@ -151,39 +151,6 @@ public Subscription schedule(T state, Func2 acti } } - /** - * Schedules a cancelable action to be executed. - * - * @param action - * Action to schedule. - * @return a subscription to be able to unsubscribe from action. - */ - public Subscription schedule(final Func1 action) { - return schedule(null, new Func2() { - - @Override - public Subscription call(Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(scheduler); - } - }); - } - - /** - * Schedules a cancelable action to be executed. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - public Subscription schedule(final Func0 action) { - return schedule(null, new Func2() { - - @Override - public Subscription call(@SuppressWarnings("unused") Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(); - } - }); - } /** * Schedules an action to be executed. @@ -203,27 +170,6 @@ public Subscription call(@SuppressWarnings("unused") Scheduler scheduler, @Suppr }); } - /** - * Schedules a cancelable action to be executed in delayTime. - * - * @param action - * Action to schedule. - * @param delayTime - * Time the action is to be delayed before executing. - * @param unit - * Time unit of the delay time. - * @return a subscription to be able to unsubscribe from action. - */ - public Subscription schedule(final Func1 action, long delayTime, TimeUnit unit) { - return schedule(null, new Func2() { - - @Override - public Subscription call(Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(scheduler); - } - }, delayTime, unit); - } - /** * Schedules an action to be executed in delayTime. * @@ -242,66 +188,6 @@ public Subscription call(@SuppressWarnings("unused") Scheduler scheduler, @Suppr }, delayTime, unit); } - /** - * Schedules a cancelable action to be executed in delayTime. - * - * @param action - * action - * @return a subscription to be able to unsubscribe from action. - */ - public Subscription schedule(final Func0 action, long delayTime, TimeUnit unit) { - return schedule(null, new Func2() { - - @Override - public Subscription call(@SuppressWarnings("unused") Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(); - } - }, delayTime, unit); - } - - /** - * Schedules a cancelable action to be executed periodically. - * - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @param unit - * The time unit the interval above is given in. - * @return A subscription to be able to unsubscribe from action. - */ - public Subscription schedulePeriodically(final Func1 action, long initialDelay, long period, TimeUnit unit) { - return schedulePeriodically(null, new Func2() { - @Override - public Subscription call(Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(scheduler); - } - }, initialDelay, period, unit); - } - - /** - * Schedules a cancelable action to be executed periodically. - * - * @param action - * The action to execute periodically. - * @param initialDelay - * Time to wait before executing the action for the first time. - * @param period - * The time interval to wait each time in between executing the action. - * @param unit - * The time unit the interval above is given in. - * @return A subscription to be able to unsubscribe from action. - */ - public Subscription schedulePeriodically(final Func0 action, long initialDelay, long period, TimeUnit unit) { - return schedulePeriodically(null, new Func2() { - @Override - public Subscription call(@SuppressWarnings("unused") Scheduler scheduler, @SuppressWarnings("unused") Void state) { - return action.call(); - } - }, initialDelay, period, unit); - } /** * Schedules an action to be executed periodically. diff --git a/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java b/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java index 8c0342a37f..5aa6ff6f68 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java +++ b/rxjava-core/src/main/java/rx/operators/OperationSubscribeOn.java @@ -16,6 +16,8 @@ package rx.operators; import org.junit.Test; +import org.mockito.Matchers; + import rx.Observable; import rx.Observer; import rx.Scheduler; @@ -24,6 +26,7 @@ import rx.util.functions.Action0; import rx.util.functions.Func0; import rx.util.functions.Func1; +import rx.util.functions.Func2; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; @@ -50,9 +53,9 @@ public SubscribeOn(Observable source, Scheduler scheduler) { @Override public Subscription call(final Observer observer) { - return scheduler.schedule(new Func0() { + return scheduler.schedule(null, new Func2() { @Override - public Subscription call() { + public Subscription call(Scheduler s, T t) { return new ScheduledSubscription(source.subscribe(observer), scheduler); } }); @@ -91,7 +94,7 @@ public void testSubscribeOn() { Observer observer = mock(Observer.class); Subscription subscription = Observable.create(subscribeOn(w, scheduler)).subscribe(observer); - verify(scheduler, times(1)).schedule(any(Func0.class)); + verify(scheduler, times(1)).schedule(isNull(), any(Func2.class)); subscription.unsubscribe(); verify(scheduler, times(1)).schedule(any(Action0.class)); verifyNoMoreInteractions(scheduler); diff --git a/rxjava-core/src/main/java/rx/operators/OperatorTester.java b/rxjava-core/src/main/java/rx/operators/OperatorTester.java index 22283673d5..664dd37cc8 100644 --- a/rxjava-core/src/main/java/rx/operators/OperatorTester.java +++ b/rxjava-core/src/main/java/rx/operators/OperatorTester.java @@ -15,25 +15,11 @@ */ package rx.operators; -import static org.junit.Assert.*; - -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; - -import org.junit.Test; -import rx.Observable; -import rx.Observer; import rx.Scheduler; import rx.Subscription; -import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; -import rx.util.functions.Func0; -import rx.util.functions.Func1; import rx.util.functions.Func2; /** @@ -77,16 +63,6 @@ public Subscription schedule(Action0 action) { return underlying.schedule(action); } - @Override - public Subscription schedule(Func0 action) { - return underlying.schedule(action); - } - - @Override - public Subscription schedule(Func1 action) { - return underlying.schedule(action); - } - @Override public Subscription schedule(T state, Func2 action) { return underlying.schedule(state, action); @@ -97,16 +73,6 @@ public Subscription schedule(Action0 action, long dueTime, TimeUnit unit) { return underlying.schedule(action, dueTime, unit); } - @Override - public Subscription schedule(Func0 action, long dueTime, TimeUnit unit) { - return underlying.schedule(action, dueTime, unit); - } - - @Override - public Subscription schedule(Func1 action, long dueTime, TimeUnit unit) { - return underlying.schedule(action, dueTime, unit); - } - @Override public Subscription schedule(T state, Func2 action, long dueTime, TimeUnit unit) { return underlying.schedule(state, action, dueTime, unit); @@ -117,16 +83,6 @@ public Subscription schedulePeriodically(Action0 action, long initialDelay, long return underlying.schedulePeriodically(action, initialDelay, period, unit); } - @Override - public Subscription schedulePeriodically(Func0 action, long initialDelay, long period, TimeUnit unit) { - return underlying.schedulePeriodically(action, initialDelay, period, unit); - } - - @Override - public Subscription schedulePeriodically(Func1 action, long initialDelay, long period, TimeUnit unit) { - return underlying.schedulePeriodically(action, initialDelay, period, unit); - } - @Override public Subscription schedulePeriodically(T state, Func2 action, long initialDelay, long period, TimeUnit unit) { return underlying.schedulePeriodically(state, action, initialDelay, period, unit); From 8c87c29bea5e076bdc4202af5626d474ab1c7117 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 21:05:08 -0700 Subject: [PATCH 11/22] Groovy ExtensionModule to support groovy.lang.Closure This adds support for the Groovy closure by adding extension methods that overload Action/Function. --- .../rx/lang/groovy/GroovyActionWrapper.java | 61 ++++++ .../rx/lang/groovy/GroovyFunctionWrapper.java | 68 +++++++ .../lang/groovy/RxGroovyExtensionModule.java | 179 ++++++++++++++++++ .../RxGroovyPropertiesModuleFactory.java | 37 ++++ ...rg.codehaus.groovy.runtime.ExtensionModule | 1 + 5 files changed, 346 insertions(+) create mode 100644 language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyActionWrapper.java create mode 100644 language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyFunctionWrapper.java create mode 100644 language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyExtensionModule.java create mode 100644 language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyPropertiesModuleFactory.java create mode 100644 language-adaptors/rxjava-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule diff --git a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyActionWrapper.java b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyActionWrapper.java new file mode 100644 index 0000000000..24394e1db7 --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyActionWrapper.java @@ -0,0 +1,61 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.lang.groovy; + +import groovy.lang.Closure; +import rx.util.functions.Action; +import rx.util.functions.Action0; +import rx.util.functions.Action1; +import rx.util.functions.Action2; +import rx.util.functions.Action3; + +/** + * Concrete wrapper that accepts a {@link Closure} and produces any needed Rx {@link Action}. + * + * @param + * @param + * @param + * @param + */ +public class GroovyActionWrapper implements Action, Action0, Action1, Action2, Action3 { + + private final Closure closure; + + public GroovyActionWrapper(Closure closure) { + this.closure = closure; + } + + @Override + public void call() { + closure.call(); + } + + @Override + public void call(T1 t1) { + closure.call(t1); + } + + @Override + public void call(T1 t1, T2 t2) { + closure.call(t1, t2); + } + + @Override + public void call(T1 t1, T2 t2, T3 t3) { + closure.call(t1, t2, t3); + } + +} \ No newline at end of file diff --git a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyFunctionWrapper.java b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyFunctionWrapper.java new file mode 100644 index 0000000000..6d4d34ef8e --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyFunctionWrapper.java @@ -0,0 +1,68 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.lang.groovy; + +import groovy.lang.Closure; +import rx.util.functions.Func0; +import rx.util.functions.Func1; +import rx.util.functions.Func2; +import rx.util.functions.Func3; +import rx.util.functions.Func4; +import rx.util.functions.Function; + +/** + * Concrete wrapper that accepts a {@link Closure} and produces any needed Rx {@link Function}. + * + * @param + * @param + * @param + * @param + * @param + */ +public class GroovyFunctionWrapper implements Func0, Func1, Func2, Func3, Func4 { + + private final Closure closure; + + + public GroovyFunctionWrapper(Closure closure) { + this.closure = closure; + } + + @Override + public R call() { + return (R) closure.call(); + } + + @Override + public R call(T1 t1) { + return (R) closure.call(t1); + } + + @Override + public R call(T1 t1, T2 t2) { + return (R) closure.call(t1, t2); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3) { + return (R) closure.call(t1, t2, t3); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3, T4 t4) { + return (R) closure.call(t1, t2, t3, t4); + } +} \ No newline at end of file diff --git a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyExtensionModule.java b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyExtensionModule.java new file mode 100644 index 0000000000..91350cb56c --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyExtensionModule.java @@ -0,0 +1,179 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.lang.groovy; + +import groovy.lang.Closure; +import groovy.lang.GroovySystem; +import groovy.lang.MetaMethod; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.codehaus.groovy.reflection.CachedClass; +import org.codehaus.groovy.reflection.ReflectionCache; +import org.codehaus.groovy.runtime.m12n.ExtensionModule; +import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl; + +import rx.Observable; +import rx.observables.BlockingObservable; +import rx.util.functions.Action; +import rx.util.functions.Function; + +/** + * ExtensionModule that adds extension methods to support groovy.lang.Closure + * anywhere rx.util.functions.Function/Action is used in classes defined in CLASS_TO_EXTEND. + * + * It is specifically intended for providing extension methods on Observable. + */ +public class RxGroovyExtensionModule extends ExtensionModule { + + @SuppressWarnings("rawtypes") + private final static Class[] CLASS_TO_EXTEND = new Class[] { Observable.class, BlockingObservable.class }; + + public RxGroovyExtensionModule() { + super("RxGroovyExtensionModule", "1.0"); + } + + /** + * Keeping this code around a little while as it was hard to figure out ... and I'm still messing with it while debugging. + * + * Once the rest of this ExtensionModule stuff is working I'll delete this method. + * + * This is used for manually initializing rather than going via the org.codehaus.groovy.runtime.ExtensionModule properties file. + */ + public static void initializeManuallyForTesting() { + System.out.println("initialize"); + MetaClassRegistryImpl mcRegistry = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()); + // RxGroovyExtensionModule em = new RxGroovyExtensionModule(); + + Properties p = new Properties(); + p.setProperty("moduleFactory", "rx.lang.groovy.RxGroovyPropertiesModuleFactory"); + Map> metaMethods = new HashMap>(); + mcRegistry.registerExtensionModuleFromProperties(p, RxGroovyExtensionModule.class.getClassLoader(), metaMethods); + + for (ExtensionModule m : mcRegistry.getModuleRegistry().getModules()) { + System.out.println("Module: " + m.getName()); + } + + for (CachedClass cc : metaMethods.keySet()) { + System.out.println("Adding MetaMethods to CachedClass: " + cc); + cc.addNewMopMethods(metaMethods.get(cc)); + } + } + + @SuppressWarnings("rawtypes") + @Override + public List getMetaMethods() { + // System.out.println("**** RxGroovyExtensionModule => Initializing and returning MetaMethods."); + List methods = new ArrayList(); + + for (Class classToExtend : CLASS_TO_EXTEND) { + for (final Method m : classToExtend.getMethods()) { + for (Class c : m.getParameterTypes()) { + if (Function.class.isAssignableFrom(c)) { + methods.add(createMetaMethod(m)); + // break out of parameter-type loop + break; + } + } + } + } + + return methods; + } + + private MetaMethod createMetaMethod(final Method m) { + return new MetaMethod() { + + @Override + public int getModifiers() { + return m.getModifiers(); + } + + @Override + public String getName() { + return m.getName(); + } + + @SuppressWarnings("rawtypes") + @Override + public Class getReturnType() { + return m.getReturnType(); + } + + @Override + public CachedClass getDeclaringClass() { + return ReflectionCache.getCachedClass(m.getDeclaringClass()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Object invoke(Object object, Object[] arguments) { + // System.out.println("***** RxGroovyExtensionModule => invoked [" + getName() + "]: " + object + " args: " + arguments[0]); + try { + Object[] newArgs = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + final Object o = arguments[i]; + if (o instanceof Closure) { + if (Action.class.isAssignableFrom(m.getParameterTypes()[i])) { + newArgs[i] = new GroovyActionWrapper((Closure) o); + } else { + newArgs[i] = new GroovyFunctionWrapper((Closure) o); + } + + } else { + newArgs[i] = o; + } + } + return m.invoke(object, newArgs); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) { + // re-throw whatever was thrown to us + throw (RuntimeException) e.getCause(); + } else { + throw new RuntimeException(e); + } + } + } + + @SuppressWarnings("rawtypes") + @Override + public CachedClass[] getParameterTypes() { + Class[] pts = m.getParameterTypes(); + CachedClass[] cc = new CachedClass[pts.length]; + for (int i = 0; i < pts.length; i++) { + if (Function.class.isAssignableFrom(pts[i])) { + // function type to be replaced by closure + cc[i] = ReflectionCache.getCachedClass(Closure.class); + } else { + // non-function type + cc[i] = ReflectionCache.getCachedClass(pts[i]); + } + } + return cc; + } + }; + } +} diff --git a/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyPropertiesModuleFactory.java b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyPropertiesModuleFactory.java new file mode 100644 index 0000000000..149bca5621 --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/RxGroovyPropertiesModuleFactory.java @@ -0,0 +1,37 @@ +/** + * Copyright 2013 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package rx.lang.groovy; + +import java.util.Properties; + +import org.codehaus.groovy.runtime.m12n.ExtensionModule; +import org.codehaus.groovy.runtime.m12n.PropertiesModuleFactory; + +/** + * Factory for {@link RxGroovyExtensionModule} to add extension methods. + *

+ * This is loaded from /META-INF/services/org.codehaus.groovy.runtime.ExtensionModule + *

+ * The property is defined as: moduleFactory=rx.lang.groovy.RxGroovyPropertiesModuleFactory + */ +public class RxGroovyPropertiesModuleFactory extends PropertiesModuleFactory { + + @Override + public ExtensionModule newModule(Properties properties, ClassLoader classLoader) { + return new RxGroovyExtensionModule(); + } + +} diff --git a/language-adaptors/rxjava-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/language-adaptors/rxjava-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule new file mode 100644 index 0000000000..975068e80c --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule @@ -0,0 +1 @@ +moduleFactory=rx.lang.groovy.RxGroovyPropertiesModuleFactory \ No newline at end of file From da4a8e5014530be9410b467d6ea35da4dfddd2b2 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 21:36:05 -0700 Subject: [PATCH 12/22] 0.11.0-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index bf54d765c8..fa6cdb407b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.10.2 +version=0.11.0-SNAPSHOT From f91a2ea489c8650a1354a9d12695795fc3e71f37 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 22:24:40 -0700 Subject: [PATCH 13/22] Observable API reduction - remove static methods that are not entry points (creators or combinatorial) - remove deprecated methods This change was done to: - Reduce the footprint of the API - Clarify the API so instance methods are preferred unless the static method is appropriate as an entry point - Remove duplicate method signatures (such as a buffer method) where the only difference was one was static. This actually causes issues at the bytecode level with dynamic languages since the only difference between them is a modifier making one of them static. Some dynamic languages have a hard time choosing between the two methods when both have the same signature. --- rxjava-core/src/main/java/rx/Observable.java | 1740 ++++------------- .../rx/operators/OperationDematerialize.java | 2 +- .../rx/operators/OperationToIterator.java | 4 +- .../java/rx/operators/OperationWhere.java | 66 - 4 files changed, 331 insertions(+), 1481 deletions(-) delete mode 100644 rxjava-core/src/main/java/rx/operators/OperationWhere.java diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index ae3042ba1b..98c7a8b441 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -1,12 +1,12 @@ /** * Copyright 2013 Netflix, Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,16 +36,13 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import rx.concurrency.Schedulers; import rx.observables.BlockingObservable; import rx.observables.ConnectableObservable; import rx.observables.GroupedObservable; -import rx.operators.OperationOnExceptionResumeNextViaObservable; -import rx.operators.SafeObservableSubscription; -import rx.operators.SafeObserver; import rx.operators.OperationAll; import rx.operators.OperationBuffer; import rx.operators.OperationCache; -import rx.operators.OperationCombineLatest; import rx.operators.OperationConcat; import rx.operators.OperationDefer; import rx.operators.OperationDematerialize; @@ -61,6 +58,7 @@ import rx.operators.OperationOnErrorResumeNextViaFunction; import rx.operators.OperationOnErrorResumeNextViaObservable; import rx.operators.OperationOnErrorReturn; +import rx.operators.OperationOnExceptionResumeNextViaObservable; import rx.operators.OperationSample; import rx.operators.OperationScan; import rx.operators.OperationSkip; @@ -76,8 +74,9 @@ import rx.operators.OperationToObservableIterable; import rx.operators.OperationToObservableList; import rx.operators.OperationToObservableSortedList; -import rx.operators.OperationWhere; import rx.operators.OperationZip; +import rx.operators.SafeObservableSubscription; +import rx.operators.SafeObserver; import rx.plugins.RxJavaErrorHandler; import rx.plugins.RxJavaObservableExecutionHook; import rx.plugins.RxJavaPlugins; @@ -115,12 +114,12 @@ *

* For more information see the RxJava * Wiki - * + * * @param */ public class Observable { -//TODO use a consistent parameter naming scheme (for example: for all operators that modify a source Observable, the parameter representing that source Observable should have the same name, e.g. "source" -- currently such parameters are named any of "sequence", "that", "source", "items", or "observable") + //TODO use a consistent parameter naming scheme (for example: for all operators that modify a source Observable, the parameter representing that source Observable should have the same name, e.g. "source" -- currently such parameters are named any of "sequence", "that", "source", "items", or "observable") private final static RxJavaObservableExecutionHook hook = RxJavaPlugins.getInstance().getObservableExecutionHook(); @@ -131,7 +130,7 @@ public class Observable { *

* NOTE: Use {@link #create(Func1)} to create an Observable instead of this method unless you * specifically have a need for inheritance. - * + * * @param onSubscribe * {@link Func1} to be executed when {@link #subscribe(Observer)} is called. */ @@ -147,16 +146,14 @@ protected Observable() { /** * An {@link Observer} must call an Observable's {@code subscribe} method in order to * receive items and notifications from the Observable. - * + * *

A typical implementation of {@code subscribe} does the following: *

- * It stores a reference to the Observer in a collection object, such as a - * {@code List} object. + * It stores a reference to the Observer in a collection object, such as a {@code List} object. *

* It returns a reference to the {@link Subscription} interface. This enables Observers to * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} - * method. + * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} method. *

* An Observable<T> instance is responsible for accepting all subscriptions * and notifying all Observers. Unless the documentation for a particular @@ -165,13 +162,13 @@ protected Observable() { *

* For more information see the * RxJava Wiki - * - * @param observer the observer + * + * @param observer + * the observer * @return a {@link Subscription} reference with which the {@link Observer} can stop receiving items * before the Observable has finished sending them * @throws IllegalArgumentException - * if the {@link Observer} provided as the argument to {@code subscribe()} is - * {@code null} + * if the {@link Observer} provided as the argument to {@code subscribe()} is {@code null} */ public Subscription subscribe(Observer observer) { // allow the hook to intercept and/or decorate @@ -226,26 +223,24 @@ public Subscription subscribe(Observer observer) { /** * An {@link Observer} must call an Observable's {@code subscribe} method in order to * receive items and notifications from the Observable. - * + * *

A typical implementation of {@code subscribe} does the following: *

- * It stores a reference to the Observer in a collection object, such as a - * {@code List} object. + * It stores a reference to the Observer in a collection object, such as a {@code List} object. *

* It returns a reference to the {@link Subscription} interface. This enables Observers to * unsubscribe, that is, to stop receiving items and notifications before the Observable stops - * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} - * method. + * sending them, which also invokes the Observer's {@link Observer#onCompleted onCompleted} method. *

* An {@code Observable} instance is responsible for accepting all subscriptions - * and notifying all Observers. Unless the documentation for a particular - * {@code Observable} implementation indicates otherwise, Observers should make no + * and notifying all Observers. Unless the documentation for a particular {@code Observable} implementation indicates otherwise, Observers should make no * assumptions about the order in which multiple Observers will receive their notifications. *

* For more information see the * RxJava Wiki - * - * @param observer the observer + * + * @param observer + * the observer * @param scheduler * the {@link Scheduler} on which Observers subscribe to the Observable * @return a {@link Subscription} reference with which Observers can stop receiving items and @@ -281,13 +276,13 @@ public Subscription subscribe(final Map callbacks) { /** * Wrapping since raw functions provided by the user are being invoked. - * + * * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" */ return protectivelyWrapAndSubscribe(new Observer() { @Override - public void onCompleted() { + public void onCompleted() { Object onComplete = callbacks.get("onCompleted"); if (onComplete != null) { Functions.from(onComplete).call(); @@ -306,11 +301,11 @@ public void onError(Throwable e) { } @Override - public void onNext(Object args) { + public void onNext(Object args) { onNext.call(args); } - }); + }); } public Subscription subscribe(final Map callbacks, Scheduler scheduler) { @@ -324,7 +319,7 @@ public Subscription subscribe(final Action1 onNext) { /** * Wrapping since raw functions provided by the user are being invoked. - * + * * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" */ return protectivelyWrapAndSubscribe(new Observer() { @@ -362,7 +357,7 @@ public Subscription subscribe(final Action1 onNext, final Action1 /** * Wrapping since raw functions provided by the user are being invoked. - * + * * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" */ return protectivelyWrapAndSubscribe(new Observer() { @@ -403,7 +398,7 @@ public Subscription subscribe(final Action1 onNext, final Action1 /** * Wrapping since raw functions provided by the user are being invoked. - * + * * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" */ return protectivelyWrapAndSubscribe(new Observer() { @@ -434,7 +429,7 @@ public Subscription subscribe(final Action1 onNext, final Action1 /** * Returns a {@link ConnectableObservable} that upon connection causes the source Observable to * push results into the specified subject. - * + * * @param subject * the {@link Subject} for the {@link ConnectableObservable} to push source items * into @@ -444,12 +439,12 @@ public Subscription subscribe(final Action1 onNext, final Action1 * push results into the specified {@link Subject} */ public ConnectableObservable multicast(Subject subject) { - return multicast(this, subject); + return OperationMulticast.multicast(this, subject); } /** * Allow the {@link RxJavaErrorHandler} to receive the exception from onError. - * + * * @param e */ private void handleError(Throwable e) { @@ -459,9 +454,9 @@ private void handleError(Throwable e) { /** * An Observable that never sends any information to an {@link Observer}. - * + * * This Observable is useful primarily for testing purposes. - * + * * @param * the type of item emitted by the Observable */ @@ -479,9 +474,8 @@ public Subscription call(Observer t1) { } /** - * an Observable that invokes {@link Observer#onError onError} when the {@link Observer} - * subscribes to it. - * + * an Observable that invokes {@link Observer#onError onError} when the {@link Observer} subscribes to it. + * * @param * the type of item emitted by the Observable */ @@ -492,7 +486,7 @@ public ThrowObservable(final Throwable exception) { /** * Accepts an {@link Observer} and calls its {@link Observer#onError onError} method. - * + * * @param observer * an {@link Observer} of this Observable * @return a reference to the subscription @@ -509,229 +503,12 @@ public Subscription call(Observer observer) { } /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers. The current buffer is emitted and replaced with a new buffer when the - * Observable produced by the specified {@link Func0} produces a {@link BufferClosing} object. The - * {@link Func0} will then be used to create a new Observable to listen for the end of the next buffer. - * - * @param source - * The source {@link Observable} which produces values. - * @param bufferClosingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every buffer created. - * When this {@link Observable} produces a {@link BufferClosing} object, the associated buffer - * is emitted and replaced with a new one. - * @return - * An {@link Observable} which produces connected non-overlapping buffers, which are emitted - * when the current {@link Observable} created with the {@link Func0} argument produces a - * {@link BufferClosing} object. - */ - public static Observable> buffer(Observable source, Func0> bufferClosingSelector) { - return create(OperationBuffer.buffer(source, bufferClosingSelector)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces buffers. - * Buffers are created when the specified "bufferOpenings" Observable produces a {@link BufferOpening} object. - * Additionally the {@link Func0} argument is used to create an Observable which produces {@link BufferClosing} - * objects. When this Observable produces such an object, the associated buffer is emitted. - * - * @param source - * The source {@link Observable} which produces values. - * @param bufferOpenings - * The {@link Observable} which when it produces a {@link BufferOpening} object, will cause - * another buffer to be created. - * @param bufferClosingSelector - * The {@link Func0} which is used to produce an {@link Observable} for every buffer created. - * When this {@link Observable} produces a {@link BufferClosing} object, the associated buffer - * is emitted. - * @return - * An {@link Observable} which produces buffers which are created and emitted when the specified - * {@link Observable}s publish certain objects. - */ - public static Observable> buffer(Observable source, Observable bufferOpenings, Func1> bufferClosingSelector) { - return create(OperationBuffer.buffer(source, bufferOpenings, bufferClosingSelector)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each containing "count" elements. When the source Observable completes or - * encounters an error, the current buffer is emitted, and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param count - * The maximum size of each buffer before it should be emitted. - * @return - * An {@link Observable} which produces connected non-overlapping buffers containing at most - * "count" produced values. - */ - public static Observable> buffer(Observable source, int count) { - return create(OperationBuffer.buffer(source, count)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces buffers every - * "skip" values, each containing "count" elements. When the source Observable completes or encounters an error, - * the current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param count - * The maximum size of each buffer before it should be emitted. - * @param skip - * How many produced values need to be skipped before starting a new buffer. Note that when "skip" and - * "count" are equals that this is the same operation as {@link Observable#buffer(Observable, int)}. - * @return - * An {@link Observable} which produces buffers every "skipped" values containing at most - * "count" produced values. - */ - public static Observable> buffer(Observable source, int count, int skip) { - return create(OperationBuffer.buffer(source, count, skip)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument. When the source - * Observable completes or encounters an error, the current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted, and - * replaced with a new buffer. - * @param unit - * The unit of time which applies to the "timespan" argument. - * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. - */ - public static Observable> buffer(Observable source, long timespan, TimeUnit unit) { - return create(OperationBuffer.buffer(source, timespan, unit)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument. When the source - * Observable completes or encounters an error, the current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted, and - * replaced with a new buffer. - * @param unit - * The unit of time which applies to the "timespan" argument. - * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. - * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. - */ - public static Observable> buffer(Observable source, long timespan, TimeUnit unit, Scheduler scheduler) { - return create(OperationBuffer.buffer(source, timespan, unit, scheduler)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes - * or encounters an error, the current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted, and - * replaced with a new buffer. - * @param unit - * The unit of time which applies to the "timespan" argument. - * @param count - * The maximum size of each buffer before it should be emitted. - * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after - * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). - */ - public static Observable> buffer(Observable source, long timespan, TimeUnit unit, int count) { - return create(OperationBuffer.buffer(source, timespan, unit, count)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable produces connected - * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size - * specified by the "count" argument (which ever is reached first). When the source Observable completes - * or encounters an error, the current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted, and - * replaced with a new buffer. - * @param unit - * The unit of time which applies to the "timespan" argument. - * @param count - * The maximum size of each buffer before it should be emitted. - * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. - * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after - * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). - */ - public static Observable> buffer(Observable source, long timespan, TimeUnit unit, int count, Scheduler scheduler) { - return create(OperationBuffer.buffer(source, timespan, unit, count, scheduler)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer - * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the - * current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted. - * @param timeshift - * The period of time after which a new buffer will be created. - * @param unit - * The unit of time which applies to the "timespan" and "timeshift" argument. - * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after - * a fixed timespan has elapsed. - */ - public static Observable> buffer(Observable source, long timespan, long timeshift, TimeUnit unit) { - return create(OperationBuffer.buffer(source, timespan, timeshift, unit)); - } - - /** - * Creates an Observable which produces buffers of collected values. This Observable starts a new buffer - * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan - * specified by the "timespan" argument. When the source Observable completes or encounters an error, the - * current buffer is emitted and the event is propagated. - * - * @param source - * The source {@link Observable} which produces values. - * @param timespan - * The period of time each buffer is collecting values before it should be emitted. - * @param timeshift - * The period of time after which a new buffer will be created. - * @param unit - * The unit of time which applies to the "timespan" and "timeshift" argument. - * @param scheduler - * The {@link Scheduler} to use when determining the end and start of a buffer. - * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after - * a fixed timespan has elapsed. - */ - public static Observable> buffer(Observable source, long timespan, long timeshift, TimeUnit unit, Scheduler scheduler) { - return create(OperationBuffer.buffer(source, timespan, timeshift, unit, scheduler)); - } - - /** - * Creates an Observable that will execute the given function when an {@link Observer} - * subscribes to it. + * Creates an Observable that will execute the given function when an {@link Observer} subscribes to it. *

* *

* Write the function you pass to create so that it behaves as an Observable: It - * should invoke the Observer's {@link Observer#onNext onNext}, - * {@link Observer#onError onError}, and {@link Observer#onCompleted onCompleted} methods + * should invoke the Observer's {@link Observer#onNext onNext}, {@link Observer#onError onError}, and {@link Observer#onCompleted onCompleted} methods * appropriately. *

* A well-formed Observable must invoke either the Observer's onCompleted method @@ -739,12 +516,11 @@ public static Observable> buffer(Observable source, long timespan *

* See Rx Design Guidelines (PDF) * for detailed information. - * + * * @param * the type of the items that this Observable emits * @param func - * a function that accepts an {@code Observer}, invokes its - * {@code onNext}, {@code onError}, and {@code onCompleted} methods + * a function that accepts an {@code Observer}, invokes its {@code onNext}, {@code onError}, and {@code onCompleted} methods * as appropriate, and returns a {@link Subscription} to allow the Observer to * canceling the subscription * @return an Observable that, when an {@link Observer} subscribes to it, will execute the given @@ -759,180 +535,102 @@ public static Observable create(Func1, Subscription> func) { * its {@link Observer#onCompleted onCompleted} method. *

* - * + * * @param * the type of the items (ostensibly) emitted by the Observable * @return an Observable that returns no data to the {@link Observer} and immediately invokes * the {@link Observer}'s {@link Observer#onCompleted() onCompleted} method */ public static Observable empty() { - return toObservable(new ArrayList()); + return from(new ArrayList()); } /** - * Returns an Observable that invokes an {@link Observer}'s {@link Observer#onError onError} - * method when the Observer subscribes to it + * Returns an Observable that invokes an {@link Observer}'s {@link Observer#onError onError} method when the Observer subscribes to it *

* - * + * * @param exception * the particular error to report * @param * the type of the items (ostensibly) emitted by the Observable - * @return an Observable that invokes the {@link Observer}'s - * {@link Observer#onError onError} method when the Observer subscribes to it + * @return an Observable that invokes the {@link Observer}'s {@link Observer#onError onError} method when the Observer subscribes to it */ public static Observable error(Throwable exception) { return new ThrowObservable(exception); } - /** - * Filters an Observable by discarding any items it emits that do not satisfy some predicate. - *

- * - * - * @param that - * the Observable to filter - * @param predicate - * a function that evaluates the items emitted by the source Observable, returning - * {@code true} if they pass the filter - * @return an Observable that emits only those items emitted by the source Observable for which the - * predicate evaluates to {@code true} - */ - public static Observable filter(Observable that, Func1 predicate) { - return create(OperationFilter.filter(that, predicate)); - } - - /** - * Filters an Observable by discarding any items it emits that do not satisfy some predicate - *

- * - * - * - * @param that - * the Observable to filter - * @param predicate - * a function that evaluates an item emitted by the source Observable, and - * returns {@code true} if it passes the filter - * @return an Observable that emits only those items emitted by the source Observable for which - * the predicate evaluates to {@code true} - */ - public static Observable where(Observable that, Func1 predicate) { - return create(OperationWhere.where(that, predicate)); - } - /** * Converts an {@link Iterable} sequence into an Observable. *

* - * - *

Implementation note: the entire iterable sequence will be immediately emitted each time an - * {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, + * + *

Implementation note: the entire iterable sequence will be immediately emitted each time an {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, * it in not possible to unsubscribe from the sequence before it completes. - * + * * @param iterable * the source {@link Iterable} sequence * @param * the type of items in the {@link Iterable} sequence and the type of items to be * emitted by the resulting Observable * @return an Observable that emits each item in the source {@link Iterable} sequence - * @see #toObservable(Iterable) */ public static Observable from(Iterable iterable) { - return toObservable(iterable); + return create(OperationToObservableIterable.toObservableIterable(iterable)); } /** * Converts an Array into an Observable. *

* - * - *

Implementation note: the entire array will be immediately emitted each time an - * {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, + * + *

Implementation note: the entire array will be immediately emitted each time an {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, * it in not possible to unsubscribe from the sequence before it completes. - * + * * @param items * the source Array * @param * the type of items in the Array, and the type of items to be emitted by the * resulting Observable * @return an Observable that emits each item in the source Array - * @see #toObservable(Object...) */ public static Observable from(T... items) { - return toObservable(items); + return create(OperationToObservableIterable.toObservableIterable(Arrays.asList(items))); } /** * Generates an Observable that emits a sequence of integers within a specified range. *

* - * - *

Implementation note: the entire range will be immediately emitted each time an - * {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, + * + *

Implementation note: the entire range will be immediately emitted each time an {@link Observer} subscribes. Since this occurs before the {@link Subscription} is returned, * it in not possible to unsubscribe from the sequence before it completes. - * + * * @param start * the value of the first integer in the sequence * @param count * the number of sequential integers to generate - * + * * @return an Observable that emits a range of sequential integers - * + * * @see Observable.Range Method (Int32, Int32) */ public static Observable range(int start, int count) { return from(Range.createWithCount(start, count)); } - /** - * Asynchronously subscribes and unsubscribes Observers on the specified {@link Scheduler}. - *

- * - * - * @param source - * the source Observable - * @param scheduler - * the {@link Scheduler} to perform subscription and unsubscription actions on - * @param - * the type of the items emitted by the Observable - * @return the source Observable modified so that its subscriptions and unsubscriptions happen - * on the specified {@link Scheduler} - */ - public static Observable subscribeOn(Observable source, Scheduler scheduler) { - return create(OperationSubscribeOn.subscribeOn(source, scheduler)); - } - - /** - * Asynchronously notify Observers on the specified {@link Scheduler}. - *

- * - * - * @param source - * the source Observable - * @param scheduler - * the {@link Scheduler} to notify Observers on - * @param - * the type of the items emitted by the Observable - * @return the source Observable modified so that its Observers are notified on the specified - * {@link Scheduler} - */ - public static Observable observeOn(Observable source, Scheduler scheduler) { - return create(OperationObserveOn.observeOn(source, scheduler)); - } - /** * Returns an Observable that calls an Observable factory to create its Observable for each * new Observer that subscribes. That is, for each subscriber, the actuall Observable is determined * by the factory function. - * + * *

* *

* The defer operator allows you to defer or delay emitting items from an Observable until such * time as an Observer subscribes to the Observable. This allows an {@link Observer} to easily * obtain updates or a refreshed version of the sequence. - * + * * @param observableFactory * the Observable factory function to invoke for each {@link Observer} that * subscribes to the resulting Observable @@ -957,7 +655,7 @@ public static Observable defer(Func0> observableFactory) { * from() will convert an {@link Iterable} object into an Observable that emits * each of the items in the Iterable, one at a time, while the just() method * converts an Iterable into an Observable that emits the entire Iterable as a single item. - * + * * @param value * the item to pass to the {@link Observer}'s {@link Observer#onNext onNext} method * @param @@ -968,125 +666,40 @@ public static Observable just(T value) { List list = new ArrayList(); list.add(value); - return toObservable(list); + return from(list); } /** - * Returns an Observable that applies a function of your choosing to each item emitted by an - * Observable and emits the result. + * Flattens a list of Observables into one Observable, without any transformation. *

- * - * - * @param sequence - * the source Observable - * @param func - * a function to apply to each item emitted by the source Observable - * @param - * the type of items emitted by the the source Observable - * @param - * the type of items to be emitted by the resulting Observable - * @return an Observable that emits the items from the source Observable as transformed by the - * given function + * + *

+ * You can combine the items emitted by multiple Observables so that they act like a single + * Observable, by using the merge method. + * + * @param source + * a list of Observables + * @return an Observable that emits items that are the result of flattening the {@code source} list of Observables + * @see MSDN: Observable.Merge */ - public static Observable map(Observable sequence, Func1 func) { - return create(OperationMap.map(sequence, func)); + public static Observable merge(List> source) { + return create(OperationMerge.merge(source)); } /** - * Creates a new Observable by applying a function that you supply to each item emitted by - * the source Observable, where that function returns an Observable, and then merging those - * resulting Observables and emitting the results of this merger. + * Flattens a sequence of Observables emitted by an Observable into one Observable, without any + * transformation. *

- * + * *

- * Note: {@code mapMany} and {@code flatMap} are equivalent. - * - * @param sequence - * the source Observable - * @param func - * a function that, when applied to an item emitted by the source Observable, - * returns an Observable - * @param - * the type of items emitted by the source Observable - * @param - * the type of items emitted by the Observables that are returned from - * {@code func} - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation - * @see #flatMap(Observable, Func1) - */ - public static Observable mapMany(Observable sequence, Func1> func) { - return create(OperationMap.mapMany(sequence, func)); - } - - /** - * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} - * emissions, and marks them with their original notification types within {@link Notification} - * objects. - *

- * - * - * @param sequence - * the Observable you want to materialize in this way - * @return an Observable that emits items that are the result of materializing the - * notifications of the source Observable. - * @see MSDN: Observable.Materialize - */ - public static Observable> materialize(final Observable sequence) { - return create(OperationMaterialize.materialize(sequence)); - } - - /** - * Reverses the effect of {@link #materialize materialize} by transforming the - * {@link Notification} objects emitted by a source Observable into the items or notifications - * they represent. - *

- * - * - * @param sequence - * an Observable that emits {@link Notification} objects that represent the items and - * notifications emitted by an Observable - * @return an Observable that emits the items and notifications embedded in the - * {@link Notification} objects emitted by the source Observable - * @see MSDN: Observable.Dematerialize - */ - public static Observable dematerialize(final Observable> sequence) { - return create(OperationDematerialize.dematerialize(sequence)); - } - - /** - * Flattens a list of Observables into one Observable, without any transformation. - *

- * - *

- * You can combine the items emitted by multiple Observables so that they act like a single - * Observable, by using the merge method. - * - * @param source - * a list of Observables - * @return an Observable that emits items that are the result of flattening the - * {@code source} list of Observables - * @see MSDN: Observable.Merge - */ - public static Observable merge(List> source) { - return create(OperationMerge.merge(source)); - } - - /** - * Flattens a sequence of Observables emitted by an Observable into one Observable, without any - * transformation. - *

- * - *

- * You can combine the items emitted by multiple Observables so that they act like a single - * Observable, by using the {@code merge} method. - * - * @param source - * an Observable that emits Observables - * @return an Observable that emits items that are the result of flattening the items emitted - * by the Observables emitted by the {@code source} Observable - * @see MSDN: Observable.Merge Method + * You can combine the items emitted by multiple Observables so that they act like a single + * Observable, by using the {@code merge} method. + * + * @param source + * an Observable that emits Observables + * @return an Observable that emits items that are the result of flattening the items emitted + * by the Observables emitted by the {@code source} Observable + * @see MSDN: Observable.Merge Method */ public static Observable merge(Observable> source) { return create(OperationMerge.merge(source)); @@ -1099,7 +712,7 @@ public static Observable merge(Observable> source) { *

* You can combine items emitted by multiple Observables so that they act like a single * Observable, by using the {@code merge} method. - * + * * @param source * a series of Observables * @return an Observable that emits items that are the result of flattening the items emitted @@ -1110,34 +723,12 @@ public static Observable merge(Observable... source) { return create(OperationMerge.merge(source)); } - /** - * Returns an Observable that emits the items from the {@code source} Observable until - * the {@code other} Observable emits an item. - *

- * - * - * @param source - * the source Observable - * @param other - * the Observable whose first emitted item will cause {@code takeUntil} to stop - * emitting items from the {@code source} Observable - * @param - * the type of items emitted by {@code source} - * @param - * the type of items emitted by {@code other} - * @return an Observable that emits the items emitted by {@code source} until such time as - * {@code other} emits its first item - */ - public static Observable takeUntil(final Observable source, final Observable other) { - return OperationTakeUntil.takeUntil(source, other); - } - /** * Returns an Observable that emits the items emitted by two or more Observables, one after the * other. *

* - * + * * @param source * a series of Observables * @return an Observable that emits items that are the result of combining the items emitted by @@ -1148,100 +739,6 @@ public static Observable concat(Observable... source) { return create(OperationConcat.concat(source)); } - /** - * Returns an Observable that emits the same items as the source Observable, and then calls - * the given Action after the Observable completes. - *

- * - * - * @param source - * an Observable - * @param action - * an {@link Action0} to be invoked when the source Observable completes - * or errors - * @return an Observable that emits the same items as the source, then invokes the action - * @see MSDN: - * Observable.Finally Method - */ - public static Observable finallyDo(Observable source, Action0 action) { - return create(OperationFinally.finallyDo(source, action)); - } - - /** - * Creates a new Observable by applying a function that you supply to each item emitted by - * the source Observable, where that function returns an Observable, and then merging those - * resulting Observables and emitting the results of this merger. - *

- * - *

- * Note: {@code mapMany} and {@code flatMap} are equivalent. - * - * @param sequence - * the source Observable - * @param func - * a function that, when applied to each item emitted by the source Observable, - * generates an Observable - * @param - * the type of items emitted by the source Observable - * @param - * the type of items emitted by the Observables that are returned from - * {@code func} - * @return an Observable that emits the result of applying the transformation function to each - * item emitted by the source Observable and merging the results of the Observables - * obtained from this transformation - * @see #mapMany(Observable, Func1) - */ - public static Observable flatMap(Observable sequence, Func1> func) { - return mapMany(sequence, func); - } - - /** - *

- * - * - * @param source - * an Observable whose items you want to group - * @param keySelector - * a function that extracts the key for each item omitted by the source Observable - * @param elementSelector - * a function to map each item emitted by the source Observable to an item emitted - * by a {@link GroupedObservable} - * @param - * the key type - * @param - * the type of items emitted by the source Observable - * @param - * the type of items to be emitted by the resulting {@link GroupedObservable}s - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - public static Observable> groupBy(Observable source, final Func1 keySelector, final Func1 elementSelector) { - return create(OperationGroupBy.groupBy(source, keySelector, elementSelector)); - } - - /** - * Groups the items emitted by an Observable according to a specified criterion, and emits these - * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. - *

- * - * - * @param source - * an Observable whose items you want to group - * @param keySelector - * a function that extracts the key for each item emitted by the source Observable - * @param - * the key type - * @param - * the type of items to be emitted by the resulting {@link GroupedObservable}s - * @return an Observable that emits {@link GroupedObservable}s, each of which corresponds to a - * unique key value and emits items representing items from the source Observable that - * share that key value - */ - public static Observable> groupBy(Observable source, final Func1 keySelector) { - return create(OperationGroupBy.groupBy(source, keySelector)); - } - /** * This behaves like {@link #merge(java.util.List)} except that if any of the merged Observables * notify of an error via {@link Observer#onError onError}, {@code mergeDelayError} will @@ -1250,13 +747,12 @@ public static Observable> groupBy(Observable s *

* *

- * Even if multiple merged Observables send {@code onError} notifications, - * {@code mergeDelayError} will only invoke the {@code onError} method of its + * Even if multiple merged Observables send {@code onError} notifications, {@code mergeDelayError} will only invoke the {@code onError} method of its * Observers once. *

* This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. - * + * * @param source * a list of Observables * @return an Observable that emits items that are the result of flattening the items emitted by @@ -1275,13 +771,12 @@ public static Observable mergeDelayError(List> source) { *

* *

- * Even if multiple merged Observables send {@code onError} notifications, - * {@code mergeDelayError} will only invoke the {@code onError} method of its + * Even if multiple merged Observables send {@code onError} notifications, {@code mergeDelayError} will only invoke the {@code onError} method of its * Observers once. *

* This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. - * + * * @param source * an Observable that emits Observables * @return an Observable that emits items that are the result of flattening the items emitted by @@ -1300,13 +795,12 @@ public static Observable mergeDelayError(Observable> source *

* *

- * Even if multiple merged Observables send {@code onError} notifications, - * {@code mergeDelayError} will only invoke the {@code onError} method of its + * Even if multiple merged Observables send {@code onError} notifications, {@code mergeDelayError} will only invoke the {@code onError} method of its * Observers once. *

* This method allows an Observer to receive all successfully emitted items from all of the * source Observables without being interrupted by an error notification from one of them. - * + * * @param source * a series of Observables * @return an Observable that emits items that are the result of flattening the items emitted by @@ -1318,365 +812,18 @@ public static Observable mergeDelayError(Observable... source) { } /** - * Returns an Observable that never sends any items or notifications to an {@link Observer}. - *

- * - *

- * This Observable is useful primarily for testing purposes. - * - * @param - * the type of items (not) emitted by the Observable - * @return an Observable that never sends any items or notifications to an {@link Observer} - */ - public static Observable never() { - return new NeverObservable(); - } - - /** - * Instruct an Observable to pass control to another Observable (the return value of a function) - * rather than invoking {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its Observer, the Observable invokes its {@link Observer}'s - * {@code onError} method, and then quits without invoking any more of its Observer's - * methods. The {@code onErrorResumeNext} method changes this behavior. If you pass a - * function that returns an Observable ({@code resumeFunction}) to - * {@code onErrorResumeNext}, if the source Observable encounters an error, instead of - * invoking its Observer's {@code onError} function, it will instead relinquish control to - * this new Observable, which will invoke the Observer's {@link Observer#onNext onNext} method - * if it is able to do so. In such a case, because no Observable necessarily invokes - * {@code onError}, the Observer may never know that an error happened. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param that - * the source Observable - * @param resumeFunction - * a function that returns an Observable that will take over if the source Observable - * encounters an error - * @return an Observable, identical to the source Observable with its behavior modified as described - */ - public static Observable onErrorResumeNext(final Observable that, final Func1> resumeFunction) { - return create(OperationOnErrorResumeNextViaFunction.onErrorResumeNextViaFunction(that, resumeFunction)); - } - - /** - * Instruct an Observable to pass control to another Observable rather than invoking - * {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its Observer, the Observable invokes its {@link Observer}'s - * {@code onError} method, and then quits without invoking any more of its Observer's - * methods. The {@code onErrorResumeNext} method changes this behavior. If you pass an - * Observable ({@code resumeSequence}) to {@code onErrorResumeNext}, if the original - * Observable encounters an error, instead of invoking its Observer's onError - * method, it will instead relinquish control to this new Observable, which will invoke the - * Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, - * because no Observable necessarily invokes {@code onError}, the Observer may never know - * that an error happened. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param that - * the source Observable - * @param resumeSequence - * a Observable that will take over if the source Observable encounters an error - * @return an Observable, identical to the source Observable with its behavior modified as described - */ - public static Observable onErrorResumeNext(final Observable that, final Observable resumeSequence) { - return create(OperationOnErrorResumeNextViaObservable.onErrorResumeNextViaObservable(that, resumeSequence)); - } - - /** - * Instruct an Observable to emit a particular item to its Observer's {@code onNext} - * function rather than invoking {@link Observer#onError onError} if it encounters an error. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its {@link Observer}, the Observable invokes its Observer's - * {@code onError} method, and then quits without invoking any more of its Observer's - * methods. The {@code onErrorReturn} method changes this behavior. If you pass a function - * ({@code resumeFunction}) to {@code onErrorReturn}, if the source Observable - * encounters an error, instead of invoking its Observer's {@code onError} method, it will - * instead pass the return value of {@code resumeFunction} to the Observer's - * {@link Observer#onNext onNext} method. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param that - * the source Observable - * @param resumeFunction - * a function that returns an item that will be passed into an {@link Observer}'s - * {@link Observer#onNext onNext} method if the Observable encounters an error that - * would otherwise cause it to invoke {@link Observer#onError onError} - * @return an Observable, identical to the source Observable with its behavior modified as described - */ - public static Observable onErrorReturn(final Observable that, Func1 resumeFunction) { - return create(OperationOnErrorReturn.onErrorReturn(that, resumeFunction)); - } - - /** - * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error of type {@link java.lang.Exception}. - *

- * This differs from {@link #onErrorResumeNext} in that this one does not handle {@link java.lang.Throwable} or {@link java.lang.Error} but lets those continue through. - *

- * - *

- * By default, when an Observable encounters an error that prevents it from emitting the - * expected item to its Observer, the Observable invokes its {@link Observer}'s {@code onError} method, and then quits without invoking any more of its Observer's - * methods. The {@code onErrorResumeNext} method changes this behavior. If you pass an - * Observable ({@code resumeSequence}) to {@code onErrorResumeNext}, if the original - * Observable encounters an error, instead of invoking its Observer's onError - * method, it will instead relinquish control to this new Observable, which will invoke the - * Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, - * because no Observable necessarily invokes {@code onError}, the Observer may never know - * that an error happened. - *

- * You can use this to prevent errors from propagating or to supply fallback data should errors - * be encountered. - * - * @param that - * the source Observable - * @param resumeSequence - * a Observable that will take over if the source Observable encounters an error - * @return an Observable, identical to the source Observable with its behavior modified as described - */ - public static Observable onExceptionResumeNext(final Observable that, final Observable resumeSequence) { - return create(OperationOnExceptionResumeNextViaObservable.onExceptionResumeNextViaObservable(that, resumeSequence)); - } - - /** - * Returns a {@link ConnectableObservable} that shares a single subscription to the underlying - * Observable that will replay all of its items and notifications to any future - * {@link Observer}. - *

- * - * @param that - * the source Observable - * @return a {@link ConnectableObservable} that upon connection causes the source Observable to - * emit items to its {@link Observer}s - */ - public static ConnectableObservable replay(final Observable that) { - return OperationMulticast.multicast(that, ReplaySubject. create()); - } - - /** - * This method has similar behavior to {@link #replay} except that this auto-subscribes to - * the source Observable rather than returning a {@link ConnectableObservable}. - *

- * - *

- * This is useful when you want an Observable to cache responses and you can't control the - * subscribe/unsubscribe behavior of all the {@link Observer}s. - *

- * NOTE: You sacrifice the ability to unsubscribe from the origin when you use the - * cache() operator so be careful not to use this operator on Observables that - * emit an infinite or very large number of items that will use up memory. - * - * @return an Observable that when first subscribed to, caches all of the items and - * notifications it emits so it can replay them for subsequent subscribers. - */ - public static Observable cache(final Observable that) { - return create(OperationCache.cache(that)); - } - - /** - * Returns a {@link ConnectableObservable}, which waits until its - * {@link ConnectableObservable#connect} method is called before it begins emitting items to - * those {@link Observer}s that have subscribed to it. - *

- * - * - * @param that - * the source Observable - * @return a {@link ConnectableObservable} that upon connection causes the source Observable to - * emit items to its {@link Observer} - */ - public static ConnectableObservable publish(final Observable that) { - return OperationMulticast.multicast(that, PublishSubject. create()); - } - - /** - * Returns an Observable that applies a function of your choosing to the first item emitted by a - * source Observable, then feeds the result of that function along with the second item emitted - * by the source Observable into the same function, and so on until all items have been emitted - * by the source Observable, and emits the final result from the final call to your function as - * its sole item. - *

- * - *

- * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," - * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, - * has an {@code inject} method that does a similar operation on lists. - * - * @param - * the type of item emitted by the source Observable - * @param sequence - * the source Observable - * @param accumulator - * an accumulator function to be invoked on each item emitted by the source - * Observable, the result of which will be used in the next accumulator call - * @return an Observable that emits a single item that is the result of applying the - * accumulator function to the sequence of items emitted by the source Observable - * @see MSDN: Observable.Aggregate - * @see Wikipedia: Fold (higher-order function) - */ - public static Observable reduce(Observable sequence, Func2 accumulator) { - return takeLast(create(OperationScan.scan(sequence, accumulator)), 1); - } - - /** - *

- * - * - * @see #reduce(Observable, Func2) - */ - public static Observable aggregate(Observable sequence, Func2 accumulator) { - return reduce(sequence, accumulator); - } - - /** - * Returns an Observable that applies a function of your choosing to the first item emitted by a - * source Observable, then feeds the result of that function along with the second item emitted - * by the source Observable into the same function, and so on until all items have been emitted - * by the source Observable, emitting the final result from the final call to your function as - * its sole item. - *

- * - *

- * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," - * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, - * has an {@code inject} method that does a similar operation on lists. - * - * @param - * the type of item emitted by the source Observable - * @param - * the type returned by the accumulator function, and the type of the seed - * @param sequence - * the source Observable - * @param initialValue - * a seed to pass in to the first execution of the accumulator function - * @param accumulator - * an accumulator function to be invoked on each item emitted by the source - * Observable, the result of which will be used in the next accumulator call - * @return an Observable that emits a single item that is the result of applying the - * accumulator function to the sequence of items emitted by the source Observable - * @see MSDN: Observable.Aggregate - * @see Wikipedia: Fold (higher-order function) - */ - public static Observable reduce(Observable sequence, R initialValue, Func2 accumulator) { - return takeLast(create(OperationScan.scan(sequence, initialValue, accumulator)), 1); - } - - /** - *

- * - * - * @see #reduce(Observable, Object, Func2) - */ - public static Observable aggregate(Observable sequence, R initialValue, Func2 accumulator) { - return reduce(sequence, initialValue, accumulator); - } - - /** - * Returns an Observable that applies a function of your choosing to the first item emitted by a - * source Observable, then feeds the result of that function along with the second item emitted - * by the source Observable into the same function, and so on until all items have been emitted - * by the source Observable, emitting the result of each of these iterations. - *

- * - * - * @param - * the type of item emitted by the source Observable - * @param sequence - * the source Observable - * @param accumulator - * an accumulator function to be invoked on each item emitted by the source - * Observable, the result of which will be emitted and used in the next accumulator - * call - * @return an Observable that emits items that are the result of accumulating the items from - * the source Observable - * @see MSDN: Observable.Scan - */ - public static Observable scan(Observable sequence, Func2 accumulator) { - return create(OperationScan.scan(sequence, accumulator)); - } - - /** - * Returns an Observable that applies a function of your choosing to the first item emitted by a - * source Observable, then feeds the result of that function along with the second item emitted - * by the source Observable into the same function, and so on until all items have been emitted - * by the source Observable, emitting the result of each of these iterations. - *

- * - *

- * Note that when you pass a seed to {@code scan()}, that seed will be the first item - * emitted by the resulting Observable. - * - * @param - * the type of item emitted by the source Observable - * @param - * the type returned by the accumulator function, and the type of the seed - * @param sequence - * the source Observable - * @param initialValue - * the initial (seed) accumulator value - * @param accumulator - * an accumulator function to be invoked on each item emitted by the source - * Observable, the result of which will be emitted and used in the next accumulator - * call - * @return an Observable that emits items that are the result of accumulating the items emitted - * by the source Observable - * @see MSDN: Observable.Scan - */ - public static Observable scan(Observable sequence, R initialValue, Func2 accumulator) { - return create(OperationScan.scan(sequence, initialValue, accumulator)); - } - - /** - * source Observable satisfy a condition. - *

- * - * - * @param sequence - * an Observable whose emitted items you are evaluating - * @param predicate - * a function that evaluates each emitted item and returns a Boolean - * @param - * the type of items emitted by the source Observable - * @return an Observable that emits {@code true} if all of the items emitted by the source - * Observable satisfy the predicate; otherwise, {@code false} - */ - public static Observable all(final Observable sequence, final Func1 predicate) { - return create(OperationAll.all(sequence, predicate)); - } - - /** - * Observable and emits the remaining items. + * Returns an Observable that never sends any items or notifications to an {@link Observer}. *

- * + * *

- * You can ignore the first {@code num} items emitted by an Observable and attend only to - * those items that come after, by modifying the Observable with the {@code skip} method. - * - * @param items - * the source Observable - * @param num - * the number of items to skip - * @return an Observable that emits the same items emitted by the source Observable, except for - * the first {@code num} items - * @see MSDN: Observable.Skip Method + * This Observable is useful primarily for testing purposes. + * + * @param + * the type of items (not) emitted by the Observable + * @return an Observable that never sends any items or notifications to an {@link Observer} */ - public static Observable skip(final Observable items, int num) { - return create(OperationSkip.skip(items, num)); + public static Observable never() { + return new NeverObservable(); } /** @@ -1684,30 +831,47 @@ public static Observable skip(final Observable items, int num) { * emits the items emitted by the most recently published of those Observables. *

* - * + * * @param sequenceOfSequences * the source Observable that emits Observables * @return an Observable that emits only the items emitted by the most recently published * Observable */ public static Observable switchDo(Observable> sequenceOfSequences) { + // TODO should this static remain? I have left it because it is an Observable return create(OperationSwitch.switchDo(sequenceOfSequences)); } + /** + * Given an Observable that emits Observables, creates a single Observable that + * emits the items emitted by the most recently published of those Observables. + *

+ * + * + * @param sequenceOfSequences + * the source Observable that emits Observables + * @return an Observable that emits only the items emitted by the most recently published + * Observable + * @throws ClassCastException + * if sequence not of type {@code Observable} + */ + @SuppressWarnings("unchecked") + public Observable switchDo() { + // TODO can we come up with a better name than this? It should be 'switch' but that is reserved. + // Perhaps 'switchOnNext'? + return create(OperationSwitch.switchDo((Observable>) this)); + } + /** * Accepts an Observable and wraps it in another Observable that ensures that the resulting * Observable is chronologically well-behaved. *

* *

- * A well-behaved Observable does not interleave its invocations of the - * {@link Observer#onNext onNext}, {@link Observer#onCompleted onCompleted}, and - * {@link Observer#onError onError} methods of its {@link Observer}s; it invokes - * {@code onCompleted} or {@code onError} only once; and it never invokes - * {@code onNext} after invoking either {@code onCompleted} or {@code onError}. - * {@code synchronize} enforces this, and the Observable it returns invokes - * {@code onNext} and {@code onCompleted} or {@code onError} synchronously. - * + * A well-behaved Observable does not interleave its invocations of the {@link Observer#onNext onNext}, {@link Observer#onCompleted onCompleted}, and {@link Observer#onError onError} methods of + * its {@link Observer}s; it invokes {@code onCompleted} or {@code onError} only once; and it never invokes {@code onNext} after invoking either {@code onCompleted} or {@code onError}. + * {@code synchronize} enforces this, and the Observable it returns invokes {@code onNext} and {@code onCompleted} or {@code onError} synchronously. + * * @param observable * the source Observable * @param @@ -1719,177 +883,17 @@ public static Observable synchronize(Observable observable) { return create(OperationSynchronize.synchronize(observable)); } - /** - * Returns an Observable that emits the first {@code num} items emitted by the source - * Observable. - *

- * - *

- * This method returns an Observable that will invoke a subscribing {@link Observer}'s - * {@link Observer#onNext onNext} method a maximum of {@code num} times before invoking - * {@link Observer#onCompleted onCompleted}. - * - * @param items - * the source Observable - * @param num - * the number of items to emit from the start of the sequence emitted by the source - * Observable - * @return an Observable that emits only the first {@code num} items emitted by the source - * Observable - */ - public static Observable take(final Observable items, final int num) { - return create(OperationTake.take(items, num)); - } - - /** - * Returns an Observable that emits the last {@code count} items emitted by the source - * Observable. - *

- * - * - * @param items - * the source Observable - * @param count - * the number of items to emit from the end of the sequence emitted by the source - * Observable - * @return an Observable that emits only the last count items emitted by the source - * Observable - */ - public static Observable takeLast(final Observable items, final int count) { - return create(OperationTakeLast.takeLast(items, count)); - } - - /** - * Returns an Observable that emits the items emitted by a source Observable so long as a given - * predicate, operating on the items emitted, remains true. - *

- * - * - * @param items - * the source Observable - * @param predicate - * a function to test each item emitted by the source Observable for a condition - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return {@code true} for each item, then completes - */ - public static Observable takeWhile(final Observable items, Func1 predicate) { - return create(OperationTakeWhile.takeWhile(items, predicate)); - } - - /** - * Returns an Observable that emits the items emitted by a source Observable so long as a given - * predicate remains true, where the predicate can operate on both the item and its index - * relative to the complete sequence. - *

- * - * - * @param items - * the source Observable - * @param predicate - * a function to test each item emitted by the source Observable for a condition; - * the second parameter of the function represents the index of the source item - * @return an Observable that emits items from the source Observable so long as the predicate - * continues to return {@code true} for each item, then completes - */ - public static Observable takeWhileWithIndex(final Observable items, Func2 predicate) { - return create(OperationTakeWhile.takeWhileWithIndex(items, predicate)); - } - /** * Wraps each item emitted by a source Observable in a {@link Timestamped} object. *

* - * + * * @return an Observable that emits timestamped items from the source Observable */ public Observable> timestamp() { return create(OperationTimestamp.timestamp(this)); } - /** - * Returns an Observable that emits a single item, a list composed of all the items emitted by - * the source Observable. - *

- * - *

- * Normally, an Observable that emits multiple items will do so by invoking its - * {@link Observer}'s {@link Observer#onNext onNext} method once for each such item. {@code toList} - * allows you can change this behavior, instructing the Observable to compose a List of all of the - * items and then invoke the Observer's {@code onNext} function once, passing the entire list. - *

- * Be careful not to use this operator on Observables that emit an infinite or very large - * number of items, as all items will be held in memory and you do not have the option to - * unsubscribe. - * - * @param that - * the source Observable - * @return an Observable that emits a single item: a {@code List} containing all of the - * items emitted by the source Observable - */ - public static Observable> toList(final Observable that) { - return create(OperationToObservableList.toObservableList(that)); - } - - /** - * Returns a {@link ConnectableObservable} that upon connection causes the source Observable to - * emit items into the specified {@link Subject}. - * - * @param source - * the source Observable whose emitted items will be pushed into the specified - * {@link Subject} - * @param subject - * the {@link Subject} to push source items into - * @param - * the type of items emitted by the source Observable - * @param - * the type of the {@link Subject} - * @return a {@link ConnectableObservable} that upon connection causes the source Observable to - * push items into the specified {@link Subject} - */ - public static ConnectableObservable multicast(Observable source, final Subject subject) { - return OperationMulticast.multicast(source, subject); - } - - /** - * Converts an {@link Iterable} sequence into an Observable. - *

- * - *

- * You can convert any object that supports the Iterable interface into an Observable that - * emits each item in the Iterable, by passing the Iterable into the toObservable - * method. - * - * @param iterable - * the source {@link Iterable} sequence - * @param - * the type of items in the {@link Iterable} sequence and the type of items to be - * emitted by the resulting Observable - * @return an Observable that emits each item in the source {@link Iterable} sequence - */ - public static Observable toObservable(Iterable iterable) { - return create(OperationToObservableIterable.toObservableIterable(iterable)); - } - - /** - * Converts a {@link Future} into an Observable. - * - *

- * - *

- * Important note: This Observable is blocking; you cannot unsubscribe from it. - * - * @param future - * the source {@link Future} - * @param - * the type of of object that the {@link Future} returns, and also the type of the - * item emitted by the resulting Observable - * @return an Observable that emits the item from the source {@link Future} - * @deprecated Replaced by {@link #from(Future)} - */ - public static Observable toObservable(Future future) { - return create(OperationToObservableFuture.toObservableFuture(future)); - } - /** * Converts a {@link Future} into an Observable. *

@@ -1900,7 +904,7 @@ public static Observable toObservable(Future future) { * object into the {@code from} method. *

* Important note: This Observable is blocking; you cannot unsubscribe from it. - * + * * @param future * the source {@link Future} * @param @@ -1913,24 +917,26 @@ public static Observable from(Future future) { } /** - * Converts a {@link Future} into an Observable with timeout. + * Converts a {@link Future} into an Observable. *

- * Important note: This Observable is blocking; you cannot unsubscribe from it. - * + * + *

+ * You can convert any object that supports the {@link Future} interface into an Observable that + * emits the return value of the {@link Future#get} method of that object, by passing the + * object into the {@code from} method. + *

+ * * @param future * the source {@link Future} - * @param timeout - * the maximum time to wait - * @param unit - * the {@link TimeUnit} of the time argument + * @param scheduler + * the {@link Scheduler} to wait for the Future on. Use a Scheduler such as {@link Schedulers#threadPoolForIO()} that can block and wait on the future. * @param * the type of object that the {@link Future} returns, and also the type of item to * be emitted by the resulting Observable - * @return an Observable that emits the item from the source {@link Future} - * @deprecated Replaced by {@link #from(Future, long, TimeUnit)} + * @return an Observable that emits the item from the source Future */ - public static Observable toObservable(Future future, long timeout, TimeUnit unit) { - return create(OperationToObservableFuture.toObservableFuture(future, timeout, unit)); + public static Observable from(Future future, Scheduler scheduler) { + return create(OperationToObservableFuture.toObservableFuture(future)).subscribeOn(scheduler); } /** @@ -1943,7 +949,7 @@ public static Observable toObservable(Future future, long timeout, Tim * object into the {@code from} method. *

* Important note: This Observable is blocking; you cannot unsubscribe from it. - * + * * @param future * the source {@link Future} * @param timeout @@ -1959,70 +965,16 @@ public static Observable from(Future future, long timeout, TimeUnit un return create(OperationToObservableFuture.toObservableFuture(future, timeout, unit)); } - /** - * Converts an array sequence into an Observable. - * - * @param items - * the source array - * @param - * the type of items in the array, and also the type of items emitted by the - * resulting Observable - * @return an Observable that emits each item in the source array - * @deprecated Use {@link #from(Object...)} - */ - public static Observable toObservable(T... items) { - return toObservable(Arrays.asList(items)); - } - - /** - * Return an Observable that emits a single list of the items emitted by the source Observable, in sorted - * order (each item emitted by the source Observable must implement {@link Comparable} with - * respect to all other items emitted by the source Observable). - *

- * - * - * @param sequence - * the source Observable - * @throws ClassCastException - * if any emitted item does not implement {@link Comparable} with respect to all - * other emitted items - * @return an Observable that emits a single,sorted list of the items from the source Observable - */ - public static Observable> toSortedList(Observable sequence) { - return create(OperationToObservableSortedList.toSortedList(sequence)); - } - - /** - * Return an Observable that emits a single list of the items emitted by the source Observable, sorted - * by the given comparison function. - *

- * - * - * @param sequence - * the source Observable - * @param sortFunction - * a function that compares two items emitted by the source Observable and returns - * an Integer that indicates their sort order - * @return an Observable that emits a single, sorted list of the items from the source Observable - */ - public static Observable> toSortedList(Observable sequence, Func2 sortFunction) { - return create(OperationToObservableSortedList.toSortedList(sequence, sortFunction)); - } - /** *

* + *

{@code zip} applies this function in strict sequence, so the first item emitted by the + * new Observable will be the result of the function applied to the first item emitted by {@code w0} and the first item emitted by {@code w1}; the second item emitted by + * the new Observable will be the result of the function applied to the second item emitted by {@code w0} and the second item emitted by {@code w1}; and so forth. *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * {@code w0} and the first item emitted by {@code w1}; the second item emitted by - * the new Observable will be the result of the function applied to the second item emitted by - * {@code w0} and the second item emitted by {@code w1}; and so forth. - *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations * of the source Observable that emits the fewest items. - * + * * @param w0 * one source Observable * @param w1 @@ -2042,7 +994,7 @@ public static Observable zip(Observable w0, Observable w1 * emitted by two source Observables are equal. *

* - * + * * @param first * one Observable to compare * @param second @@ -2067,7 +1019,7 @@ public Boolean call(T first, T second) { * function. *

* - * + * * @param first * one Observable to compare * @param second @@ -2088,18 +1040,14 @@ public static Observable sequenceEqual(Observable first, Observa * combinations of three items emitted, in sequence, by three other Observables. *

* + *

{@code zip} applies this function in strict sequence, so the first item emitted by the + * new Observable will be the result of the function applied to the first item emitted by {@code w0}, the first item emitted by {@code w1}, and the first item emitted by {@code w2}; the second + * item emitted by the new Observable will be the result of the + * function applied to the second item emitted by {@code w0}, the second item emitted by {@code w1}, and the second item emitted by {@code w2}; and so forth. *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * {@code w0}, the first item emitted by {@code w1}, and the first item emitted by - * {@code w2}; the second item emitted by the new Observable will be the result of the - * function applied to the second item emitted by {@code w0}, the second item emitted by - * {@code w1}, and the second item emitted by {@code w2}; and so forth. - *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations * of the source Observable that emits the fewest items. - * + * * @param w0 * one source Observable * @param w1 @@ -2120,18 +1068,15 @@ public static Observable zip(Observable w0, Observable * - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the - * new Observable will be the result of the function applied to the first item emitted by - * {@code w0}, the first item emitted by {@code w1}, the first item emitted by - * {@code w2}, and the first item emitted by {@code w3}; the second item emitted by + *

{@code zip} applies this function in strict sequence, so the first item emitted by the + * new Observable will be the result of the function applied to the first item emitted by {@code w0}, the first item emitted by {@code w1}, the first item emitted by {@code w2}, and the first item + * emitted by {@code w3}; the second item emitted by * the new Observable will be the result of the function applied to the second item emitted by * each of those Observables; and so forth. *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations + * The resulting {@code Observable} returned from {@code zip} will invoke {@link Observer#onNext onNext} as many times as the number of {@code onNext} invocations * of the source Observable that emits the fewest items. - * + * * @param w0 * one source Observable * @param w1 @@ -2151,33 +1096,31 @@ public static Observable zip(Observable w0, Observabl /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces connected non-overlapping buffers. The current buffer is - * emitted and replaced with a new buffer when the Observable produced by the specified - * {@link Func0} produces a {@link BufferClosing} object. The * {@link Func0} will then + * emitted and replaced with a new buffer when the Observable produced by the specified {@link Func0} produces a {@link BufferClosing} object. The * {@link Func0} will then * be used to create a new Observable to listen for the end of the next buffer. - * + * * @param bufferClosingSelector * The {@link Func0} which is used to produce an {@link Observable} for every buffer created. * When this {@link Observable} produces a {@link BufferClosing} object, the associated buffer * is emitted and replaced with a new one. * @return - * An {@link Observable} which produces connected non-overlapping buffers, which are emitted - * when the current {@link Observable} created with the {@link Func0} argument produces a - * {@link BufferClosing} object. + * An {@link Observable} which produces connected non-overlapping buffers, which are emitted + * when the current {@link Observable} created with the {@link Func0} argument produces a {@link BufferClosing} object. */ public Observable> buffer(Func0> bufferClosingSelector) { - return buffer(this, bufferClosingSelector); + return create(OperationBuffer.buffer(this, bufferClosingSelector)); } /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces buffers. Buffers are created when the specified "bufferOpenings" * Observable produces a {@link BufferOpening} object. Additionally the {@link Func0} argument * is used to create an Observable which produces {@link BufferClosing} objects. When this * Observable produces such an object, the associated buffer is emitted. - * + * * @param bufferOpenings * The {@link Observable} which, when it produces a {@link BufferOpening} object, will cause * another buffer to be created. @@ -2186,76 +1129,75 @@ public Observable> buffer(Func0> bufferClosing * When this {@link Observable} produces a {@link BufferClosing} object, the associated buffer * is emitted. * @return - * An {@link Observable} which produces buffers which are created and emitted when the specified - * {@link Observable}s publish certain objects. + * An {@link Observable} which produces buffers which are created and emitted when the specified {@link Observable}s publish certain objects. */ public Observable> buffer(Observable bufferOpenings, Func1> bufferClosingSelector) { - return buffer(this, bufferOpenings, bufferClosingSelector); + return create(OperationBuffer.buffer(this, bufferOpenings, bufferClosingSelector)); } /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces connected non-overlapping buffers, each containing "count" * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. - * + * * @param count * The maximum size of each buffer before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping buffers containing at most - * "count" produced values. + * An {@link Observable} which produces connected non-overlapping buffers containing at most + * "count" produced values. */ public Observable> buffer(int count) { - return buffer(this, count); + return create(OperationBuffer.buffer(this, count)); } /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces buffers every "skip" values, each containing "count" * elements. When the source Observable completes or encounters an error, the current * buffer is emitted, and the event is propagated. - * + * * @param count * The maximum size of each buffer before it should be emitted. * @param skip * How many produced values need to be skipped before starting a new buffer. Note that when "skip" and * "count" are equals that this is the same operation as {@link Observable#buffer(Observable, int)}. * @return - * An {@link Observable} which produces buffers every "skipped" values containing at most - * "count" produced values. + * An {@link Observable} which produces buffers every "skipped" values containing at most + * "count" produced values. */ public Observable> buffer(int count, int skip) { - return buffer(this, count, skip); + return create(OperationBuffer.buffer(this, count, skip)); } /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces connected non-overlapping buffers, each of a fixed duration * specified by the "timespan" argument. When the source Observable completes or encounters * an error, the current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. * @param unit * The unit of time which applies to the "timespan" argument. * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. + * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. */ public Observable> buffer(long timespan, TimeUnit unit) { - return buffer(this, timespan, unit); + return create(OperationBuffer.buffer(this, timespan, unit)); } /** * Creates an Observable which produces buffers of collected values. - * + * *

This Observable produces connected non-overlapping buffers, each of a fixed duration * specified by the "timespan" argument. When the source Observable completes or encounters * an error, the current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. @@ -2264,10 +1206,10 @@ public Observable> buffer(long timespan, TimeUnit unit) { * @param scheduler * The {@link Scheduler} to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. + * An {@link Observable} which produces connected non-overlapping buffers with a fixed duration. */ public Observable> buffer(long timespan, TimeUnit unit, Scheduler scheduler) { - return buffer(this, timespan, unit, scheduler); + return create(OperationBuffer.buffer(this, timespan, unit, scheduler)); } /** @@ -2275,7 +1217,7 @@ public Observable> buffer(long timespan, TimeUnit unit, Scheduler schedu * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. @@ -2284,11 +1226,11 @@ public Observable> buffer(long timespan, TimeUnit unit, Scheduler schedu * @param count * The maximum size of each buffer before it should be emitted. * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after - * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). + * An {@link Observable} which produces connected non-overlapping buffers which are emitted after + * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). */ public Observable> buffer(long timespan, TimeUnit unit, int count) { - return buffer(this, timespan, unit, count); + return create(OperationBuffer.buffer(this, timespan, unit, count)); } /** @@ -2296,7 +1238,7 @@ public Observable> buffer(long timespan, TimeUnit unit, int count) { * non-overlapping buffers, each of a fixed duration specified by the "timespan" argument or a maximum size * specified by the "count" argument (which ever is reached first). When the source Observable completes * or encounters an error, the current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted, and * replaced with a new buffer. @@ -2307,11 +1249,11 @@ public Observable> buffer(long timespan, TimeUnit unit, int count) { * @param scheduler * The {@link Scheduler} to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces connected non-overlapping buffers which are emitted after - * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). + * An {@link Observable} which produces connected non-overlapping buffers which are emitted after + * a fixed duration or when the buffer has reached maximum capacity (which ever occurs first). */ public Observable> buffer(long timespan, TimeUnit unit, int count, Scheduler scheduler) { - return buffer(this, timespan, unit, count, scheduler); + return create(OperationBuffer.buffer(this, timespan, unit, count, scheduler)); } /** @@ -2319,7 +1261,7 @@ public Observable> buffer(long timespan, TimeUnit unit, int count, Sched * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan * specified by the "timespan" argument. When the source Observable completes or encounters an error, the * current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted. * @param timeshift @@ -2327,11 +1269,11 @@ public Observable> buffer(long timespan, TimeUnit unit, int count, Sched * @param unit * The unit of time which applies to the "timespan" and "timeshift" argument. * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after - * a fixed timespan has elapsed. + * An {@link Observable} which produces new buffers periodically, and these are emitted after + * a fixed timespan has elapsed. */ public Observable> buffer(long timespan, long timeshift, TimeUnit unit) { - return buffer(this, timespan, timeshift, unit); + return create(OperationBuffer.buffer(this, timespan, timeshift, unit)); } /** @@ -2339,7 +1281,7 @@ public Observable> buffer(long timespan, long timeshift, TimeUnit unit) * periodically, which is determined by the "timeshift" argument. Each buffer is emitted after a fixed timespan * specified by the "timespan" argument. When the source Observable completes or encounters an error, the * current buffer is emitted and the event is propagated. - * + * * @param timespan * The period of time each buffer is collecting values before it should be emitted. * @param timeshift @@ -2349,28 +1291,26 @@ public Observable> buffer(long timespan, long timeshift, TimeUnit unit) * @param scheduler * The {@link Scheduler} to use when determining the end and start of a buffer. * @return - * An {@link Observable} which produces new buffers periodically, and these are emitted after - * a fixed timespan has elapsed. + * An {@link Observable} which produces new buffers periodically, and these are emitted after + * a fixed timespan has elapsed. */ public Observable> buffer(long timespan, long timeshift, TimeUnit unit, Scheduler scheduler) { - return buffer(this, timespan, timeshift, unit, scheduler); + return create(OperationBuffer.buffer(this, timespan, timeshift, unit, scheduler)); } /** * Returns an Observable that emits the results of a function of your choosing applied to * combinations of four items emitted, in sequence, by four other Observables. - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the + *

{@code zip} applies this function in strict sequence, so the first item emitted by the * new Observable will be the result of the function applied to the first item emitted by * all of the Observalbes; the second item emitted by the new Observable will be the result of * the function applied to the second item emitted by each of those Observables; and so forth. *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@code onNext} as many times as the number of {@code onNext} invokations of the + * The resulting {@code Observable} returned from {@code zip} will invoke {@code onNext} as many times as the number of {@code onNext} invokations of the * source Observable that emits the fewest items. *

* - * + * * @param ws * An Observable of source Observables * @param reduceFunction @@ -2390,18 +1330,16 @@ public Observable call(List> wsList) { /** * Returns an Observable that emits the results of a function of your choosing applied to * combinations of four items emitted, in sequence, by four other Observables. - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the + *

{@code zip} applies this function in strict sequence, so the first item emitted by the * new Observable will be the result of the function applied to the first item emitted by * all of the Observalbes; the second item emitted by the new Observable will be the result of * the function applied to the second item emitted by each of those Observables; and so forth. *

- * The resulting {@code Observable} returned from {@code zip} will invoke - * {@code onNext} as many times as the number of {@code onNext} invokations of the + * The resulting {@code Observable} returned from {@code zip} will invoke {@code onNext} as many times as the number of {@code onNext} invokations of the * source Observable that emits the fewest items. *

* - * + * * @param ws * A collection of source Observables * @param reduceFunction @@ -2413,30 +1351,27 @@ public static Observable zip(Collection> ws, FuncN reduc return create(OperationZip.zip(ws, reduceFunction)); } - /** + /** *

* - * + * * @param predicate - * a function that evaluates the items emitted by the source Observable, returning - * {@code true} if they pass the filter + * a function that evaluates the items emitted by the source Observable, returning {@code true} if they pass the filter * @return an Observable that emits only those items in the original Observable that the filter * evaluates as {@code true} */ public Observable filter(Func1 predicate) { - return filter(this, predicate); + return create(OperationFilter.filter(this, predicate)); } /** - * Registers an {@link Action0} to be called when this Observable invokes - * {@link Observer#onCompleted onCompleted} or {@link Observer#onError onError}. + * Registers an {@link Action0} to be called when this Observable invokes {@link Observer#onCompleted onCompleted} or {@link Observer#onError onError}. *

* - * + * * @param action * an {@link Action0} to be invoked when the source Observable finishes - * @return an Observable that emits the same items as the source Observable, then invokes the - * {@link Action0} + * @return an Observable that emits the same items as the source Observable, then invokes the {@link Action0} * @see MSDN: Observable.Finally Method */ public Observable finallyDo(Action0 action) { @@ -2451,7 +1386,7 @@ public Observable finallyDo(Action0 action) { * *

* Note: {@code mapMany} and {@code flatMap} are equivalent. - * + * * @param func * a function that, when applied to an item emitted by the source Observable, returns * an Observable @@ -2467,16 +1402,15 @@ public Observable flatMap(Func1> func) { /** *

* - * + * * @param predicate - * a function that evaluates an item emitted by the source Observable, returning - * {@code true} if it passes the filter + * a function that evaluates an item emitted by the source Observable, returning {@code true} if it passes the filter * @return an Observable that emits only those items in the original Observable that the filter * evaluates as {@code true} * @see #filter(Func1) */ public Observable where(Func1 predicate) { - return where(this, predicate); + return filter(predicate); } /** @@ -2484,14 +1418,14 @@ public Observable where(Func1 predicate) { * Observable and emits the result. *

* - * + * * @param func * a function to apply to each item emitted by the Observable * @return an Observable that emits the items from the source Observable, transformed by the * given function */ public Observable map(Func1 func) { - return map(this, func); + return create(OperationMap.map(this, func)); } /** @@ -2502,7 +1436,7 @@ public Observable map(Func1 func) { * *

* Note: mapMany and flatMap are equivalent. - * + * * @param func * a function that, when applied to an item emitted by the source Observable, returns * an Observable @@ -2512,50 +1446,48 @@ public Observable map(Func1 func) { * @see #flatMap(Func1) */ public Observable mapMany(Func1> func) { - return mapMany(this, func); + return create(OperationMap.mapMany(this, func)); } /** - * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} - * emissions, and marks them with their original notification types within {@link Notification} - * objects. + * Turns all of the notifications from a source Observable into {@link Observer#onNext onNext} emissions, and marks them with their original notification types within {@link Notification} objects. *

* - * + * * @return an Observable whose items are the result of materializing the items and * notifications of the source Observable * @see MSDN: Observable.materialize */ public Observable> materialize() { - return materialize(this); + return create(OperationMaterialize.materialize(this)); } /** * Asynchronously subscribes and unsubscribes Observers on the specified {@link Scheduler}. *

* - * + * * @param scheduler * the {@link Scheduler} to perform subscription and unsubscription actions on * @return the source Observable modified so that its subscriptions and unsubscriptions happen * on the specified {@link Scheduler} */ public Observable subscribeOn(Scheduler scheduler) { - return subscribeOn(this, scheduler); + return create(OperationSubscribeOn.subscribeOn(this, scheduler)); } /** * Asynchronously notify {@link Observer}s on the specified {@link Scheduler}. *

* - * + * * @param scheduler * the {@link Scheduler} to notify {@link Observer}s on * @return the source Observable modified so that its {@link Observer}s are notified on the * specified {@link Scheduler} */ public Observable observeOn(Scheduler scheduler) { - return observeOn(this, scheduler); + return create(OperationObserveOn.observeOn(this, scheduler)); } /** @@ -2564,21 +1496,19 @@ public Observable observeOn(Scheduler scheduler) { * or notifications they represent. *

* - * - * @return an Observable that emits the items and notifications embedded in the - * {@link Notification} objects emitted by the source Observable + * + * @return an Observable that emits the items and notifications embedded in the {@link Notification} objects emitted by the source Observable * @see MSDN: Observable.dematerialize * @throws Throwable * if the source Observable is not of type {@code Observable>}. */ @SuppressWarnings("unchecked") public Observable dematerialize() { - return dematerialize((Observable>) this); + return create(OperationDematerialize.dematerialize((Observable>) this)); } /** - * Instruct an Observable to pass control to another Observable rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error. *

* *

@@ -2589,26 +1519,24 @@ public Observable dematerialize() { * function that returns an Observable (resumeFunction) to * onErrorResumeNext, if the original Observable encounters an error, instead of * invoking its Observer's onError method, it will instead relinquish control to - * the Observable returned from resumeFunction, which will invoke the Observer's - * {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no + * the Observable returned from resumeFunction, which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no * Observable necessarily invokes onError, the Observer may never know that an * error happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. - * + * * @param resumeFunction * a function that returns an Observable that will take over if the source Observable * encounters an error * @return the original Observable, with appropriately modified behavior */ public Observable onErrorResumeNext(final Func1> resumeFunction) { - return onErrorResumeNext(this, resumeFunction); + return create(OperationOnErrorResumeNextViaFunction.onErrorResumeNextViaFunction(this, resumeFunction)); } /** - * Instruct an Observable to pass control to another Observable rather than invoking - * {@link Observer#onError onError} if it encounters an error. + * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error. *

* *

@@ -2619,26 +1547,24 @@ public Observable onErrorResumeNext(final Func1> res * another Observable (resumeSequence) to an Observable's * onErrorResumeNext method, if the original Observable encounters an error, * instead of invoking its Observer's onError method, it will instead relinquish - * control to resumeSequence which will invoke the Observer's - * {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no + * control to resumeSequence which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no * Observable necessarily invokes onError, the Observer may never know that an * error happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. - * + * * @param resumeSequence * a function that returns an Observable that will take over if the source Observable * encounters an error * @return the original Observable, with appropriately modified behavior */ public Observable onErrorResumeNext(final Observable resumeSequence) { - return onErrorResumeNext(this, resumeSequence); + return create(OperationOnErrorResumeNextViaObservable.onErrorResumeNextViaObservable(this, resumeSequence)); } - + /** - * Instruct an Observable to pass control to another Observable rather than invoking - * {@link Observer#onError onError} if it encounters an error of type {@link java.lang.Exception}. + * Instruct an Observable to pass control to another Observable rather than invoking {@link Observer#onError onError} if it encounters an error of type {@link java.lang.Exception}. *

* This differs from {@link #onErrorResumeNext} in that this one does not handle {@link java.lang.Throwable} or {@link java.lang.Error} but lets those continue through. *

@@ -2651,21 +1577,20 @@ public Observable onErrorResumeNext(final Observable resumeSequence) { * another Observable (resumeSequence) to an Observable's * onErrorResumeNext method, if the original Observable encounters an error, * instead of invoking its Observer's onError method, it will instead relinquish - * control to resumeSequence which will invoke the Observer's - * {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no + * control to resumeSequence which will invoke the Observer's {@link Observer#onNext onNext} method if it is able to do so. In such a case, because no * Observable necessarily invokes onError, the Observer may never know that an * error happened. *

* You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. - * + * * @param resumeSequence * a function that returns an Observable that will take over if the source Observable * encounters an error * @return the original Observable, with appropriately modified behavior */ public Observable onExceptionResumeNext(final Observable resumeSequence) { - return onExceptionResumeNext(this, resumeSequence); + return create(OperationOnExceptionResumeNextViaObservable.onExceptionResumeNextViaObservable(this, resumeSequence)); } /** @@ -2685,14 +1610,14 @@ public Observable onExceptionResumeNext(final Observable resumeSequence) { *

* You can use this to prevent errors from propagating or to supply fallback data should errors * be encountered. - * + * * @param resumeFunction * a function that returns an item that the new Observable will emit if the source * Observable encounters an error * @return the original Observable with appropriately modified behavior */ public Observable onErrorReturn(Func1 resumeFunction) { - return onErrorReturn(this, resumeFunction); + return create(OperationOnErrorReturn.onErrorReturn(this, resumeFunction)); } /** @@ -2707,7 +1632,7 @@ public Observable onErrorReturn(Func1 resumeFunction) { * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, * has an inject method that does a similar operation on lists. - * + * * @param accumulator * An accumulator function to be invoked on each item emitted by the source * Observable, whose result will be used in the next accumulator call @@ -2717,21 +1642,20 @@ public Observable onErrorReturn(Func1 resumeFunction) { * @see Wikipedia: Fold (higher-order function) */ public Observable reduce(Func2 accumulator) { - return reduce(this, accumulator); + return create(OperationScan.scan(this, accumulator)).takeLast(1); } /** * Returns a {@link ConnectableObservable} that shares a single subscription to the underlying - * Observable that will replay all of its items and notifications to any future - * {@link Observer}. + * Observable that will replay all of its items and notifications to any future {@link Observer}. *

* - * + * * @return a {@link ConnectableObservable} that upon connection causes the source Observable to * emit items to its {@link Observer}s */ public ConnectableObservable replay() { - return replay(this); + return OperationMulticast.multicast(this, ReplaySubject. create()); } /** @@ -2746,37 +1670,36 @@ public ConnectableObservable replay() { * NOTE: You sacrifice the ability to unsubscribe from the origin when you use the * cache() operator so be careful not to use this operator on Observables that * emit an infinite or very large number of items that will use up memory. - * + * * @return an Observable that when first subscribed to, caches all of its notifications for * the benefit of subsequent subscribers. */ public Observable cache() { - return cache(this); + return create(OperationCache.cache(this)); } /** - * Returns a {@link ConnectableObservable}, which waits until its - * {@link ConnectableObservable#connect connect} method is called before it begins emitting + * Returns a {@link ConnectableObservable}, which waits until its {@link ConnectableObservable#connect connect} method is called before it begins emitting * items to those {@link Observer}s that have subscribed to it. *

* - * + * * @return a {@link ConnectableObservable} that upon connection causes the source Observable to * emit items to its {@link Observer}s */ public ConnectableObservable publish() { - return publish(this); + return OperationMulticast.multicast(this, PublishSubject. create()); } /** * Synonymous with reduce(). *

* - * + * * @see #reduce(Func2) */ public Observable aggregate(Func2 accumulator) { - return aggregate(this, accumulator); + return reduce(accumulator); } /** @@ -2791,7 +1714,7 @@ public Observable aggregate(Func2 accumulator) { * This technique, which is called "reduce" or "aggregate" here, is sometimes called "fold," * "accumulate," "compress," or "inject" in other programming contexts. Groovy, for instance, * has an inject method that does a similar operation on lists. - * + * * @param initialValue * the initial (seed) accumulator value * @param accumulator @@ -2803,18 +1726,18 @@ public Observable aggregate(Func2 accumulator) { * @see Wikipedia: Fold (higher-order function) */ public Observable reduce(R initialValue, Func2 accumulator) { - return reduce(this, initialValue, accumulator); + return create(OperationScan.scan(this, initialValue, accumulator)).takeLast(1); } /** * Synonymous with reduce(). *

* - * + * * @see #reduce(Object, Func2) */ public Observable aggregate(R initialValue, Func2 accumulator) { - return aggregate(this, initialValue, accumulator); + return reduce(initialValue, accumulator); } /** @@ -2829,16 +1752,15 @@ public Observable aggregate(R initialValue, Func2 accumulator) { *

* Note that when you pass a seed to scan() the resulting Observable will emit * that seed as its first emitted item. - * + * * @param accumulator * an accumulator function to be invoked on each item emitted by the source - * Observable, whose result will be emitted to {@link Observer}s via - * {@link Observer#onNext onNext} and used in the next accumulator call. + * Observable, whose result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the next accumulator call. * @return an Observable that emits the results of each call to the accumulator function * @see MSDN: Observable.Scan */ public Observable scan(Func2 accumulator) { - return scan(this, accumulator); + return create(OperationScan.scan(this, accumulator)); } /** @@ -2846,7 +1768,7 @@ public Observable scan(Func2 accumulator) { * Observable at a specified time interval. *

* - * + * * @param period * the sampling rate * @param unit @@ -2863,7 +1785,7 @@ public Observable sample(long period, TimeUnit unit) { * Observable at a specified time interval. *

* - * + * * @param period * the sampling rate * @param unit @@ -2889,19 +1811,17 @@ public Observable sample(long period, TimeUnit unit, Scheduler scheduler) { *

* Note that when you pass a seed to scan() the resulting Observable will emit * that seed as its first emitted item. - * + * * @param initialValue * the initial (seed) accumulator value * @param accumulator * an accumulator function to be invoked on each item emitted by the source - * Observable, whose result will be emitted to {@link Observer}s via - * {@link Observer#onNext onNext} and used in the next accumulator call. + * Observable, whose result will be emitted to {@link Observer}s via {@link Observer#onNext onNext} and used in the next accumulator call. * @return an Observable that emits the results of each call to the accumulator function - * @see MSDN: - * Observable.Scan + * @see MSDN: Observable.Scan */ public Observable scan(R initialValue, Func2 accumulator) { - return scan(this, initialValue, accumulator); + return create(OperationScan.scan(this, initialValue, accumulator)); } /** @@ -2909,14 +1829,14 @@ public Observable scan(R initialValue, Func2 accumulator) { * the source Observable satisfy a condition. *

* - * + * * @param predicate * a function that evaluates an item and returns a Boolean * @return an Observable that emits true if all items emitted by the source * Observable satisfy the predicate; otherwise, false */ public Observable all(Func1 predicate) { - return all(this, predicate); + return create(OperationAll.all(this, predicate)); } /** @@ -2927,14 +1847,14 @@ public Observable all(Func1 predicate) { *

* You can ignore the first num items emitted by an Observable and attend only to * those items that come after, by modifying the Observable with the skip method. - * + * * @param num * the number of items to skip * @return an Observable that is identical to the source Observable except that it does not * emit the first num items that the source emits */ public Observable skip(int num) { - return skip(this, num); + return create(OperationSkip.skip(this, num)); } /** @@ -2943,10 +1863,9 @@ public Observable skip(int num) { *

* *

- * This method returns an Observable that will invoke a subscribing {@link Observer}'s - * {@link Observer#onNext onNext} function a maximum of num times before invoking + * This method returns an Observable that will invoke a subscribing {@link Observer}'s {@link Observer#onNext onNext} function a maximum of num times before invoking * {@link Observer#onCompleted onCompleted}. - * + * * @param num * the number of items to take * @return an Observable that emits only the first num items from the source @@ -2954,7 +1873,7 @@ public Observable skip(int num) { * fewer than num items */ public Observable take(final int num) { - return take(this, num); + return create(OperationTake.take(this, num)); } /** @@ -2962,7 +1881,7 @@ public Observable take(final int num) { * specified condition is true. *

* - * + * * @param predicate * a function that evaluates an item emitted by the source Observable and returns a * Boolean @@ -2970,7 +1889,7 @@ public Observable take(final int num) { * satisfies the condition defined by predicate */ public Observable takeWhile(final Func1 predicate) { - return takeWhile(this, predicate); + return create(OperationTakeWhile.takeWhile(this, predicate)); } /** @@ -2979,7 +1898,7 @@ public Observable takeWhile(final Func1 predicate) { * relative to the complete sequence. *

* - * + * * @param predicate * a function to test each item emitted by the source Observable for a condition; * the second parameter of the function represents the index of the source item @@ -2987,7 +1906,7 @@ public Observable takeWhile(final Func1 predicate) { * continues to return true for each item, then completes */ public Observable takeWhileWithIndex(final Func2 predicate) { - return takeWhileWithIndex(this, predicate); + return create(OperationTakeWhile.takeWhileWithIndex(this, predicate)); } /** @@ -2995,7 +1914,7 @@ public Observable takeWhileWithIndex(final Func2 predica * Observable. *

* - * + * * @param count * the number of items to emit from the end of the sequence emitted by the source * Observable @@ -3003,7 +1922,7 @@ public Observable takeWhileWithIndex(final Func2 predica * Observable */ public Observable takeLast(final int count) { - return takeLast(this, count); + return create(OperationTakeLast.takeLast(this, count)); } /** @@ -3011,7 +1930,7 @@ public Observable takeLast(final int count) { * other Observable emits an item. *

* - * + * * @param other * the Observable whose first emitted item will cause takeUntil to stop * emitting items from the source Observable @@ -3021,7 +1940,7 @@ public Observable takeLast(final int count) { * other emits its first item */ public Observable takeUntil(Observable other) { - return takeUntil(this, other); + return OperationTakeUntil.takeUntil(this, other); } /** @@ -3030,21 +1949,19 @@ public Observable takeUntil(Observable other) { *

* *

- * Normally, an Observable that returns multiple items will do so by invoking its - * {@link Observer}'s {@link Observer#onNext onNext} method for each such item. You can change + * Normally, an Observable that returns multiple items will do so by invoking its {@link Observer}'s {@link Observer#onNext onNext} method for each such item. You can change * this behavior, instructing the Observable to compose a list of all of these items and then to * invoke the Observer's onNext function once, passing it the entire list, by - * calling the Observable's toList method prior to calling its {@link #subscribe} - * method. + * calling the Observable's toList method prior to calling its {@link #subscribe} method. *

* Be careful not to use this operator on Observables that emit infinite or very large numbers * of items, as you do not have the option to unsubscribe. - * + * * @return an Observable that emits a single item: a List containing all of the items emitted by * the source Observable. */ public Observable> toList() { - return toList(this); + return create(OperationToObservableList.toObservableList(this)); } /** @@ -3053,14 +1970,14 @@ public Observable> toList() { * all other items in the sequence). *

* - * + * * @throws ClassCastException * if any item emitted by the Observable does not implement {@link Comparable} with * respect to all other items emitted by the Observable * @return an Observable that emits the items from the source Observable in sorted order */ public Observable> toSortedList() { - return toSortedList(this); + return create(OperationToObservableSortedList.toSortedList(this)); } /** @@ -3068,21 +1985,21 @@ public Observable> toSortedList() { * order based on a specified comparison function *

* - * + * * @param sortFunction * a function that compares two items emitted by the source Observable and returns * an Integer that indicates their sort order * @return an Observable that emits the items from the source Observable in sorted order */ public Observable> toSortedList(Func2 sortFunction) { - return toSortedList(this, sortFunction); + return create(OperationToObservableSortedList.toSortedList(this, sortFunction)); } /** * Emit a specified set of items before beginning to emit items from the source Observable. *

* - * + * * @param values * the items you want the modified Observable to emit first * @return an Observable that exhibits the modified behavior @@ -3097,7 +2014,7 @@ public Observable startWith(T... values) { * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. *

* - * + * * @param keySelector * a function that extracts the key from an item * @param elementSelector @@ -3111,7 +2028,7 @@ public Observable startWith(T... values) { * share that key value */ public Observable> groupBy(final Func1 keySelector, final Func1 elementSelector) { - return groupBy(this, keySelector, elementSelector); + return create(OperationGroupBy.groupBy(this, keySelector, elementSelector)); } /** @@ -3119,7 +2036,7 @@ public Observable> groupBy(final Func1 keyS * grouped items as {@link GroupedObservable}s, one GroupedObservable per group. *

* - * + * * @param keySelector * a function that extracts the key for each item * @param @@ -3129,15 +2046,14 @@ public Observable> groupBy(final Func1 keyS * share that key value */ public Observable> groupBy(final Func1 keySelector) { - return groupBy(this, keySelector); + return create(OperationGroupBy.groupBy(this, keySelector)); } /** * Converts an Observable into a {@link BlockingObservable} (an Observable with blocking * operators). - * - * @see Blocking - * Observable Operators + * + * @see Blocking Observable Operators */ public BlockingObservable toBlockingObservable() { return BlockingObservable.from(this); @@ -3147,9 +2063,9 @@ public BlockingObservable toBlockingObservable() { * Whether a given {@link Function} is an internal implementation inside rx.* packages or not. *

* For why this is being used see https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" - * + * * NOTE: If strong reasons for not depending on package names comes up then the implementation of this method can change to looking for a marker interface. - * + * * @param f * @return {@code true} if the given function is an internal implementation, and {@code false} otherwise. */ @@ -3203,8 +2119,8 @@ public Subscription call(Observer Observer) { @Test public void testReduce() { - Observable Observable = toObservable(1, 2, 3, 4); - reduce(Observable, new Func2() { + Observable observable = from(1, 2, 3, 4); + observable.reduce(new Func2() { @Override public Integer call(Integer t1, Integer t2) { @@ -3219,8 +2135,8 @@ public Integer call(Integer t1, Integer t2) { @Test public void testReduceWithInitialValue() { - Observable Observable = toObservable(1, 2, 3, 4); - reduce(Observable, 50, new Func2() { + Observable observable = from(1, 2, 3, 4); + observable.reduce(50, new Func2() { @Override public Integer call(Integer t1, Integer t2) { @@ -3235,8 +2151,8 @@ public Integer call(Integer t1, Integer t2) { @Test public void testSequenceEqual() { - Observable first = toObservable(1, 2, 3); - Observable second = toObservable(1, 2, 4); + Observable first = from(1, 2, 3); + Observable second = from(1, 2, 4); @SuppressWarnings("unchecked") Observer result = mock(Observer.class); sequenceEqual(first, second).subscribe(result); @@ -3279,9 +2195,9 @@ public void testMaterializeDematerializeChaining() { /** * The error from the user provided Observer is not handled by the subscribe method try/catch. - * + * * It is handled by the AtomicObserver that wraps the provided Observer. - * + * * Result: Passes (if AtomicObserver functionality exists) */ @Test @@ -3348,7 +2264,7 @@ public void onNext(String v) { /** * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous - * + * * Result: Passes */ @Test @@ -3398,8 +2314,8 @@ public void onNext(String v) { /** * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous - * - * + * + * * Result: Passes */ @Test @@ -3605,9 +2521,9 @@ public void call(String v) { /** * https://github.com/Netflix/RxJava/issues/198 - * + * * Rx Design Guidelines 5.2 - * + * * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be * to rethrow the exception on the thread that the message comes out from the Observable. * The OnCompleted behavior in this case is to do nothing." @@ -3631,13 +2547,13 @@ public void call(Object t1) { /** * https://github.com/Netflix/RxJava/issues/198 - * + * * Rx Design Guidelines 5.2 - * + * * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be * to rethrow the exception on the thread that the message comes out from the Observable. * The OnCompleted behavior in this case is to do nothing." - * + * * @throws InterruptedException */ @Test diff --git a/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java b/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java index 3d5c2d8392..14ac8748b6 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java +++ b/rxjava-core/src/main/java/rx/operators/OperationDematerialize.java @@ -92,7 +92,7 @@ public static class UnitTest { @SuppressWarnings("unchecked") public void testDematerialize1() { Observable> notifications = Observable.from(1, 2).materialize(); - Observable dematerialize = Observable.dematerialize(notifications); + Observable dematerialize = notifications.dematerialize(); Observer aObserver = mock(Observer.class); dematerialize.subscribe(aObserver); diff --git a/rxjava-core/src/main/java/rx/operators/OperationToIterator.java b/rxjava-core/src/main/java/rx/operators/OperationToIterator.java index f3c1b21067..4b56e7dda1 100644 --- a/rxjava-core/src/main/java/rx/operators/OperationToIterator.java +++ b/rxjava-core/src/main/java/rx/operators/OperationToIterator.java @@ -49,10 +49,10 @@ public class OperationToIterator { * the type of source. * @return the iterator that could be used to iterate over the elements of the observable. */ - public static Iterator toIterator(Observable that) { + public static Iterator toIterator(Observable source) { final BlockingQueue> notifications = new LinkedBlockingQueue>(); - Observable.materialize(that).subscribe(new Observer>() { + source.materialize().subscribe(new Observer>() { @Override public void onCompleted() { // ignore diff --git a/rxjava-core/src/main/java/rx/operators/OperationWhere.java b/rxjava-core/src/main/java/rx/operators/OperationWhere.java deleted file mode 100644 index d82b6d829b..0000000000 --- a/rxjava-core/src/main/java/rx/operators/OperationWhere.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright 2013 Netflix, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package rx.operators; - -import org.junit.Test; -import org.mockito.Mockito; - -import rx.Observable; -import rx.Observer; -import rx.Subscription; -import rx.util.functions.Func1; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * Filters an Observable by discarding any items it emits that do not meet some test. - *

- * - */ -public final class OperationWhere { - - public static Func1, Subscription> where(Observable that, Func1 predicate) { - return OperationFilter.filter(that, predicate); - } - - public static class UnitTest { - - @Test - public void testWhere() { - Observable w = Observable.from("one", "two", "three"); - Observable observable = Observable.create(where(w, new Func1() { - - @Override - public Boolean call(String t1) { - return t1.equals("two"); - } - })); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, Mockito.never()).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, Mockito.never()).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - } - -} From 8cb026af3efc1621ccbe5587ff3b66c2d2714543 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 22:27:28 -0700 Subject: [PATCH 14/22] Move Observable UnitTests The Observable class is huge by nature as it is the facade for all operators. Due to this it represents all functionality and should not have it's tests inside it. They are moved to /src/test/ so as to allow breaking them up into lots of individual classes. --- rxjava-core/src/main/java/rx/Observable.java | 522 ----------------- rxjava-core/src/test/java/README.md | 4 +- .../src/test/java/rx/ObservableTests.java | 536 ++++++++++++++++++ 3 files changed, 537 insertions(+), 525 deletions(-) create mode 100644 rxjava-core/src/test/java/rx/ObservableTests.java diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index 98c7a8b441..f00bf47f7a 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -24,17 +24,9 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import rx.concurrency.Schedulers; import rx.observables.BlockingObservable; @@ -83,7 +75,6 @@ import rx.subjects.PublishSubject; import rx.subjects.ReplaySubject; import rx.subjects.Subject; -import rx.subscriptions.BooleanSubscription; import rx.subscriptions.Subscriptions; import rx.util.BufferClosing; import rx.util.BufferOpening; @@ -2081,517 +2072,4 @@ private boolean isInternalImplementation(Object o) { return p != null && p.getName().startsWith("rx.operators"); } - public static class UnitTest { - - @Mock - Observer w; - - @Before - public void before() { - MockitoAnnotations.initMocks(this); - } - - @Test - public void testCreate() { - - Observable observable = create(new Func1, Subscription>() { - - @Override - public Subscription call(Observer Observer) { - Observer.onNext("one"); - Observer.onNext("two"); - Observer.onNext("three"); - Observer.onCompleted(); - return Subscriptions.empty(); - } - - }); - - @SuppressWarnings("unchecked") - Observer aObserver = mock(Observer.class); - observable.subscribe(aObserver); - verify(aObserver, times(1)).onNext("one"); - verify(aObserver, times(1)).onNext("two"); - verify(aObserver, times(1)).onNext("three"); - verify(aObserver, Mockito.never()).onError(any(Throwable.class)); - verify(aObserver, times(1)).onCompleted(); - } - - @Test - public void testReduce() { - Observable observable = from(1, 2, 3, 4); - observable.reduce(new Func2() { - - @Override - public Integer call(Integer t1, Integer t2) { - return t1 + t2; - } - - }).subscribe(w); - // we should be called only once - verify(w, times(1)).onNext(anyInt()); - verify(w).onNext(10); - } - - @Test - public void testReduceWithInitialValue() { - Observable observable = from(1, 2, 3, 4); - observable.reduce(50, new Func2() { - - @Override - public Integer call(Integer t1, Integer t2) { - return t1 + t2; - } - - }).subscribe(w); - // we should be called only once - verify(w, times(1)).onNext(anyInt()); - verify(w).onNext(60); - } - - @Test - public void testSequenceEqual() { - Observable first = from(1, 2, 3); - Observable second = from(1, 2, 4); - @SuppressWarnings("unchecked") - Observer result = mock(Observer.class); - sequenceEqual(first, second).subscribe(result); - verify(result, times(2)).onNext(true); - verify(result, times(1)).onNext(false); - } - - @Test - public void testOnSubscribeFails() { - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - final RuntimeException re = new RuntimeException("bad impl"); - Observable o = Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(Observer t1) { - throw re; - } - - }); - o.subscribe(observer); - verify(observer, times(0)).onNext(anyString()); - verify(observer, times(0)).onCompleted(); - verify(observer, times(1)).onError(re); - } - - @Test - public void testMaterializeDematerializeChaining() { - Observable obs = Observable.just(1); - Observable chained = obs.materialize().dematerialize(); - - @SuppressWarnings("unchecked") - Observer observer = mock(Observer.class); - chained.subscribe(observer); - - verify(observer, times(1)).onNext(1); - verify(observer, times(1)).onCompleted(); - verify(observer, times(0)).onError(any(Throwable.class)); - } - - /** - * The error from the user provided Observer is not handled by the subscribe method try/catch. - * - * It is handled by the AtomicObserver that wraps the provided Observer. - * - * Result: Passes (if AtomicObserver functionality exists) - */ - @Test - public void testCustomObservableWithErrorInObserverAsynchronous() throws InterruptedException { - final CountDownLatch latch = new CountDownLatch(1); - final AtomicInteger count = new AtomicInteger(); - final AtomicReference error = new AtomicReference(); - Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(final Observer observer) { - final BooleanSubscription s = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - try { - if (!s.isUnsubscribed()) { - observer.onNext("1"); - observer.onNext("2"); - observer.onNext("three"); - observer.onNext("4"); - observer.onCompleted(); - } - } finally { - latch.countDown(); - } - } - }).start(); - return s; - } - }).subscribe(new Observer() { - @Override - public void onCompleted() { - System.out.println("completed"); - } - - @Override - public void onError(Throwable e) { - error.set(e); - System.out.println("error"); - e.printStackTrace(); - } - - @Override - public void onNext(String v) { - int num = Integer.parseInt(v); - System.out.println(num); - // doSomething(num); - count.incrementAndGet(); - } - - }); - - // wait for async sequence to complete - latch.await(); - - assertEquals(2, count.get()); - assertNotNull(error.get()); - if (!(error.get() instanceof NumberFormatException)) { - fail("It should be a NumberFormatException"); - } - } - - /** - * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous - * - * Result: Passes - */ - @Test - public void testCustomObservableWithErrorInObserverSynchronous() { - final AtomicInteger count = new AtomicInteger(); - final AtomicReference error = new AtomicReference(); - Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(Observer observer) { - observer.onNext("1"); - observer.onNext("2"); - observer.onNext("three"); - observer.onNext("4"); - observer.onCompleted(); - return Subscriptions.empty(); - } - }).subscribe(new Observer() { - - @Override - public void onCompleted() { - System.out.println("completed"); - } - - @Override - public void onError(Throwable e) { - error.set(e); - System.out.println("error"); - e.printStackTrace(); - } - - @Override - public void onNext(String v) { - int num = Integer.parseInt(v); - System.out.println(num); - // doSomething(num); - count.incrementAndGet(); - } - - }); - assertEquals(2, count.get()); - assertNotNull(error.get()); - if (!(error.get() instanceof NumberFormatException)) { - fail("It should be a NumberFormatException"); - } - } - - /** - * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous - * - * - * Result: Passes - */ - @Test - public void testCustomObservableWithErrorInObservableSynchronous() { - final AtomicInteger count = new AtomicInteger(); - final AtomicReference error = new AtomicReference(); - Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(Observer observer) { - observer.onNext("1"); - observer.onNext("2"); - throw new NumberFormatException(); - } - }).subscribe(new Observer() { - - @Override - public void onCompleted() { - System.out.println("completed"); - } - - @Override - public void onError(Throwable e) { - error.set(e); - System.out.println("error"); - e.printStackTrace(); - } - - @Override - public void onNext(String v) { - System.out.println(v); - count.incrementAndGet(); - } - - }); - assertEquals(2, count.get()); - assertNotNull(error.get()); - if (!(error.get() instanceof NumberFormatException)) { - fail("It should be a NumberFormatException"); - } - } - - @Test - public void testPublish() throws InterruptedException { - final AtomicInteger counter = new AtomicInteger(); - ConnectableObservable o = Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(final Observer observer) { - final BooleanSubscription subscription = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - counter.incrementAndGet(); - observer.onNext("one"); - observer.onCompleted(); - } - }).start(); - return subscription; - } - }).publish(); - - final CountDownLatch latch = new CountDownLatch(2); - - // subscribe once - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - // subscribe again - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - Subscription s = o.connect(); - try { - if (!latch.await(1000, TimeUnit.MILLISECONDS)) { - fail("subscriptions did not receive values"); - } - assertEquals(1, counter.get()); - } finally { - s.unsubscribe(); - } - } - - @Test - public void testReplay() throws InterruptedException { - final AtomicInteger counter = new AtomicInteger(); - ConnectableObservable o = Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(final Observer observer) { - final BooleanSubscription subscription = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - counter.incrementAndGet(); - observer.onNext("one"); - observer.onCompleted(); - } - }).start(); - return subscription; - } - }).replay(); - - // we connect immediately and it will emit the value - Subscription s = o.connect(); - try { - - // we then expect the following 2 subscriptions to get that same value - final CountDownLatch latch = new CountDownLatch(2); - - // subscribe once - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - // subscribe again - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - if (!latch.await(1000, TimeUnit.MILLISECONDS)) { - fail("subscriptions did not receive values"); - } - assertEquals(1, counter.get()); - } finally { - s.unsubscribe(); - } - } - - @Test - public void testCache() throws InterruptedException { - final AtomicInteger counter = new AtomicInteger(); - Observable o = Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(final Observer observer) { - final BooleanSubscription subscription = new BooleanSubscription(); - new Thread(new Runnable() { - - @Override - public void run() { - counter.incrementAndGet(); - observer.onNext("one"); - observer.onCompleted(); - } - }).start(); - return subscription; - } - }).cache(); - - // we then expect the following 2 subscriptions to get that same value - final CountDownLatch latch = new CountDownLatch(2); - - // subscribe once - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - // subscribe again - o.subscribe(new Action1() { - - @Override - public void call(String v) { - assertEquals("one", v); - latch.countDown(); - } - }); - - if (!latch.await(1000, TimeUnit.MILLISECONDS)) { - fail("subscriptions did not receive values"); - } - assertEquals(1, counter.get()); - } - - /** - * https://github.com/Netflix/RxJava/issues/198 - * - * Rx Design Guidelines 5.2 - * - * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be - * to rethrow the exception on the thread that the message comes out from the Observable. - * The OnCompleted behavior in this case is to do nothing." - */ - @Test - public void testErrorThrownWithoutErrorHandlerSynchronous() { - try { - error(new RuntimeException("failure")).subscribe(new Action1() { - - @Override - public void call(Object t1) { - // won't get anything - } - - }); - fail("expected exception"); - } catch (Throwable e) { - assertEquals("failure", e.getMessage()); - } - } - - /** - * https://github.com/Netflix/RxJava/issues/198 - * - * Rx Design Guidelines 5.2 - * - * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be - * to rethrow the exception on the thread that the message comes out from the Observable. - * The OnCompleted behavior in this case is to do nothing." - * - * @throws InterruptedException - */ - @Test - public void testErrorThrownWithoutErrorHandlerAsynchronous() throws InterruptedException { - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference exception = new AtomicReference(); - Observable.create(new Func1, Subscription>() { - - @Override - public Subscription call(final Observer observer) { - new Thread(new Runnable() { - - @Override - public void run() { - try { - observer.onError(new Error("failure")); - } catch (Throwable e) { - // without an onError handler it has to just throw on whatever thread invokes it - exception.set(e); - } - latch.countDown(); - } - }).start(); - return Subscriptions.empty(); - } - }).subscribe(new Action1() { - - @Override - public void call(String t1) { - - } - - }); - // wait for exception - latch.await(3000, TimeUnit.MILLISECONDS); - assertNotNull(exception.get()); - assertEquals("failure", exception.get().getMessage()); - } - } - } diff --git a/rxjava-core/src/test/java/README.md b/rxjava-core/src/test/java/README.md index 74b6c91536..c6a9aea6af 100644 --- a/rxjava-core/src/test/java/README.md +++ b/rxjava-core/src/test/java/README.md @@ -1,6 +1,4 @@ -This test folder only contains performance and functional/integration style tests. - -The unit tests themselves are embedded as inner classes of the Java code (such as here: [rxjava-core/src/main/java/rx/operators](https://github.com/Netflix/RxJava/tree/master/rxjava-core/src/main/java/rx/operators)). +Not all unit tests are here, many are also embedded as inner classes of the main code (such as here: [rxjava-core/src/main/java/rx/operators](https://github.com/Netflix/RxJava/tree/master/rxjava-core/src/main/java/rx/operators)). * For an explanation of this design choice see Ben J. Christensen's [JUnit Tests as Inner Classes](http://benjchristensen.com/2011/10/23/junit-tests-as-inner-classes/). diff --git a/rxjava-core/src/test/java/rx/ObservableTests.java b/rxjava-core/src/test/java/rx/ObservableTests.java new file mode 100644 index 0000000000..690d45859e --- /dev/null +++ b/rxjava-core/src/test/java/rx/ObservableTests.java @@ -0,0 +1,536 @@ +package rx; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import rx.observables.ConnectableObservable; +import rx.subscriptions.BooleanSubscription; +import rx.subscriptions.Subscriptions; +import rx.util.functions.Action1; +import rx.util.functions.Func1; +import rx.util.functions.Func2; + +public class ObservableTests { + + @Mock + Observer w; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testCreate() { + + Observable observable = Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(Observer Observer) { + Observer.onNext("one"); + Observer.onNext("two"); + Observer.onNext("three"); + Observer.onCompleted(); + return Subscriptions.empty(); + } + + }); + + @SuppressWarnings("unchecked") + Observer aObserver = mock(Observer.class); + observable.subscribe(aObserver); + verify(aObserver, times(1)).onNext("one"); + verify(aObserver, times(1)).onNext("two"); + verify(aObserver, times(1)).onNext("three"); + verify(aObserver, Mockito.never()).onError(any(Throwable.class)); + verify(aObserver, times(1)).onCompleted(); + } + + @Test + public void testReduce() { + Observable observable = Observable.from(1, 2, 3, 4); + observable.reduce(new Func2() { + + @Override + public Integer call(Integer t1, Integer t2) { + return t1 + t2; + } + + }).subscribe(w); + // we should be called only once + verify(w, times(1)).onNext(anyInt()); + verify(w).onNext(10); + } + + @Test + public void testReduceWithInitialValue() { + Observable observable = Observable.from(1, 2, 3, 4); + observable.reduce(50, new Func2() { + + @Override + public Integer call(Integer t1, Integer t2) { + return t1 + t2; + } + + }).subscribe(w); + // we should be called only once + verify(w, times(1)).onNext(anyInt()); + verify(w).onNext(60); + } + + @Test + public void testSequenceEqual() { + Observable first = Observable.from(1, 2, 3); + Observable second = Observable.from(1, 2, 4); + @SuppressWarnings("unchecked") + Observer result = mock(Observer.class); + Observable.sequenceEqual(first, second).subscribe(result); + verify(result, times(2)).onNext(true); + verify(result, times(1)).onNext(false); + } + + @Test + public void testOnSubscribeFails() { + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + final RuntimeException re = new RuntimeException("bad impl"); + Observable o = Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(Observer t1) { + throw re; + } + + }); + o.subscribe(observer); + verify(observer, times(0)).onNext(anyString()); + verify(observer, times(0)).onCompleted(); + verify(observer, times(1)).onError(re); + } + + @Test + public void testMaterializeDematerializeChaining() { + Observable obs = Observable.just(1); + Observable chained = obs.materialize().dematerialize(); + + @SuppressWarnings("unchecked") + Observer observer = mock(Observer.class); + chained.subscribe(observer); + + verify(observer, times(1)).onNext(1); + verify(observer, times(1)).onCompleted(); + verify(observer, times(0)).onError(any(Throwable.class)); + } + + /** + * The error from the user provided Observer is not handled by the subscribe method try/catch. + * + * It is handled by the AtomicObserver that wraps the provided Observer. + * + * Result: Passes (if AtomicObserver functionality exists) + */ + @Test + public void testCustomObservableWithErrorInObserverAsynchronous() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicInteger count = new AtomicInteger(); + final AtomicReference error = new AtomicReference(); + Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(final Observer observer) { + final BooleanSubscription s = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + try { + if (!s.isUnsubscribed()) { + observer.onNext("1"); + observer.onNext("2"); + observer.onNext("three"); + observer.onNext("4"); + observer.onCompleted(); + } + } finally { + latch.countDown(); + } + } + }).start(); + return s; + } + }).subscribe(new Observer() { + @Override + public void onCompleted() { + System.out.println("completed"); + } + + @Override + public void onError(Throwable e) { + error.set(e); + System.out.println("error"); + e.printStackTrace(); + } + + @Override + public void onNext(String v) { + int num = Integer.parseInt(v); + System.out.println(num); + // doSomething(num); + count.incrementAndGet(); + } + + }); + + // wait for async sequence to complete + latch.await(); + + assertEquals(2, count.get()); + assertNotNull(error.get()); + if (!(error.get() instanceof NumberFormatException)) { + fail("It should be a NumberFormatException"); + } + } + + /** + * The error from the user provided Observer is handled by the subscribe try/catch because this is synchronous + * + * Result: Passes + */ + @Test + public void testCustomObservableWithErrorInObserverSynchronous() { + final AtomicInteger count = new AtomicInteger(); + final AtomicReference error = new AtomicReference(); + Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(Observer observer) { + observer.onNext("1"); + observer.onNext("2"); + observer.onNext("three"); + observer.onNext("4"); + observer.onCompleted(); + return Subscriptions.empty(); + } + }).subscribe(new Observer() { + + @Override + public void onCompleted() { + System.out.println("completed"); + } + + @Override + public void onError(Throwable e) { + error.set(e); + System.out.println("error"); + e.printStackTrace(); + } + + @Override + public void onNext(String v) { + int num = Integer.parseInt(v); + System.out.println(num); + // doSomething(num); + count.incrementAndGet(); + } + + }); + assertEquals(2, count.get()); + assertNotNull(error.get()); + if (!(error.get() instanceof NumberFormatException)) { + fail("It should be a NumberFormatException"); + } + } + + /** + * The error from the user provided Observable is handled by the subscribe try/catch because this is synchronous + * + * + * Result: Passes + */ + @Test + public void testCustomObservableWithErrorInObservableSynchronous() { + final AtomicInteger count = new AtomicInteger(); + final AtomicReference error = new AtomicReference(); + Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(Observer observer) { + observer.onNext("1"); + observer.onNext("2"); + throw new NumberFormatException(); + } + }).subscribe(new Observer() { + + @Override + public void onCompleted() { + System.out.println("completed"); + } + + @Override + public void onError(Throwable e) { + error.set(e); + System.out.println("error"); + e.printStackTrace(); + } + + @Override + public void onNext(String v) { + System.out.println(v); + count.incrementAndGet(); + } + + }); + assertEquals(2, count.get()); + assertNotNull(error.get()); + if (!(error.get() instanceof NumberFormatException)) { + fail("It should be a NumberFormatException"); + } + } + + @Test + public void testPublish() throws InterruptedException { + final AtomicInteger counter = new AtomicInteger(); + ConnectableObservable o = Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(final Observer observer) { + final BooleanSubscription subscription = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + counter.incrementAndGet(); + observer.onNext("one"); + observer.onCompleted(); + } + }).start(); + return subscription; + } + }).publish(); + + final CountDownLatch latch = new CountDownLatch(2); + + // subscribe once + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + // subscribe again + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + Subscription s = o.connect(); + try { + if (!latch.await(1000, TimeUnit.MILLISECONDS)) { + fail("subscriptions did not receive values"); + } + assertEquals(1, counter.get()); + } finally { + s.unsubscribe(); + } + } + + @Test + public void testReplay() throws InterruptedException { + final AtomicInteger counter = new AtomicInteger(); + ConnectableObservable o = Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(final Observer observer) { + final BooleanSubscription subscription = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + counter.incrementAndGet(); + observer.onNext("one"); + observer.onCompleted(); + } + }).start(); + return subscription; + } + }).replay(); + + // we connect immediately and it will emit the value + Subscription s = o.connect(); + try { + + // we then expect the following 2 subscriptions to get that same value + final CountDownLatch latch = new CountDownLatch(2); + + // subscribe once + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + // subscribe again + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + if (!latch.await(1000, TimeUnit.MILLISECONDS)) { + fail("subscriptions did not receive values"); + } + assertEquals(1, counter.get()); + } finally { + s.unsubscribe(); + } + } + + @Test + public void testCache() throws InterruptedException { + final AtomicInteger counter = new AtomicInteger(); + Observable o = Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(final Observer observer) { + final BooleanSubscription subscription = new BooleanSubscription(); + new Thread(new Runnable() { + + @Override + public void run() { + counter.incrementAndGet(); + observer.onNext("one"); + observer.onCompleted(); + } + }).start(); + return subscription; + } + }).cache(); + + // we then expect the following 2 subscriptions to get that same value + final CountDownLatch latch = new CountDownLatch(2); + + // subscribe once + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + // subscribe again + o.subscribe(new Action1() { + + @Override + public void call(String v) { + assertEquals("one", v); + latch.countDown(); + } + }); + + if (!latch.await(1000, TimeUnit.MILLISECONDS)) { + fail("subscriptions did not receive values"); + } + assertEquals(1, counter.get()); + } + + /** + * https://github.com/Netflix/RxJava/issues/198 + * + * Rx Design Guidelines 5.2 + * + * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be + * to rethrow the exception on the thread that the message comes out from the Observable. + * The OnCompleted behavior in this case is to do nothing." + */ + @Test + public void testErrorThrownWithoutErrorHandlerSynchronous() { + try { + Observable.error(new RuntimeException("failure")).subscribe(new Action1() { + + @Override + public void call(Object t1) { + // won't get anything + } + + }); + fail("expected exception"); + } catch (Throwable e) { + assertEquals("failure", e.getMessage()); + } + } + + /** + * https://github.com/Netflix/RxJava/issues/198 + * + * Rx Design Guidelines 5.2 + * + * "when calling the Subscribe method that only has an onNext argument, the OnError behavior will be + * to rethrow the exception on the thread that the message comes out from the Observable. + * The OnCompleted behavior in this case is to do nothing." + * + * @throws InterruptedException + */ + @Test + public void testErrorThrownWithoutErrorHandlerAsynchronous() throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference exception = new AtomicReference(); + Observable.create(new Func1, Subscription>() { + + @Override + public Subscription call(final Observer observer) { + new Thread(new Runnable() { + + @Override + public void run() { + try { + observer.onError(new Error("failure")); + } catch (Throwable e) { + // without an onError handler it has to just throw on whatever thread invokes it + exception.set(e); + } + latch.countDown(); + } + }).start(); + return Subscriptions.empty(); + } + }).subscribe(new Action1() { + + @Override + public void call(String t1) { + + } + + }); + // wait for exception + latch.await(3000, TimeUnit.MILLISECONDS); + assertNotNull(exception.get()); + assertEquals("failure", exception.get().getMessage()); + } +} \ No newline at end of file From 077b148f189e02fd3509ddd7131a4a1bb285a369 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Tue, 27 Aug 2013 22:36:35 -0700 Subject: [PATCH 15/22] Fix RxJava Groovy Unit Tests after static method refactor --- .../rx/lang/groovy/ObservableTests.groovy | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/language-adaptors/rxjava-groovy/src/test/groovy/rx/lang/groovy/ObservableTests.groovy b/language-adaptors/rxjava-groovy/src/test/groovy/rx/lang/groovy/ObservableTests.groovy index dd36af1088..e0fdfdcfc3 100644 --- a/language-adaptors/rxjava-groovy/src/test/groovy/rx/lang/groovy/ObservableTests.groovy +++ b/language-adaptors/rxjava-groovy/src/test/groovy/rx/lang/groovy/ObservableTests.groovy @@ -58,7 +58,7 @@ def class ObservableTests { @Test public void testFilter() { - Observable.filter(Observable.from(1, 2, 3), {it >= 2}).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).filter({it >= 2}).subscribe({ result -> a.received(result)}); verify(a, times(0)).received(1); verify(a, times(1)).received(2); verify(a, times(1)).received(3); @@ -82,7 +82,7 @@ def class ObservableTests { @Test public void testMap2() { - Observable.map(Observable.from(1, 2, 3), {'hello_' + it}).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).map({'hello_' + it}).subscribe({ result -> a.received(result)}); verify(a, times(1)).received("hello_" + 1); verify(a, times(1)).received("hello_" + 2); verify(a, times(1)).received("hello_" + 3); @@ -90,7 +90,7 @@ def class ObservableTests { @Test public void testMaterialize() { - Observable.materialize(Observable.from(1, 2, 3)).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).materialize().subscribe({ result -> a.received(result)}); // we expect 4 onNext calls: 3 for 1, 2, 3 ObservableNotification.OnNext and 1 for ObservableNotification.OnCompleted verify(a, times(4)).received(any(Notification.class)); verify(a, times(0)).error(any(Exception.class)); @@ -162,7 +162,7 @@ def class ObservableTests { @Test public void testSkipTake() { - Observable.skip(Observable.from(1, 2, 3), 1).take(1).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).skip(1).take(1).subscribe({ result -> a.received(result)}); verify(a, times(0)).received(1); verify(a, times(1)).received(2); verify(a, times(0)).received(3); @@ -170,7 +170,7 @@ def class ObservableTests { @Test public void testSkip() { - Observable.skip(Observable.from(1, 2, 3), 2).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).skip(2).subscribe({ result -> a.received(result)}); verify(a, times(0)).received(1); verify(a, times(0)).received(2); verify(a, times(1)).received(3); @@ -178,7 +178,7 @@ def class ObservableTests { @Test public void testTake() { - Observable.take(Observable.from(1, 2, 3), 2).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).take(2).subscribe({ result -> a.received(result)}); verify(a, times(1)).received(1); verify(a, times(1)).received(2); verify(a, times(0)).received(3); @@ -192,7 +192,7 @@ def class ObservableTests { @Test public void testTakeWhileViaGroovy() { - Observable.takeWhile(Observable.from(1, 2, 3), { x -> x < 3}).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).takeWhile( { x -> x < 3}).subscribe({ result -> a.received(result)}); verify(a, times(1)).received(1); verify(a, times(1)).received(2); verify(a, times(0)).received(3); @@ -200,7 +200,7 @@ def class ObservableTests { @Test public void testTakeWhileWithIndexViaGroovy() { - Observable.takeWhileWithIndex(Observable.from(1, 2, 3), { x, i -> i < 2}).subscribe({ result -> a.received(result)}); + Observable.from(1, 2, 3).takeWhileWithIndex({ x, i -> i < 2}).subscribe({ result -> a.received(result)}); verify(a, times(1)).received(1); verify(a, times(1)).received(2); verify(a, times(0)).received(3); @@ -212,24 +212,12 @@ def class ObservableTests { verify(a, times(1)).received(Arrays.asList(1, 2, 3, 4, 5)); } - @Test - public void testToSortedListStatic() { - Observable.toSortedList(Observable.from(1, 3, 2, 5, 4)).subscribe({ result -> a.received(result)}); - verify(a, times(1)).received(Arrays.asList(1, 2, 3, 4, 5)); - } - @Test public void testToSortedListWithFunction() { new TestFactory().getNumbers().toSortedList({a, b -> a - b}).subscribe({ result -> a.received(result)}); verify(a, times(1)).received(Arrays.asList(1, 2, 3, 4, 5)); } - @Test - public void testToSortedListWithFunctionStatic() { - Observable.toSortedList(Observable.from(1, 3, 2, 5, 4), {a, b -> a - b}).subscribe({ result -> a.received(result)}); - verify(a, times(1)).received(Arrays.asList(1, 2, 3, 4, 5)); - } - @Test public void testForEach() { Observable.create(new AsyncObservable()).toBlockingObservable().forEach({ result -> a.received(result)}); From de66728dd70c78320fb870fdba71234cdf6842a9 Mon Sep 17 00:00:00 2001 From: jmhofer Date: Wed, 28 Aug 2013 20:37:47 +0200 Subject: [PATCH 16/22] re-added combineLatest methods that got lost due to too optimistic super/extends generics --- rxjava-core/src/main/java/rx/Observable.java | 38 +++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index f00bf47f7a..2b9ba46fcb 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -15,10 +15,6 @@ */ package rx; -import static org.junit.Assert.*; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -27,7 +23,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; - import rx.concurrency.Schedulers; import rx.observables.BlockingObservable; import rx.observables.ConnectableObservable; @@ -35,6 +30,7 @@ import rx.operators.OperationAll; import rx.operators.OperationBuffer; import rx.operators.OperationCache; +import rx.operators.OperationCombineLatest; import rx.operators.OperationConcat; import rx.operators.OperationDefer; import rx.operators.OperationDematerialize; @@ -1085,6 +1081,38 @@ public static Observable zip(Observable w0, Observabl return create(OperationZip.zip(w0, w1, w2, w3, reduceFunction)); } + /** + * Combines the given observables, emitting an event containing an aggregation of the latest values of each of the source observables + * each time an event is received from one of the source observables, where the aggregation is defined by the given function. + *

+ * + * + * @param w0 + * The first source observable. + * @param w1 + * The second source observable. + * @param combineFunction + * The aggregation function used to combine the source observable values. + * @return An Observable that combines the source Observables with the given combine function + */ + public static Observable combineLatest(Observable w0, Observable w1, Func2 combineFunction) { + return create(OperationCombineLatest.combineLatest(w0, w1, combineFunction)); + } + + /** + * @see #combineLatest(Observable, Observable, Func2) + */ + public static Observable combineLatest(Observable w0, Observable w1, Observable w2, Func3 combineFunction) { + return create(OperationCombineLatest.combineLatest(w0, w1, w2, combineFunction)); + } + + /** + * @see #combineLatest(Observable, Observable, Func2) + */ + public static Observable combineLatest(Observable w0, Observable w1, Observable w2, Observable w3, Func4 combineFunction) { + return create(OperationCombineLatest.combineLatest(w0, w1, w2, w3, combineFunction)); + } + /** * Creates an Observable which produces buffers of collected values. * From bd10365756b5d74f9faa9f50512735d3f4d7905f Mon Sep 17 00:00:00 2001 From: jmhofer Date: Wed, 28 Aug 2013 21:20:06 +0200 Subject: [PATCH 17/22] Reactivated the rxjava-core tests --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index c7378d469a..440cac0acc 100644 --- a/build.gradle +++ b/build.gradle @@ -63,3 +63,7 @@ subprojects { } } +project(':rxjava-core') { + sourceSets.test.java.srcDir 'src/test/java' +} + From e3e148a195927582102b0fc076d49a27b16c3de2 Mon Sep 17 00:00:00 2001 From: jmhofer Date: Wed, 28 Aug 2013 21:46:58 +0200 Subject: [PATCH 18/22] repaired rxjava-swing to work with new scheduler and observable api --- .../src/main/java/rx/concurrency/SwingScheduler.java | 8 ++------ .../src/main/java/rx/observables/SwingObservable.java | 3 +-- .../src/main/java/rx/swing/sources/KeyEventSource.java | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/concurrency/SwingScheduler.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/concurrency/SwingScheduler.java index ced759f6f5..2ce298c590 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/concurrency/SwingScheduler.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/concurrency/SwingScheduler.java @@ -38,7 +38,6 @@ import rx.subscriptions.CompositeSubscription; import rx.subscriptions.Subscriptions; import rx.util.functions.Action0; -import rx.util.functions.Func0; import rx.util.functions.Func2; /** @@ -187,14 +186,12 @@ public void testPeriodicScheduling() throws Exception { final CountDownLatch latch = new CountDownLatch(4); final Action0 innerAction = mock(Action0.class); - final Action0 unsubscribe = mock(Action0.class); - final Func0 action = new Func0() { + final Action0 action = new Action0() { @Override - public Subscription call() { + public void call() { try { innerAction.call(); assertTrue(SwingUtilities.isEventDispatchThread()); - return Subscriptions.create(unsubscribe); } finally { latch.countDown(); } @@ -210,7 +207,6 @@ public Subscription call() { sub.unsubscribe(); waitForEmptyEventQueue(); verify(innerAction, times(4)).call(); - verify(unsubscribe, times(4)).call(); } @Test diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java index 174c529d2d..b280638191 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/observables/SwingObservable.java @@ -26,7 +26,6 @@ import javax.swing.AbstractButton; import rx.Observable; -import static rx.Observable.filter; import rx.swing.sources.AbstractButtonSource; import rx.swing.sources.ComponentEventSource; import rx.swing.sources.KeyEventSource; @@ -68,7 +67,7 @@ public static Observable fromKeyEvents(Component component) { * @return Observable of key events. */ public static Observable fromKeyEvents(Component component, final Set keyCodes) { - return filter(fromKeyEvents(component), new Func1() { + return fromKeyEvents(component).filter(new Func1() { @Override public Boolean call(KeyEvent event) { return keyCodes.contains(event.getKeyCode()); diff --git a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java index 3716b599f9..291e0202aa 100644 --- a/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java +++ b/rxjava-contrib/rxjava-swing/src/main/java/rx/swing/sources/KeyEventSource.java @@ -85,7 +85,7 @@ public void call() { * @see SwingObservable.fromKeyEvents(Component, Set) */ public static Observable> currentlyPressedKeysOf(Component component) { - return Observable.>scan(fromKeyEventsOf(component), new HashSet(), new Func2, KeyEvent, Set>() { + return fromKeyEventsOf(component).>scan(new HashSet(), new Func2, KeyEvent, Set>() { @Override public Set call(Set pressedKeys, KeyEvent event) { Set afterEvent = new HashSet(pressedKeys); From 2dcbf1cd0245c50f4b338e8f31a5dd80d9f8501f Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Thu, 29 Aug 2013 00:31:28 -0700 Subject: [PATCH 19/22] Added dummy Clojure class and stopped compiling Clojure examples to get rxjava-clojure JAR generation unblocked --- .../clojure/examples/{rx_examples.clj => rx_examples.txt} | 0 .../examples/{video_example.clj => video_example.txt} | 0 .../src/main/clojure/rx/lang/clojure/DummyClojureClass.clj | 6 ++++++ 3 files changed, 6 insertions(+) rename language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/{rx_examples.clj => rx_examples.txt} (100%) rename language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/{video_example.clj => video_example.txt} (100%) create mode 100644 language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj diff --git a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.clj b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt similarity index 100% rename from language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.clj rename to language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt diff --git a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.clj b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt similarity index 100% rename from language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.clj rename to language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt diff --git a/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj b/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj new file mode 100644 index 0000000000..bcdebdc3bb --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj @@ -0,0 +1,6 @@ +(ns rx.lang.clojure.DummyClojureClass) + +(defn hello-world [username] + (println (format "Hello, %s" username))) + +(hello-world "world") From 885de91ea45d194f0473fa9c3098243f18d3f65f Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Thu, 29 Aug 2013 13:13:22 -0700 Subject: [PATCH 20/22] Make Functions.from typesafe --- .../java/rx/subscriptions/Subscriptions.java | 18 +----------------- .../main/java/rx/util/functions/Action.java | 2 +- .../main/java/rx/util/functions/Functions.java | 13 ++----------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java index f3f1dd46c7..788942e99a 100644 --- a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java +++ b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java @@ -20,6 +20,7 @@ import rx.Subscription; import rx.util.functions.Action0; import rx.util.functions.FuncN; +import rx.util.functions.Function; import rx.util.functions.Functions; /** @@ -83,23 +84,6 @@ public static CompositeSubscription create(Subscription... subscriptions) { return new CompositeSubscription(subscriptions); } - /** - * A {@link Subscription} implemented via an anonymous function (such as closures from other languages). - * - * @return {@link Subscription} - */ - public static Subscription create(final Object unsubscribe) { - final FuncN f = Functions.from(unsubscribe); - return new Subscription() { - - @Override - public void unsubscribe() { - f.call(); - } - - }; - } - /** * A {@link Subscription} that does nothing when its unsubscribe method is called. */ diff --git a/rxjava-core/src/main/java/rx/util/functions/Action.java b/rxjava-core/src/main/java/rx/util/functions/Action.java index c1d43eede6..27d781e957 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action.java @@ -5,6 +5,6 @@ *

* Marker interface to allow instanceof checks. */ -public interface Action { +public interface Action extends Function { } diff --git a/rxjava-core/src/main/java/rx/util/functions/Functions.java b/rxjava-core/src/main/java/rx/util/functions/Functions.java index bae9c466ca..c66ca837e4 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Functions.java +++ b/rxjava-core/src/main/java/rx/util/functions/Functions.java @@ -15,9 +15,6 @@ */ package rx.util.functions; -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; - public class Functions { /** @@ -26,17 +23,11 @@ public class Functions { * @param function */ @SuppressWarnings({ "rawtypes" }) - public static FuncN from(final Object function) { + public static FuncN from(final Function function) { if (function == null) { throw new RuntimeException("function is null. Can't send arguments to null function."); } - - /* check for typed Rx Function implementation first */ - if (function instanceof Function) { - return fromFunction((Function) function); - } - // no support found - throw new RuntimeException("Unsupported closure type: " + function.getClass().getSimpleName()); + return fromFunction(function); } @SuppressWarnings({ "unchecked", "rawtypes" }) From f8bacd49420b0a5ed3a246b4a36ee3b643478823 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Thu, 29 Aug 2013 13:14:42 -0700 Subject: [PATCH 21/22] Remove subscribe(Map) We considered it being but that is also awkward as it's not a real functional interface. Also because of type erasure extension methods aren't super helpful here as Map collides with Map --- rxjava-core/src/main/java/rx/Observable.java | 61 ++------------------ 1 file changed, 6 insertions(+), 55 deletions(-) diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index 2b9ba46fcb..a4ddbaf452 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -77,6 +77,7 @@ import rx.util.OnErrorNotImplementedException; import rx.util.Range; import rx.util.Timestamped; +import rx.util.functions.Action; import rx.util.functions.Action0; import rx.util.functions.Action1; import rx.util.functions.Func0; @@ -249,56 +250,6 @@ private Subscription protectivelyWrapAndSubscribe(Observer o) { return subscription.wrap(subscribe(new SafeObserver(subscription, o))); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Subscription subscribe(final Map callbacks) { - if (callbacks == null) { - throw new RuntimeException("callbacks map can not be null"); - } - Object _onNext = callbacks.get("onNext"); - if (_onNext == null) { - throw new RuntimeException("'onNext' key must contain an implementation"); - } - // lookup and memoize onNext - final FuncN onNext = Functions.from(_onNext); - - /** - * Wrapping since raw functions provided by the user are being invoked. - * - * See https://github.com/Netflix/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls to user code from within an operator" - */ - return protectivelyWrapAndSubscribe(new Observer() { - - @Override - public void onCompleted() { - Object onComplete = callbacks.get("onCompleted"); - if (onComplete != null) { - Functions.from(onComplete).call(); - } - } - - @Override - public void onError(Throwable e) { - handleError(e); - Object onError = callbacks.get("onError"); - if (onError != null) { - Functions.from(onError).call(e); - } else { - throw new OnErrorNotImplementedException(e); - } - } - - @Override - public void onNext(Object args) { - onNext.call(args); - } - - }); - } - - public Subscription subscribe(final Map callbacks, Scheduler scheduler) { - return subscribeOn(scheduler).subscribe(callbacks); - } - public Subscription subscribe(final Action1 onNext) { if (onNext == null) { throw new IllegalArgumentException("onNext can not be null"); @@ -1086,13 +1037,13 @@ public static Observable zip(Observable w0, Observabl * each time an event is received from one of the source observables, where the aggregation is defined by the given function. *

* - * + * * @param w0 - * The first source observable. + * The first source observable. * @param w1 - * The second source observable. + * The second source observable. * @param combineFunction - * The aggregation function used to combine the source observable values. + * The aggregation function used to combine the source observable values. * @return An Observable that combines the source Observables with the given combine function */ public static Observable combineLatest(Observable w0, Observable w1, Func2 combineFunction) { @@ -1112,7 +1063,7 @@ public static Observable combineLatest(Observable w0, Obs public static Observable combineLatest(Observable w0, Observable w1, Observable w2, Observable w3, Func4 combineFunction) { return create(OperationCombineLatest.combineLatest(w0, w1, w2, w3, combineFunction)); } - + /** * Creates an Observable which produces buffers of collected values. * From 4fa627d6b6ef50f459cef50397af8d873468cfa4 Mon Sep 17 00:00:00 2001 From: Dave Ray Date: Thu, 29 Aug 2013 22:55:22 -0700 Subject: [PATCH 22/22] Update rxjava-clojure adaptor. Added rx.lang.clojure.interop namespace with fn and action macros. Updated examples. Updated README. --- language-adaptors/rxjava-clojure/README.md | 52 +++++++-- language-adaptors/rxjava-clojure/build.gradle | 9 +- .../lang/clojure/examples/http_examples.txt | 58 ++++++++++ .../rx/lang/clojure/examples/rx_examples.txt | 109 ++++-------------- .../lang/clojure/examples/video_example.txt | 50 ++++---- .../rx/lang/clojure/DummyClojureClass.clj | 6 - .../main/clojure/rx/lang/clojure/interop.clj | 98 ++++++++++++++++ .../clojure/rx/lang/clojure/interop_test.clj | 88 ++++++++++++++ .../rx/lang/clojure/observable_tests.clj | 7 -- 9 files changed, 344 insertions(+), 133 deletions(-) create mode 100644 language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/http_examples.txt delete mode 100644 language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj create mode 100644 language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/interop.clj create mode 100644 language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/interop_test.clj delete mode 100644 language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/observable_tests.clj diff --git a/language-adaptors/rxjava-clojure/README.md b/language-adaptors/rxjava-clojure/README.md index 35faeab8ba..bb452b98a3 100644 --- a/language-adaptors/rxjava-clojure/README.md +++ b/language-adaptors/rxjava-clojure/README.md @@ -1,21 +1,57 @@ # Clojure Adaptor for RxJava +This adaptor provides functions and macros to ease Clojure/RxJava interop. In particular, there are functions and macros for turning Clojure functions and code into RxJava `Func*` and `Action*` interfaces without the tedium of manually reifying the interfaces. -This adaptor allows 'fn' functions to be used and RxJava will know how to invoke them. +# Basic Usage -This enables code such as: +## Requiring the interop namespace +The first thing to do is to require the namespace: ```clojure -(-> - (Observable/toObservable ["one" "two" "three"]) - (.take 2) - (.subscribe (fn [arg] (println arg)))) +(ns my.namespace + (:require [rx.lang.clojure.interop :as rx]) + (:import [rx Observable])) ``` -This still dependes on Clojure using Java interop against the Java API. +or, at the REPL: -A future goal is a Clojure wrapper to expose the functions in a more idiomatic way. +```clojure +(require '[rx.lang.clojure.interop :as rx]) +``` + +## Using rx/fn +Once the namespace is required, you can use the `rx/fn` macro anywhere RxJava wants a `rx.util.functions.Func` object. The syntax is exactly the same as `clojure.core/fn`: + +```clojure +(-> my-observable + (.map (rx/fn [v] (* 2 v)))) +``` + +If you already have a plain old Clojure function you'd like to use, you can pass it to the `rx/fn*` function to get a new object that implements `rx.util.functions.Func`: + +```clojure +(-> my-numbers + (.reduce (rx/fn* +))) +``` + +## Using rx/action +The `rx/action` macro is identical to `rx/fn` except that the object returned implements `rx.util.functions.Action` interfaces. It's used in `subscribe` and other side-effect-y contexts: + +```clojure +(-> my-observable + (.map (rx/fn* transform-data)) + (.finallyDo (rx/action [] (println "Finished transform"))) + (.subscribe (rx/action [v] (println "Got value" v)) + (rx/action [e] (println "Get error" e)) + (rx/action [] (println "Sequence complete")))) +``` + +# Gotchas +Here are a few things to keep in mind when using this interop: +* Keep in mind the (mostly empty) distinction between `Func` and `Action` and which is used in which contexts +* If there are multiple Java methods overloaded by `Func` arity, you'll need to use a type hint to let the compiler know which one to choose. +* Methods that take a predicate (like filter) expect the predicate to return a boolean value. A function that returns a non-boolean value will result in a `ClassCastException`. # Binaries diff --git a/language-adaptors/rxjava-clojure/build.gradle b/language-adaptors/rxjava-clojure/build.gradle index fc8af32d0b..0aeba9680a 100644 --- a/language-adaptors/rxjava-clojure/build.gradle +++ b/language-adaptors/rxjava-clojure/build.gradle @@ -4,12 +4,9 @@ apply plugin: 'osgi' dependencies { compile project(':rxjava-core') - provided 'junit:junit-dep:4.10' - provided 'org.mockito:mockito-core:1.8.5' - // clojure compile 'org.clojure:clojure:1.4.+' - compile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http + //compile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http } /* @@ -20,7 +17,7 @@ warnOnReflection = true buildscript { repositories { maven { url "http://clojars.org/repo" } } - dependencies { classpath "clojuresque:clojuresque:1.5.4" } + dependencies { classpath "clojuresque:clojuresque:1.5.8" } } repositories { @@ -52,4 +49,4 @@ jar { instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' instruction 'Fragment-Host', 'com.netflix.rxjava.core' } -} \ No newline at end of file +} diff --git a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/http_examples.txt b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/http_examples.txt new file mode 100644 index 0000000000..c9c61f757d --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/http_examples.txt @@ -0,0 +1,58 @@ +(ns rx.lang.clojure.examples.http-examples + (:require [rx.lang.clojure.interop :as rx] + [clj-http.client :as http]) + (:import rx.Observable rx.subscriptions.Subscriptions)) + +; NOTE on naming conventions. I'm using camelCase names (against clojure convention) +; in this file as I'm purposefully keeping functions and methods across +; different language implementations in-sync for easy comparison. + +(defn fetchWikipediaArticleAsynchronously [wikipediaArticleNames] + "Fetch a list of Wikipedia articles asynchronously. + + return Observable of HTML" + (Observable/create + (rx/fn [observer] + (let [f (future + (doseq [articleName wikipediaArticleNames] + (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) + ; after sending response to onnext we complete the sequence + (-> observer .onCompleted))] + ; a subscription that cancels the future if unsubscribed + (Subscriptions/create (rx/action [] (future-cancel f))))))) + +; To see output +(comment + (-> (fetchWikipediaArticleAsynchronously ["Tiger" "Elephant"]) + (.subscribe (rx/action [v] (println "--- Article ---\n" (subs (:body v) 0 125) "..."))))) + + +; -------------------------------------------------- +; Error Handling +; -------------------------------------------------- + +(defn fetchWikipediaArticleAsynchronouslyWithErrorHandling [wikipediaArticleNames] + "Fetch a list of Wikipedia articles asynchronously + with proper error handling. + + return Observable of HTML" + (Observable/create + (rx/fn [observer] + (let [f (future + (try + (doseq [articleName wikipediaArticleNames] + (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) + ;(catch Exception e (prn "exception"))) + (catch Exception e (-> observer (.onError e)))) + ; after sending response to onNext we complete the sequence + (-> observer .onCompleted))] + ; a subscription that cancels the future if unsubscribed + (Subscriptions/create (rx/action [] (future-cancel f))))))) + +; To see output +(comment + (-> (fetchWikipediaArticleAsynchronouslyWithErrorHandling ["Tiger" "NonExistentTitle" "Elephant"]) + (.subscribe (rx/action [v] (println "--- Article ---\n" (subs (:body v) 0 125) "...")) + (rx/action [e] (println "--- Error ---\n" (.getMessage e)))))) + + diff --git a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt index 943ecb2f17..8245840a6c 100644 --- a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt +++ b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/rx_examples.txt @@ -1,6 +1,6 @@ (ns rx.lang.clojure.examples.rx-examples - (:import rx.Observable rx.subscriptions.Subscriptions) - (:require [clj-http.client :as http])) + (:require [rx.lang.clojure.interop :as rx]) + (:import rx.Observable rx.subscriptions.Subscriptions)) ; NOTE on naming conventions. I'm using camelCase names (against clojure convention) ; in this file as I'm purposefully keeping functions and methods across @@ -12,8 +12,8 @@ (defn hello [& args] - (-> (Observable/toObservable args) - (.subscribe #(println (str "Hello " % "!"))))) + (-> (Observable/from args) + (.subscribe (rx/action [v] (println (str "Hello " v "!")))))) ; To see output (comment @@ -23,22 +23,13 @@ ; Create Observable from Existing Data ; -------------------------------------------------- -(defn existingDataFromNumbers [] - (Observable/toObservable [1 2 3 4 5 6])) (defn existingDataFromNumbersUsingFrom [] (Observable/from [1 2 3 4 5 6])) -(defn existingDataFromObjects [] - (Observable/toObservable ["a" "b" "c"])) - (defn existingDataFromObjectsUsingFrom [] (Observable/from ["a" "b" "c"])) -(defn existingDataFromList [] - (let [list [5, 6, 7, 8]] - (Observable/toObservable list))) - (defn existingDataFromListUsingFrom [] (let [list [5, 6, 7, 8]] (Observable/from list))) @@ -56,7 +47,7 @@ returns Observable" (Observable/create - (fn [observer] + (rx/fn [observer] (doseq [x (range 50)] (-> observer (.onNext (str "value_" x)))) ; after sending all values we complete the sequence (-> observer .onCompleted) @@ -66,7 +57,7 @@ ; To see output (comment - (.subscribe (customObservableBlocking) println)) + (.subscribe (customObservableBlocking) (rx/action* println))) (defn customObservableNonBlocking [] "This example shows a custom Observable that does not block @@ -74,38 +65,18 @@ returns Observable" (Observable/create - (fn [observer] + (rx/fn [observer] (let [f (future (doseq [x (range 50)] (-> observer (.onNext (str "anotherValue_" x)))) ; after sending all values we complete the sequence (-> observer .onCompleted))] ; return a subscription that cancels the future - (Subscriptions/create #(future-cancel f)))))) - -; To see output -(comment - (.subscribe (customObservableNonBlocking) println)) - - -(defn fetchWikipediaArticleAsynchronously [wikipediaArticleNames] - "Fetch a list of Wikipedia articles asynchronously. - - return Observable of HTML" - (Observable/create - (fn [observer] - (let [f (future - (doseq [articleName wikipediaArticleNames] - (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) - ; after sending response to onnext we complete the sequence - (-> observer .onCompleted))] - ; a subscription that cancels the future if unsubscribed - (Subscriptions/create #(future-cancel f)))))) + (Subscriptions/create (rx/action [] (future-cancel f))))))) ; To see output (comment - (-> (fetchWikipediaArticleAsynchronously ["Tiger" "Elephant"]) - (.subscribe #(println "--- Article ---\n" (subs (:body %) 0 125) "...")))) + (.subscribe (customObservableNonBlocking) (rx/action* println))) ; -------------------------------------------------- @@ -119,8 +90,8 @@ (customObservableNonBlocking) (.skip 10) (.take 5) - (.map #(str % "_transformed")) - (.subscribe #(println "onNext =>" %)))) + (.map (rx/fn [v] (str v "_transformed"))) + (.subscribe (rx/action [v] (println "onNext =>" v))))) ; To see output (comment @@ -136,7 +107,7 @@ return Observable" (Observable/create - (fn [observer] + (rx/fn [observer] (let [f (future (try ; simulate fetching user data via network service call with latency @@ -147,14 +118,14 @@ (-> observer .onCompleted) (catch Exception e (-> observer (.onError e))))) ] ; a subscription that cancels the future if unsubscribed - (Subscriptions/create #(future-cancel f)))))) + (Subscriptions/create (rx/action [] (future-cancel f))))))) (defn getVideoBookmark [userId, videoId] "Asynchronously fetch bookmark for video return Observable" (Observable/create - (fn [observer] + (rx/fn [observer] (let [f (future (try ; simulate fetching user data via network service call with latency @@ -165,13 +136,13 @@ (-> observer .onCompleted) (catch Exception e (-> observer (.onError e)))))] ; a subscription that cancels the future if unsubscribed - (Subscriptions/create #(future-cancel f)))))) + (Subscriptions/create (rx/action [] (future-cancel f))))))) (defn getVideoMetadata [videoId, preferredLanguage] "Asynchronously fetch movie metadata for a given language return Observable" (Observable/create - (fn [observer] + (rx/fn [observer] (let [f (future (try ; simulate fetching video data via network service call with latency @@ -190,7 +161,7 @@ (-> observer .onCompleted) (catch Exception e (-> observer (.onError e))))) ] ; a subscription that cancels the future if unsubscribed - (Subscriptions/create #(future-cancel f)))))) + (Subscriptions/create (rx/action [] (future-cancel f))))))) (defn getVideoForUser [userId videoId] @@ -200,24 +171,24 @@ - user data return Observable" (let [user-observable (-> (getUser userId) - (.map (fn [user] {:user-name (:name user) + (.map (rx/fn [user] {:user-name (:name user) :language (:preferred-language user)}))) bookmark-observable (-> (getVideoBookmark userId videoId) - (.map (fn [bookmark] {:viewed-position (:position bookmark)}))) + (.map (rx/fn [bookmark] {:viewed-position (:position bookmark)}))) ; getVideoMetadata requires :language from user-observable so nest inside map function video-metadata-observable (-> user-observable (.mapMany ; fetch metadata after a response from user-observable is received - (fn [user-map] + (rx/fn [user-map] (getVideoMetadata videoId (:language user-map)))))] ; now combine 3 async sequences using zip (-> (Observable/zip bookmark-observable video-metadata-observable user-observable - (fn [bookmark-map metadata-map user-map] + (rx/fn [bookmark-map metadata-map user-map] {:bookmark-map bookmark-map :metadata-map metadata-map :user-map user-map})) ; and transform into a single response object - (.map (fn [data] + (.map (rx/fn [data] {:video-id videoId :video-metadata (:metadata-map data) :user-id userId @@ -231,37 +202,7 @@ (comment (-> (getVideoForUser 12345 78965) (.subscribe - (fn [x] (println "--- Object ---\n" x)) - (fn [e] (println "--- Error ---\n" e)) - (fn [] (println "--- Completed ---"))))) - - -; -------------------------------------------------- -; Error Handling -; -------------------------------------------------- - -(defn fetchWikipediaArticleAsynchronouslyWithErrorHandling [wikipediaArticleNames] - "Fetch a list of Wikipedia articles asynchronously - with proper error handling. - - return Observable of HTML" - (Observable/create - (fn [observer] - (let [f (future - (try - (doseq [articleName wikipediaArticleNames] - (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) - ;(catch Exception e (prn "exception"))) - (catch Exception e (-> observer (.onError e)))) - ; after sending response to onNext we complete the sequence - (-> observer .onCompleted))] - ; a subscription that cancels the future if unsubscribed - (Subscriptions/create #(future-cancel f)))))) - -; To see output -(comment - (-> (fetchWikipediaArticleAsynchronouslyWithErrorHandling ["Tiger" "NonExistentTitle" "Elephant"]) - (.subscribe #(println "--- Article ---\n" (subs (:body %) 0 125) "...") - #(println "--- Error ---\n" (.getMessage %))))) - + (rx/action [x] (println "--- Object ---\n" x)) + (rx/action [e] (println "--- Error ---\n" e)) + (rx/action [] (println "--- Completed ---"))))) diff --git a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt index 557e54aad6..3d376be4f4 100644 --- a/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt +++ b/language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples/video_example.txt @@ -1,5 +1,7 @@ (ns rx.lang.clojure.examples.video-example - (:import [rx Observable Observer Subscription] rx.subscriptions.Subscriptions)) + (:require [rx.lang.clojure.interop :as rx]) + (:import [rx Observable Observer Subscription] + rx.subscriptions.Subscriptions)) ; Adapted from language-adaptors/rxjava-groovy/src/examples/groovy/rx/lang/groovy/examples/VideoExample.groovy @@ -21,11 +23,11 @@ ; how progressive rendering could work (println "---- sequence of video dictionaries ----") (-> (get-video-grid-for-display 1) - (.subscribe #(locking print-lock (println %)) - #(locking print-lock (println "Error: " %)) - #(do - (println "Finished example 1") - (on-complete))))) + (.subscribe (rx/action [v] (locking print-lock (println v))) + (rx/action [v] (locking print-lock (println "Error: " v))) + (rx/action [] + (println "Finished example 1") + (on-complete))))) (defn example2 [on-complete] @@ -34,9 +36,9 @@ ; for document style responses (most webservices) (-> (get-video-grid-for-display 1) .toList - (.subscribe #(println "\n ---- single list of video dictionaries ----\n" %) - #(println "Error: " %) - #(do + (.subscribe (rx/action [v] (println "\n ---- single list of video dictionaries ----\n" v)) + (rx/action [v] (println "Error: " v)) + (rx/action [] (println "Finished Example 2") (println "Exiting") (on-complete))))) @@ -61,27 +63,27 @@ " [user-id] (-> (get-list-of-lists user-id) - (.mapMany (fn [list] + (.mapMany (rx/fn [list] ; for each VideoList we want to fetch the videos (-> (video-list->videos list) (.take 10) ; we only want the first 10 of each list - (.mapMany (fn [video] + (.mapMany (rx/fn [video] ; for each video we want to fetch metadata (let [m (-> (video->metadata video) - (.map (fn [md] + (.map (rx/fn [md] ; transform to the data and format we want {:title (:title md) :length (:duration md) }))) b (-> (video->bookmark video user-id) - (.map (fn [position] + (.map (rx/fn [position] {:bookmark position}))) r (-> (video->rating video user-id) - (.map (fn [rating] + (.map (rx/fn [rating] {:rating {:actual (:actual-star-rating rating) :average (:average-star-rating rating) :predicted (:predicted-star-rating rating) }})))] ; join these together into a single, merged map for each video - (Observable/zip m b r (fn [m b r] + (Observable/zip m b r (rx/fn [m b r] (merge {:id video} m b r))))))))))) @@ -91,9 +93,10 @@ "Returns an observable that executes (f observer) in a future, returning a subscription that will cancel the future." [f] - (Observable/create (fn [^Observer observer] + (Observable/create (rx/fn [^Observer observer] + (println "Starting f") (let [f (future (f observer))] - (Subscriptions/create #(future-cancel f)))))) + (Subscriptions/create (rx/action [] (future-cancel f))))))) (defn ^Observable get-list-of-lists " @@ -109,7 +112,8 @@ (.onCompleted observer)))) -(comment (.subscribe (get-list-of-lists 7777) println)) +(comment (.subscribe (get-list-of-lists 7777) + (rx/action* println))) (defn video-list [position] @@ -118,7 +122,7 @@ (defn ^Observable video-list->videos [{:keys [position] :as video-list}] - (Observable/create (fn [^Observer observer] + (Observable/create (rx/fn [^Observer observer] (dotimes [i 50] (.onNext observer (+ (* position 1000) i))) (.onCompleted observer) @@ -128,23 +132,25 @@ (defn ^Observable video->metadata [video-id] - (Observable/create (fn [^Observer observer] + (Observable/create (rx/fn [^Observer observer] (.onNext observer {:title (str "video-" video-id "-title") :actors ["actor1" "actor2"] :duration 5428 }) (.onCompleted observer) (Subscriptions/empty)))) -(comment (.subscribe (video->metadata 10) println)) +(comment (.subscribe (video->metadata 10) (rx/action* println))) (defn ^Observable video->bookmark [video-id user-id] (future-observable (fn [^Observer observer] (Thread/sleep 4) + (println "onNext") (.onNext observer (if (> (rand-int 6) 1) 0 (rand-int 4000))) + (println "onComplete") (.onCompleted observer)))) -(comment (.subscribe (video->bookmark 112345 99999) println)) +(comment (.subscribe (video->bookmark 112345 99999) (rx/action* println))) (defn ^Observable video->rating [video-id user-id] diff --git a/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj b/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj deleted file mode 100644 index bcdebdc3bb..0000000000 --- a/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/DummyClojureClass.clj +++ /dev/null @@ -1,6 +0,0 @@ -(ns rx.lang.clojure.DummyClojureClass) - -(defn hello-world [username] - (println (format "Hello, %s" username))) - -(hello-world "world") diff --git a/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/interop.clj b/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/interop.clj new file mode 100644 index 0000000000..de87e384dc --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/interop.clj @@ -0,0 +1,98 @@ +(ns rx.lang.clojure.interop + "Functions an macros for instantiating rx Func* and Action* interfaces." + (:refer-clojure :exclude [fn])) + +(def ^:private -ns- *ns*) +(set! *warn-on-reflection* true) + +(defmacro ^:private reify-callable + "Reify a bunch of Callable-like interfaces + + prefix fully qualified interface name. numbers will be appended + arities vector of desired arities + f the function to execute + + " + [prefix arities f] + (let [f-name (gensym "rc")] + `(let [~f-name ~f] + (reify + ~@(mapcat (clojure.core/fn [n] + (let [ifc-sym (symbol (str prefix n)) + arg-syms (map #(symbol (str "v" %)) (range n))] + `(~ifc-sym + (~'call ~(vec (cons 'this arg-syms)) + ~(cons f-name arg-syms))))) + arities) )))) + +(defn fn* + "Given function f, returns an object that implements rx.util.functions.Func0-9 + by delegating the call() method to the given function. + + If the f has the wrong arity, an ArityException will be thrown at runtime. + + Example: + + (.reduce my-numbers (rx/fn* +)) + + See: + http://netflix.github.io/RxJava/javadoc/rx/util/functions/Func0.html + " + [f] + (reify-callable "rx.util.functions.Func" [0 1 2 3 4 5 6 7 8 9] f)) + +(defn fnN* + "Given function f, returns an object that implements rx.util.functions.FuncN + by delegating to the given function. + + Unfortunately, this can't be included in fn* because of ambiguities between + the single arg call() method and the var args call method. + + See: + http://netflix.github.io/RxJava/javadoc/rx/util/functions/FuncN.html + " + [f] + (reify rx.util.functions.FuncN + (call [this objects] + (apply f objects)))) + +(defmacro fn + "Like clojure.core/fn, but returns the appropriate rx.util.functions.Func* + interface. + + Example: + + (.map my-observable (rx/fn [a] (* 2 a))) + + " + [& fn-form] + ; have to qualify fn*. Otherwise bad things happen with the fn* special form in clojure + `(rx.lang.clojure.interop/fn* (clojure.core/fn ~@fn-form))) + +(defn action* + "Given function f, returns an object that implements rx.util.functions.Action0-9 + by delegating to the given function. + + Example: + + (.subscribe my-observable (rx/action* println)) + + See: + http://netflix.github.io/RxJava/javadoc/rx/util/functions/Action0.html + " + [f] + (reify-callable "rx.util.functions.Action" [0 1 2 3] f)) + +(defmacro action + "Like clojure.core/fn, but returns the appropriate rx.util.functions.Action* + interface. + + Example: + + (.finallyDo my-observable (rx/action [] (println \"Finally!\"))) + + " + [& fn-form] + `(action* (clojure.core/fn ~@fn-form))) + +;################################################################################ diff --git a/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/interop_test.clj b/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/interop_test.clj new file mode 100644 index 0000000000..72dcadaa6e --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/interop_test.clj @@ -0,0 +1,88 @@ +(ns rx.lang.clojure.interop-test + (:require [rx.lang.clojure.interop :as rx] + [clojure.test :refer [deftest testing is]]) + (:import [rx Observable] + [rx.observables BlockingObservable] + )) + +(deftest test-fn* + (testing "implements Func0-9" + (let [f (rx/fn* vector)] + (is (instance? rx.util.functions.Func0 f)) + (is (instance? rx.util.functions.Func1 f)) + (is (instance? rx.util.functions.Func2 f)) + (is (instance? rx.util.functions.Func3 f)) + (is (instance? rx.util.functions.Func4 f)) + (is (instance? rx.util.functions.Func5 f)) + (is (instance? rx.util.functions.Func6 f)) + (is (instance? rx.util.functions.Func7 f)) + (is (instance? rx.util.functions.Func8 f)) + (is (instance? rx.util.functions.Func9 f)) + (is (= [] (.call f))) + (is (= [1] (.call f 1))) + (is (= [1 2] (.call f 1 2))) + (is (= [1 2 3] (.call f 1 2 3))) + (is (= [1 2 3 4] (.call f 1 2 3 4))) + (is (= [1 2 3 4 5] (.call f 1 2 3 4 5))) + (is (= [1 2 3 4 5 6] (.call f 1 2 3 4 5 6))) + (is (= [1 2 3 4 5 6 7] (.call f 1 2 3 4 5 6 7))) + (is (= [1 2 3 4 5 6 7 8] (.call f 1 2 3 4 5 6 7 8))) + (is (= [1 2 3 4 5 6 7 8 9] (.call f 1 2 3 4 5 6 7 8 9)))))) + +(deftest test-fn + (testing "makes appropriate Func*" + (let [f (rx/fn [a b c] (println "test-fn") (+ a b c))] + (is (= 6 (.call f 1 2 3)))))) + +(deftest test-fnN* + (testing "implements FuncN" + (is (= (vec (range 99)) + (.call (rx/fnN* vector) (into-array Object (range 99))))))) + +(deftest test-action* + (testing "implements Action0-3" + (let [calls (atom []) + a (rx/action* #(swap! calls conj (vec %&)))] + (is (instance? rx.util.functions.Action0 a)) + (is (instance? rx.util.functions.Action1 a)) + (is (instance? rx.util.functions.Action2 a)) + (is (instance? rx.util.functions.Action3 a)) + (.call a) + (.call a 1) + (.call a 1 2) + (.call a 1 2 3) + (is (= [[] [1] [1 2] [1 2 3]]))))) + +(deftest test-action + (testing "makes appropriate Action*" + (let [called (atom nil) + a (rx/action [a b] (reset! called [a b]))] + (.call a 9 10) + (is (= [9 10] @called))))) + +(deftest test-basic-usage + + (testing "can pass rx/fn to map and friends" + (is (= (+ 1 4 9) + (-> (Observable/from [1 2 3]) + (.map (rx/fn [v] (* v v))) + (.reduce (rx/fn* +)) + (BlockingObservable/single))))) + + (testing "can pass rx/action to subscribe and friends" + (let [finally-called (atom nil) + complete-called (promise) + result (atom []) + o (-> (Observable/from ["4" "5" "6"]) + (.map (rx/fn* #(Long/parseLong %))) + (.finallyDo (rx/action [] + (reset! finally-called true))) + (.reduce (rx/fn [a v] (* a v))) + (.subscribe (rx/action [v] (swap! result conj v)) + (rx/action [e]) + (rx/action [] (deliver complete-called true)))) ] + (is (= true @complete-called)) + (is (= true @finally-called)) + (is (= [(* 4 5 6)] @result))))) + +;################################################################################ diff --git a/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/observable_tests.clj b/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/observable_tests.clj deleted file mode 100644 index f0521c2127..0000000000 --- a/language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/observable_tests.clj +++ /dev/null @@ -1,7 +0,0 @@ -(ns rx.lang.clojure.observable-tests - (import rx.Observable)) - -;; still need to get this wired up in build.gradle to run as tests -; (-> (rx.Observable/toObservable ["one" "two" "three"]) (.take 2) (.subscribe (fn [arg] (println arg)))) - -; (-> (rx.Observable/toObservable [1 2 3]) (.takeWhile (fn [x i] (< x 2))) (.subscribe (fn [arg] (println arg))))