From 7f1a9898d1d890ce37f7b4e3be86c2c5711eb510 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Tue, 2 Jul 2013 22:04:09 -0700 Subject: [PATCH 01/13] Make rxjava-core typesafe --- .../java/rx/observables/SwingObservable.java | 2 - rxjava-core/src/main/java/rx/Observable.java | 1164 +---------------- .../rx/observables/BlockingObservable.java | 207 --- .../main/java/rx/subjects/AsyncSubject.java | 11 +- .../main/java/rx/subjects/PublishSubject.java | 30 +- .../main/java/rx/subjects/ReplaySubject.java | 8 +- 6 files changed, 27 insertions(+), 1395 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-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index b93f1621cf..8233b848ed 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -280,7 +280,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(); @@ -288,7 +288,7 @@ public void onCompleted() { } @Override - public void onError(Exception e) { + public void onError(Exception e) { handleError(e); Object onError = callbacks.get("onError"); if (onError != null) { @@ -299,61 +299,17 @@ public void onError(Exception 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(Exception 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"); @@ -389,48 +345,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(Exception 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"); @@ -469,51 +383,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(Exception 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"); @@ -663,49 +532,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 Observer<T>, invokes its - * onNext, onError, and 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. @@ -755,33 +581,6 @@ public static Observable filter(Observable that, Func1 pre return create(OperationFilter.filter(that, predicate)); } - /** - * Filters an Observable by discarding any items it emits that do not meet some test. - *

- * - * - * @param that - * the Observable to filter - * @param function - * a function that evaluates an item emitted by the source Observable, and - * returns true if it passes the filter - * @return an Observable that emits only those items emitted by the source Observable that the - * filter evaluates as 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 meet some test. *

@@ -909,39 +708,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. *

@@ -989,37 +755,6 @@ public static Observable map(Observable sequence, Func1 func) return create(OperationMap.map(sequence, func)); } - /** - * Applies a function of your choosing to every item emitted by an Observable, and emits the - * results of these transformations as its own Observable items. - *

- * - * - * @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 @@ -1048,43 +783,6 @@ public static Observable mapMany(Observable sequence, Func1 - * - *

- * Note: mapMany and 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 - * 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} @@ -1261,36 +959,8 @@ public static Observable flatMap(Observable sequence, Func1 - * - *

- * Note: mapMany and 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 - * 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. + * 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. *

* * @@ -1315,51 +985,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. @@ -1381,38 +1006,6 @@ public R call(T t1) { public static Observable> groupBy(Observable source, final Func1 keySelector) { 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 @@ -1535,45 +1128,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 onErrorResumeNext method changes this behavior. If you pass a - * function that returns an Observable (resumeFunction) to - * onErrorResumeNext, if the source Observable encounters an error, instead of - * invoking its Observer's 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 - * 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 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(Exception 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. @@ -1715,27 +1269,6 @@ public static Observable reduce(Observable sequence, Func2 ac return takeLast(create(OperationScan.scan(sequence, accumulator)), 1); } - /** - * A version of 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 reduce() *

@@ -1747,17 +1280,6 @@ public static Observable aggregate(Observable sequence, Func2 return reduce(sequence, accumulator); } - /** - * A version of 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 @@ -1791,25 +1313,6 @@ public static Observable reduce(Observable sequence, R initialValue return takeLast(create(OperationScan.scan(sequence, initialValue, accumulator)), 1); } - /** - * A version of 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 reduce(). *

@@ -1821,17 +1324,6 @@ public static Observable aggregate(Observable sequence, R initialVa return reduce(sequence, initialValue, accumulator); } - /** - * A version of 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 @@ -1856,27 +1348,6 @@ public static Observable scan(Observable sequence, Func2 accu return create(OperationScan.scan(sequence, accumulator)); } - /** - * A version of 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 @@ -1908,26 +1379,6 @@ public static Observable scan(Observable sequence, R initialValue, return create(OperationScan.scan(sequence, initialValue, accumulator)); } - /** - * A version of 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 Boolean that indicates whether all items emitted by a * source Observable satisfy a condition. @@ -1947,33 +1398,6 @@ public static Observable all(final Observable sequence, final Fu return create(OperationAll.all(sequence, predicate)); } - /** - * Returns an Observable that emits a Boolean 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 true if all items emitted by the source - * Observable satisfy the predicate; otherwise, 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 num items emitted by the source * Observable and emits the remaining items. @@ -2092,31 +1516,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 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 @@ -2136,35 +1535,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 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. *

@@ -2373,34 +1743,8 @@ public static Observable> toSortedList(Observable sequence, Func2 } /** - * Return an Observable that emits the items emitted by the source Observable, in a sorted - * order based on a specified 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 the items from the source Observable in sorted order - */ - 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. + * 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. *

* *

@@ -2474,68 +1818,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. @@ -2568,48 +1850,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. @@ -2644,50 +1884,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); - } - - }); - } - /** * Filters an Observable by discarding any items it emits that do not meet some test. *

@@ -2719,29 +1915,6 @@ public Observable finallyDo(Action0 action) { return create(OperationFinally.finallyDo(this, action)); } - /** - * Filters an Observable by discarding any items it emits that do not meet some test. - *

- * - * - * @param callback - * a function that evaluates an item emitted by the source Observable, returning - * true if it passes the filter - * @return an Observable that emits only those items in the original Observable that the filter - * evaluates as "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 @@ -2763,27 +1936,6 @@ public Observable flatMap(Func1> func) { return mapMany(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 meet some test. *

@@ -2814,30 +1966,6 @@ public Observable map(Func1 func) { return map(this, func); } - /** - * Applies a function of your choosing to each item emitted by an Observable, and returns this - * transformation as a new Observable. - *

- * - * - * @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 @@ -2859,36 +1987,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} @@ -2980,42 +2078,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(Exception 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. @@ -3073,42 +2135,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(Exception 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 @@ -3182,17 +2208,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(). *

@@ -3204,17 +2219,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 @@ -3242,17 +2246,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(). *

@@ -3264,17 +2257,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 @@ -3335,17 +2317,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 @@ -3373,17 +2344,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. @@ -3399,21 +2359,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. @@ -3468,22 +2413,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 @@ -3501,24 +2430,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. @@ -3607,21 +2518,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. *

@@ -3657,28 +2553,6 @@ public Observable startWith(T... values) { public Observable> groupBy(final Func1 keySelector, final Func1 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. - *

- * - * - * @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 @@ -3697,24 +2571,6 @@ public Observable> groupBy(final Object keySelect public Observable> groupBy(final Func1 keySelector) { 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 @@ -4246,10 +3102,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 3ef4dbcebc..62ebdb1854 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(Exception)} 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/subjects/AsyncSubject.java b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java index 5261e4dbdf..5b90a2bbdc 100644 --- a/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/AsyncSubject.java @@ -122,9 +122,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); @@ -144,9 +143,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); @@ -167,9 +165,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); @@ -193,7 +190,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 0714ecfe50..1284af52b4 100644 --- a/rxjava-core/src/main/java/rx/subjects/PublishSubject.java +++ b/rxjava-core/src/main/java/rx/subjects/PublishSubject.java @@ -194,12 +194,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); } }); @@ -244,9 +244,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); @@ -255,7 +254,6 @@ public void testCompleted() { subject.onNext("three"); subject.onCompleted(); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -285,9 +283,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); @@ -296,7 +293,6 @@ public void testError() { subject.onNext("three"); subject.onError(testException); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -319,9 +315,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); @@ -330,7 +325,6 @@ public void testSubscribeMidSequence() { assertObservedUntilTwo(aObserver); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -352,9 +346,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); @@ -364,7 +357,6 @@ public void testUnsubscribeFirstObserver() { subscription.unsubscribe(); assertObservedUntilTwo(aObserver); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -396,9 +388,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); @@ -412,7 +403,6 @@ public void testUnsubscribeAfterOnCompleted() { inOrder.verify(anObserver, times(1)).onCompleted(); inOrder.verify(anObserver, Mockito.never()).onError(any(Exception.class)); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); @@ -425,10 +415,9 @@ public void testUnsubscribeAfterOnCompleted() { @Test public void testUnsubscribeAfterOnError() { - PublishSubject subject = PublishSubject.create(); + PublishSubject subject = PublishSubject.create(); RuntimeException exception = new RuntimeException("failure"); - @SuppressWarnings("unchecked") Observer anObserver = mock(Observer.class); subject.subscribe(anObserver); @@ -442,7 +431,6 @@ public void testUnsubscribeAfterOnError() { inOrder.verify(anObserver, times(1)).onError(exception); inOrder.verify(anObserver, Mockito.never()).onCompleted(); - @SuppressWarnings("unchecked") Observer anotherObserver = mock(Observer.class); subject.subscribe(anotherObserver); diff --git a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java index ff5f2badcc..026ab5df61 100644 --- a/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java +++ b/rxjava-core/src/main/java/rx/subjects/ReplaySubject.java @@ -185,7 +185,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); @@ -222,7 +222,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); @@ -255,7 +255,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); @@ -279,7 +279,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 c93ba88e8bdc797376b0fb9f6ebddf531a9755cb Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 01:39:33 -0700 Subject: [PATCH 02/13] Add Code generator that adapts the core Observable to a dynamic language's native function support * Only hooked up to rxjava-groovy in this commit --- build.gradle | 2 + language-adaptors/codegen/build.gradle | 50 ++++ language-adaptors/codegen/examples.txt | 47 +++ .../java/rx/codegen/ClassPathBasedRunner.java | 48 +++ .../main/java/rx/codegen/CodeGenerator.java | 281 ++++++++++++++++++ language-adaptors/rxjava-clojure/build.gradle | 10 - .../rx/lang/clojure/ClojureActionWrapper.java | 41 +++ .../java/rx/lang/clojure/ClojureAdaptor.java | 59 +--- .../lang/clojure/ClojureFunctionWrapper.java | 58 ++++ language-adaptors/rxjava-groovy/build.gradle | 32 +- .../rx/lang/groovy/GroovyActionWrapper.java | 39 +++ .../java/rx/lang/groovy/GroovyAdaptor.java | 29 +- .../rx/lang/groovy/GroovyFunctionWrapper.java | 58 ++++ .../rx/lang/jruby/JRubyActionWrapper.java | 48 +++ .../main/java/rx/lang/jruby/JRubyAdaptor.java | 23 +- .../rx/lang/jruby/JRubyFunctionWrapper.java | 70 +++++ .../scala/rx/lang/scala/ScalaAdaptor.scala | 9 +- .../java/rx/subscriptions/Subscriptions.java | 17 -- .../main/java/rx/util/functions/Action.java | 10 + .../main/java/rx/util/functions/Action0.java | 2 +- .../main/java/rx/util/functions/Action1.java | 2 +- .../main/java/rx/util/functions/Action2.java | 2 +- .../main/java/rx/util/functions/Action3.java | 2 +- .../functions/FunctionLanguageAdaptor.java | 22 +- .../java/rx/util/functions/Functions.java | 222 ++------------ settings.gradle | 1 + 26 files changed, 861 insertions(+), 323 deletions(-) create mode 100644 language-adaptors/codegen/build.gradle create mode 100644 language-adaptors/codegen/examples.txt create mode 100644 language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java create mode 100644 language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java create mode 100644 language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureActionWrapper.java create mode 100644 language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureFunctionWrapper.java 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-jruby/src/main/java/rx/lang/jruby/JRubyActionWrapper.java create mode 100644 language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyFunctionWrapper.java create mode 100644 rxjava-core/src/main/java/rx/util/functions/Action.java diff --git a/build.gradle b/build.gradle index 9073b716ee..3e8a9cfde7 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,8 @@ apply from: file('gradle/maven.gradle') apply from: file('gradle/license.gradle') apply from: file('gradle/release.gradle') +ext.coreJarDir = new File(rootDir, "/rxjava-core/build/libs").getCanonicalPath() + subprojects { group = "com.netflix.${githubProjectName}" diff --git a/language-adaptors/codegen/build.gradle b/language-adaptors/codegen/build.gradle new file mode 100644 index 0000000000..f97f16ae72 --- /dev/null +++ b/language-adaptors/codegen/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'java' +apply plugin: 'groovy' +apply plugin: 'eclipse' +apply plugin: 'idea' +apply plugin: 'osgi' + +dependencies { + compile project(':rxjava-core') + compile 'org.javassist:javassist:3.17.1-GA' + + provided 'junit:junit:4.10' + provided 'org.mockito:mockito-core:1.8.5' +} + +//task createDynamicallyAdaptedObservable(type: JavaExec) { +// main = 'rx.lang.utils.LanguageAdaptorCodeGenerator' +// classpath = sourceSets.main.runtimeClasspath +// args dynamicClassDir + +// FileTree coreTree = fileTree('../../rxjava-core/src/main').include('**/*.java') +// FileTree adaptorTree = fileTree('src/main').include("**/*.java") +// inputs.files (coreTree + adaptorTree) +//} + +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-language-adaptor-utils' + 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/codegen/examples.txt b/language-adaptors/codegen/examples.txt new file mode 100644 index 0000000000..3cece97b6f --- /dev/null +++ b/language-adaptors/codegen/examples.txt @@ -0,0 +1,47 @@ +Here's the example source of Observable (heavily elided): + +public class rx.Observable { + public static Observable create(Func1, Subscription> func) { + return new Observable(func); + } + + public static Observable create(Object func) { + ... + } + + public static Observable take(final Observable items, final int num) { + return create(OperationTake.take(items, num)); + } + + public static Observable takeWhile(final Observable items, Func1 predicate) { + return create(OperationTakeWhile.takeWhile(items, predicate)); + } + + public Observable filter(Func1 predicate) { + return filter(this, predicate); + } + + public static Observable filter(Observable that, Func1 predicate) { + return create(OperationFilter.filter(that, predicate)); + } +} + +Groovy-friendly version adds: + +public class rx.Observable { + public static rx.Observable create(groovy.lang.Closure func) { + return create(new GroovyFunctionAdaptor(func)); + } + + public static rx.Observable takeWhile(final Observable items, groovy.lang.Closure predicate) { + return takeWhile(items, new GroovyFunctionAdaptor(predicate)); + } + + public rx.Observable filter(groovy.lang.Closure predicate) { + return filter(new GroovyFunctionAdaptor(predicate)); + } + + public static rxObservable filter(Observable that, groovy.lang.Closure predicate) { + return filter(that, new GroovyFunctionAdaptor(predicate)); + } +} diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java b/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java new file mode 100644 index 0000000000..5630724abd --- /dev/null +++ b/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java @@ -0,0 +1,48 @@ +package rx.codegen; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import rx.util.functions.FunctionLanguageAdaptor; + +public class ClassPathBasedRunner { + public static void main(String[] args) { + if (args.length != 2) { + System.out.println("Usage : Expects 2 args: (Language, File to place classfiles)"); + System.out.println("Currently supported languages: Groovy/Clojure/JRuby"); + System.exit(1); + } + String lang = args[0]; + File dir = new File(args[1]); + System.out.println("Looking for Adaptor for : " + lang); + String className = "rx.lang." + lang.toLowerCase() + "." + lang + "Adaptor"; + try { + Class adaptorClass = Class.forName(className); + System.out.println("Found Adaptor : " + adaptorClass); + FunctionLanguageAdaptor adaptor = (FunctionLanguageAdaptor) adaptorClass.newInstance(); + + CodeGenerator codeGen = new CodeGenerator(); + System.out.println("Using dir : " + dir + " for outputting classfiles"); + for (Class observableClass: getObservableClasses()) { + codeGen.addMethods(observableClass, adaptor, new File(args[1])); + } + } catch (ClassNotFoundException ex) { + System.out.println("Did not find adaptor class : " + className); + System.exit(1); + } catch (InstantiationException ex) { + System.out.println("Reflective constuctor on : " + className + " failed"); + System.exit(1); + } catch (IllegalAccessException ex) { + System.out.println("Access to constructor on : " + className + " failed"); + System.exit(1); + } + } + + private static List> getObservableClasses() { + List> observableClasses = new ArrayList>(); + observableClasses.add(rx.Observable.class); + observableClasses.add(rx.observables.BlockingObservable.class); + return observableClasses; + } +} \ No newline at end of file diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java new file mode 100644 index 0000000000..a67bff1714 --- /dev/null +++ b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java @@ -0,0 +1,281 @@ +package rx.codegen; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.NotFoundException; +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; +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.Func5; +import rx.util.functions.Func6; +import rx.util.functions.Func7; +import rx.util.functions.Func8; +import rx.util.functions.Func9; +import rx.util.functions.Function; +import rx.util.functions.FunctionLanguageAdaptor; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import org.junit.Test; + +public class CodeGenerator { + + static ClassPool pool = ClassPool.getDefault(); + + public void addMethods(Class initialClass, FunctionLanguageAdaptor adaptor, File file) { + Set> nativeFunctionClasses = adaptor.getAllClassesToRewrite(); + System.out.println("Adding dynamic language support to : " + initialClass.getSimpleName()); + for (Class nativeFunctionClass: nativeFunctionClasses) { + System.out.println(" * Adding : " + nativeFunctionClass.getName()); + } + addSupportFor(initialClass, adaptor, file); + } + + private static void addSupportFor(Class observableClass, FunctionLanguageAdaptor adaptor, File file) { + CtClass clazz; + + if (!observableClass.getName().startsWith("rx.")) { + throw new IllegalStateException("Refusing to rewrite a class that is not a core Rx Observable!"); + } + + Set> nativeFunctionClasses = adaptor.getAllClassesToRewrite(); + + try { + clazz = pool.get(observableClass.getName()); + } catch (NotFoundException e) { + throw new RuntimeException("Failed to add language adaptor methods as could not find observable Class named " + observableClass.getName(), e); + } + try { + rewriteMethodsWithRxArgs(clazz, adaptor); + + for (CtMethod cm: clazz.getMethods()) { + System.out.println(cm.getName() + " : " + cm.getSignature() + " : " + cm.getDeclaringClass().getName()); + } + + writeClassFile(clazz, file); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to add language adaptor methods.", e); + } + } + + private static void rewriteMethodsWithRxArgs(CtClass clazz, FunctionLanguageAdaptor adaptor) throws Exception { + List newMethods = new ArrayList(); + + for (CtMethod method : clazz.getMethods()) { + CtClass[] argTypes = method.getParameterTypes(); + boolean needsRewrite = false; + for (CtClass argType : argTypes) { + if (isRxFunctionType(argType) || isRxActionType(argType)) { + needsRewrite = true; + } + } + if (needsRewrite) { + try { + newMethods.addAll(getRewrittenMethods(clazz, method, adaptor)); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to add language adaptor method: " + method.getName(), e); + } + } + } + + for (CtMethod cm: newMethods) { + clazz.addMethod(cm); + } + } + + private static boolean isNativeFunctionType(CtClass type, Set> nativeFunctionClasses) { + for (Class nativeFunctionClass: nativeFunctionClasses) { + if (type.getName().equals(nativeFunctionClass.getName())) { + return true; + } + } + return false; + } + + private static boolean isRxFunctionType(CtClass type) throws Exception { + return implementsInterface(type, Function.class); + } + + private static boolean isRxActionType(CtClass type) throws Exception { + return implementsInterface(type, Action.class); + } + + private static boolean implementsInterface(CtClass type, Class interfaceClass) throws Exception { + // Did I pass in the exact interface? + if (type.getName().equals(interfaceClass.getName())) { + return true; + } + // Do I implement the interface? + for (CtClass implementedInterface : type.getInterfaces()) { + if (implementedInterface.getName().equals(interfaceClass.getName())) { + return true; + } + } + return false; + } + + private static List getRewrittenMethods(CtClass clazz, CtMethod method, FunctionLanguageAdaptor adaptor) throws Exception { + List newMethods = new ArrayList(); + + for (Class nativeFunctionClass: adaptor.getAllClassesToRewrite()) { + Class functionAdaptorClass = adaptor.getFunctionClassRewritingMap().get(nativeFunctionClass); + Class actionAdaptorClass = adaptor.getActionClassRewritingMap().get(nativeFunctionClass); + ArrayList parameters = new ArrayList(); + CtClass[] argTypes = method.getParameterTypes(); + + ArrayList initialArgTypes = new ArrayList(); + ArrayList finalArgTypes = new ArrayList(); + + for (CtClass argType : argTypes) { + initialArgTypes.add(argType.getName()); + if (isRxFunctionType(argType) || isRxActionType(argType)) { + // needs conversion + finalArgTypes.add(nativeFunctionClass.getName()); + parameters.add(pool.get(nativeFunctionClass.getName())); + } else { + // no conversion, copy through + finalArgTypes.add(argType.getName()); + parameters.add(argType); + } + } + + String initialArgString = makeArgList(initialArgTypes); + String finalArgString = makeArgList(finalArgTypes); + + CtClass[] oldParameters = parameters.toArray(new CtClass[parameters.size()]); + CtMethod newMethod = new CtMethod(method.getReturnType(), method.getName(), oldParameters, clazz); + newMethod.setModifiers(method.getModifiers()); + List argumentList = new ArrayList(); + StringBuffer newBody = new StringBuffer(); + newBody.append("{ return "); + newBody.append(method.getName()); + newBody.append("("); + for (int i = 0; i < method.getParameterTypes().length; i++) { + CtClass argType = method.getParameterTypes()[i]; + if (isRxActionType(argType) && actionAdaptorClass != null) { + argumentList.add(getAdaptedArg(actionAdaptorClass, i + 1)); + } else if (isRxFunctionType(argType) && functionAdaptorClass != null) { + argumentList.add(getAdaptedArg(functionAdaptorClass, i + 1)); + } else { + argumentList.add(getUntouchedArg(i + 1)); + } + } + newBody.append(makeArgList(argumentList)); + newBody.append(")"); + newBody.append(";}"); + System.out.println(method.getReturnType().getName() + " " + method.getName() + "(" + initialArgString + ") --> " + newMethod.getReturnType().getName() + " " + newMethod.getName() + "(" + finalArgString + ")"); + System.out.println(" " + newBody.toString()); + newMethod.setBody(newBody.toString()); + newMethods.add(newMethod); + } + return newMethods; + } + + private static String getAdaptedArg(Class adaptorClass, int index) { + StringBuffer buffer = new StringBuffer(); + buffer.append("new "); + buffer.append(adaptorClass.getName()); + buffer.append("("); + buffer.append(getUntouchedArg(index)); + buffer.append(")"); + return buffer.toString(); + } + + private static String getUntouchedArg(int index) { + StringBuffer buffer = new StringBuffer(); + buffer.append("$"); + buffer.append(index); + return buffer.toString(); + } + + private static String makeArgList(List args) { + if (args.size() > 0) { + StringBuffer buffer = new StringBuffer(args.get(0)); + for (String arg: args.subList(1, args.size())) { + buffer.append("," + arg); + } + return buffer.toString(); + } + return ""; + } + + private static void writeClassFile(CtClass clazz, File dir) { + try { + System.out.println("Using " + dir.getCanonicalPath() + " for dynamic class file"); + clazz.writeFile(dir.getCanonicalPath()); + } catch (java.io.IOException ioe) { + System.out.println("Could not write classfile to : " + dir.toString()); + System.exit(1); + } catch (javassist.CannotCompileException cce) { + System.out.println("Could not create a valid classfile"); + System.exit(2); + } + } + + public static class UnitTest { + @Test + public void testIsRxFunctionType() { + try { + assertTrue(isRxFunctionType(pool.get(Function.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func0.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func1.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func2.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func3.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func4.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func5.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func6.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func7.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func8.class.getName()))); + assertTrue(isRxFunctionType(pool.get(Func9.class.getName()))); + assertFalse(isRxFunctionType(pool.get(Action.class.getName()))); + assertFalse(isRxFunctionType(pool.get(Action0.class.getName()))); + assertFalse(isRxFunctionType(pool.get(Action1.class.getName()))); + assertFalse(isRxFunctionType(pool.get(Action2.class.getName()))); + assertFalse(isRxFunctionType(pool.get(Action3.class.getName()))); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + public void testIsRxActionType() { + try { + assertFalse(isRxActionType(pool.get(Function.class.getName()))); + assertFalse(isRxActionType(pool.get(Func0.class.getName()))); + assertFalse(isRxActionType(pool.get(Func1.class.getName()))); + assertFalse(isRxActionType(pool.get(Func2.class.getName()))); + assertFalse(isRxActionType(pool.get(Func3.class.getName()))); + assertFalse(isRxActionType(pool.get(Func4.class.getName()))); + assertFalse(isRxActionType(pool.get(Func5.class.getName()))); + assertFalse(isRxActionType(pool.get(Func6.class.getName()))); + assertFalse(isRxActionType(pool.get(Func7.class.getName()))); + assertFalse(isRxActionType(pool.get(Func8.class.getName()))); + assertFalse(isRxActionType(pool.get(Func9.class.getName()))); + assertTrue(isRxActionType(pool.get(Action.class.getName()))); + assertTrue(isRxActionType(pool.get(Action0.class.getName()))); + assertTrue(isRxActionType(pool.get(Action1.class.getName()))); + assertTrue(isRxActionType(pool.get(Action2.class.getName()))); + assertTrue(isRxActionType(pool.get(Action3.class.getName()))); + } catch (Exception e) { + fail(e.getMessage()); + } + } + } +} + diff --git a/language-adaptors/rxjava-clojure/build.gradle b/language-adaptors/rxjava-clojure/build.gradle index 0ea7feb27c..7b2c8275c4 100644 --- a/language-adaptors/rxjava-clojure/build.gradle +++ b/language-adaptors/rxjava-clojure/build.gradle @@ -52,16 +52,6 @@ idea { } -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} - // include /src/examples folder sourceSets { examples diff --git a/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureActionWrapper.java b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureActionWrapper.java new file mode 100644 index 0000000000..38d4dd64a8 --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureActionWrapper.java @@ -0,0 +1,41 @@ +/** + * 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 rx.util.functions.Action0; +import rx.util.functions.Action1; + +import clojure.lang.IFn; +import clojure.lang.RT; +import clojure.lang.Var; + +public class ClojureActionWrapper implements Action0, Action1 { + private IFn ifn; + + public ClojureActionWrapper(IFn ifn) { + this.ifn = ifn; + } + + @Override + public void call() { + ifn.invoke(); + } + + @Override + public void call(T1 t1) { + ifn.invoke(t1); + } +} \ No newline at end of file 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 index 4420f7c919..594ee51802 100644 --- 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 @@ -15,7 +15,8 @@ */ package rx.lang.clojure; -import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -32,57 +33,17 @@ 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)); - } + public Map, Class> getFunctionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(IFn.class, ClojureFunctionWrapper.class); + return m; } @Override - public Class[] getFunctionClass() { - return new Class[] { IFn.class }; + public Map, Class> getActionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(IFn.class, ClojureActionWrapper.class); + return m; } public static class UnitTest { diff --git a/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureFunctionWrapper.java b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureFunctionWrapper.java new file mode 100644 index 0000000000..1aed83fc7e --- /dev/null +++ b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureFunctionWrapper.java @@ -0,0 +1,58 @@ +/** + * 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 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.FunctionLanguageAdaptor; + +import clojure.lang.IFn; + +public class ClojureFunctionWrapper implements Func0, Func1, Func2, Func3, Func4 { + private IFn ifn; + + public ClojureFunctionWrapper(IFn ifn) { + this.ifn = ifn; + } + + @Override + public R call() { + return (R) ifn.invoke(); + } + + @Override + public R call(T1 t1) { + return (R) ifn.invoke(t1); + } + + @Override + public R call(T1 t1, T2 t2) { + return (R) ifn.invoke(t1, t2); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3) { + return (R) ifn.invoke(t1, t2, t3); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3, T4 t4) { + return (R) ifn.invoke(t1, t2, t3, t4); + } +} \ No newline at end of file diff --git a/language-adaptors/rxjava-groovy/build.gradle b/language-adaptors/rxjava-groovy/build.gradle index 91c060193d..5164254586 100644 --- a/language-adaptors/rxjava-groovy/build.gradle +++ b/language-adaptors/rxjava-groovy/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'osgi' dependencies { compile project(':rxjava-core') + compile project(':language-adaptors:codegen') groovy 'org.codehaus.groovy:groovy-all:2.+' provided 'junit:junit-dep:4.10' provided 'org.mockito:mockito-core:1.8.5' @@ -24,6 +25,33 @@ configurations { // include 'examples' in build task build.dependsOn examplesClasses +test.dependsOn jar + +task createAdaptedObservable(type: JavaExec) { + main = 'rx.codegen.ClassPathBasedRunner' + classpath = sourceSets.main.runtimeClasspath + args = ["Groovy", sourceSets.main.output.classesDir] +} + +task jar(overwrite: true, type: Jar, dependsOn: "createAdaptedObservable") { + description = 'Copies the RxJava core JAR and replaces Observable with Groovy-friendly versions.' + destinationDir = jar.archivePath.getParentFile() + archiveName = baseName + "-" + version + "." + extension + + from (zipTree(coreJarDir + "/rxjava-core-" + version + ".jar")) { + exclude "rx/Observable.class" + exclude "rx/observables/BlockingObservable.class" + } + from (sourceSets.main.output.classesDir) { + include "rx/Observable.class" + include "rx/observables/BlockingObservable.class" + } + + /* manifest { + name = 'rxjava-core' + attributes('Bundle-Vendor': 'Netflix', 'Bundle-DocURL': 'https://github.com/Netflix/RxJava', 'Import-Package': '!org.junit,!junit.framework,!org.mockito.*,*') + }*/ +} eclipse { classpath { @@ -42,7 +70,7 @@ idea { } } -jar { +/*jar { manifest { name = 'rxjava-groovy' instruction 'Bundle-Vendor', 'Netflix' @@ -50,4 +78,4 @@ jar { instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' instruction 'Fragment-Host', 'com.netflix.rxjava.core' } -} \ No newline at end of file +}*/ \ No newline at end of file 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..a831a0ed42 --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyActionWrapper.java @@ -0,0 +1,39 @@ +/** + * 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 rx.util.functions.Action0; +import rx.util.functions.Action1; + +import groovy.lang.Closure; + +public class GroovyActionWrapper implements Action0, Action1 { + private Closure closure; + + public GroovyActionWrapper(Closure closure) { + this.closure = closure; + } + + @Override + public void call() { + closure.call(); + } + + @Override + public void call(T1 t1) { + closure.call(t1); + } +} \ No newline at end of file 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 index 70cef9c18e..530a7d2d63 100644 --- 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 @@ -15,17 +15,36 @@ */ package rx.lang.groovy; -import groovy.lang.Closure; +import java.util.HashMap; +import java.util.Map; + import rx.util.functions.FunctionLanguageAdaptor; +import groovy.lang.Closure; + +import java.util.HashSet; +import java.util.Set; + public class GroovyAdaptor implements FunctionLanguageAdaptor { @Override - public Object call(Object function, Object[] args) { - return ((Closure) function).call(args); + public Map, Class> getFunctionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(Closure.class, GroovyFunctionWrapper.class); + return m; } - public Class[] getFunctionClass() { - return new Class[] { Closure.class }; + @Override + public Map, Class> getActionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(Closure.class, GroovyActionWrapper.class); + return m; + } + + @Override + public Set> getAllClassesToRewrite() { + Set> groovyClasses = new HashSet>(); + groovyClasses.add(Closure.class); + return groovyClasses; } } 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..1b038fd1ba --- /dev/null +++ b/language-adaptors/rxjava-groovy/src/main/java/rx/lang/groovy/GroovyFunctionWrapper.java @@ -0,0 +1,58 @@ +/** + * 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 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.FunctionLanguageAdaptor; + +import groovy.lang.Closure; + +public class GroovyFunctionWrapper implements Func0, Func1, Func2, Func3, Func4 { + private 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-jruby/src/main/java/rx/lang/jruby/JRubyActionWrapper.java b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyActionWrapper.java new file mode 100644 index 0000000000..ada202eaf1 --- /dev/null +++ b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyActionWrapper.java @@ -0,0 +1,48 @@ +/** + * 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 org.jruby.Ruby; +import org.jruby.RubyProc; +import org.jruby.javasupport.JavaEmbedUtils; +import org.jruby.runtime.builtin.IRubyObject; + +import rx.util.functions.Action0; +import rx.util.functions.Action1; +import rx.util.functions.FunctionLanguageAdaptor; + +public class JRubyActionWrapper implements Action0, Action1 { + private RubyProc proc; + + public JRubyActionWrapper(RubyProc proc) { + this.proc = proc; + } + + @Override + public void call() { + Ruby ruby = proc.getRuntime(); + IRubyObject[] rubyArgs = new IRubyObject[0]; + proc.getBlock().call(ruby.getCurrentContext(), rubyArgs); + } + + @Override + public void call(T1 t1) { + Ruby ruby = proc.getRuntime(); + IRubyObject[] rubyArgs = new IRubyObject[1]; + rubyArgs[0] = JavaEmbedUtils.javaToRuby(ruby, t1); + proc.getBlock().call(ruby.getCurrentContext(), rubyArgs); + } +} \ 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 index d66dc16acf..1b6b71abe0 100644 --- 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 @@ -19,12 +19,11 @@ import static org.mockito.Mockito.*; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; -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; @@ -40,19 +39,17 @@ 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); + public Map, Class> getFunctionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(RubyProc.class, JRubyFunctionWrapper.class); + return m; } @Override - public Class[] getFunctionClass() { - return new Class[] { RubyProc.class }; + public Map, Class> getActionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(RubyProc.class, JRubyActionWrapper.class); + return m; } public static class UnitTest { diff --git a/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyFunctionWrapper.java b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyFunctionWrapper.java new file mode 100644 index 0000000000..c3e78957cb --- /dev/null +++ b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyFunctionWrapper.java @@ -0,0 +1,70 @@ +/** + * 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 org.jruby.Ruby; +import org.jruby.RubyProc; +import org.jruby.javasupport.JavaEmbedUtils; +import org.jruby.runtime.builtin.IRubyObject; + +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.FunctionLanguageAdaptor; + +public class JRubyFunctionWrapper implements Func0, Func1, Func2, Func3, Func4 { + private RubyProc proc; + + public JRubyFunctionWrapper(RubyProc proc) { + this.proc = proc; + } + + @Override + public R call() { + return (R) callRubyProc(); + } + + @Override + public R call(T1 t1) { + return (R) callRubyProc(t1); + } + + @Override + public R call(T1 t1, T2 t2) { + return (R) callRubyProc(t1, t2); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3) { + return (R) callRubyProc(t1, t2, t3); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3, T4 t4) { + return (R) callRubyProc(t1, t2, t3, t4); + } + + private Object callRubyProc(Object... args) { + Ruby ruby = proc.getRuntime(); + IRubyObject[] rubyArgs = new IRubyObject[args.length]; + for (int i = 0; i < args.length; i++) { + rubyArgs[i] = JavaEmbedUtils.javaToRuby(ruby, args[i]); + } + return (R) proc.getBlock().call(ruby.getCurrentContext(), rubyArgs); + } +} \ No newline at end of file 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 index 12418d516d..d2d2138976 100644 --- 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 @@ -53,14 +53,7 @@ class ScalaAdaptor extends FunctionLanguageAdaptor { 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 = { + private def matchOption(funcOption: Option[_], args: Array[AnyRef]) : Object = { funcOption match { case Some(func: AnyRef) => return matchFunction(func, args) case _ => return None diff --git a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java index 1db0b7a660..41055f0672 100644 --- a/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java +++ b/rxjava-core/src/main/java/rx/subscriptions/Subscriptions.java @@ -79,23 +79,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 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..832b78dd52 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 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..68c1b804ed 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 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..ba4826bdca 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 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..3c2b083c6f 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 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/FunctionLanguageAdaptor.java b/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java index 6ec87f358a..9e471e7329 100644 --- a/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java +++ b/rxjava-core/src/main/java/rx/util/functions/FunctionLanguageAdaptor.java @@ -15,16 +15,10 @@ */ package rx.util.functions; -public interface FunctionLanguageAdaptor { +import java.util.Map; +import java.util.Set; - /** - * Invoke the function and return the results. - * - * @param function - * @param args - * @return Object results from function execution - */ - Object call(Object function, Object[] args); +public interface FunctionLanguageAdaptor { /** * The Class of the Function that this adaptor serves. @@ -35,5 +29,13 @@ public interface FunctionLanguageAdaptor { * * @return Class[] of classes that this adaptor should be invoked for. */ - public Class[] getFunctionClass(); + //public Class[] getFunctionClass(); + + //TODO MRJ: Add Javadoc + public Map, Class> getActionClassRewritingMap(); + + //TODO MRJ: Add Javadoc + public Map, Class> getFunctionClassRewritingMap(); + + public Set> getAllClassesToRewrite(); } 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 53671c210d..42af15cf17 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Functions.java +++ b/rxjava-core/src/main/java/rx/util/functions/Functions.java @@ -15,207 +15,11 @@ */ package rx.util.functions; -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)}. + * Utility class for getting concrete implementations of Functions/Actions */ 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 (Exception 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. - * - * @param function - */ - @SuppressWarnings({ "rawtypes" }) - public static FuncN from(final Object 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); - } 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 @@ -241,19 +45,27 @@ private static FuncN fromFunction(Function function) { return fromFunc((Func9) function); } else if (function instanceof FuncN) { return (FuncN) function; - } else if (function instanceof Action0) { - return fromAction((Action0) function); - } else if (function instanceof Action1) { - return fromAction((Action1) function); - } else if (function instanceof Action2) { - return fromAction((Action2) function); - } else if (function instanceof Action3) { - return fromAction((Action3) function); } throw new RuntimeException("Unknown implementation of Function: " + function.getClass().getSimpleName()); } + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static FuncN fromAction(Action action) { + // check Action* classes + if (action instanceof Action0) { + return fromAction((Action0) action); + } else if (action instanceof Action1) { + return fromAction((Action1) action); + } else if (action instanceof Action2) { + return fromAction((Action2) action); + } else if (action instanceof Action3) { + return fromAction((Action3) action); + } + + throw new RuntimeException("Unknown implementation of Action: " + action.getClass().getSimpleName()); + } + /** * Convert a function to FuncN to allow heterogeneous handling of functions with different arities. * diff --git a/settings.gradle b/settings.gradle index f07f904404..d6cc324181 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,5 @@ include 'rxjava-core', \ 'language-adaptors:rxjava-jruby', \ 'language-adaptors:rxjava-clojure', \ 'language-adaptors:rxjava-scala', \ +'language-adaptors:codegen', \ 'rxjava-contrib:rxjava-swing' From bbedef284e27adfc91526deff109aec2f8998a4c Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 09:22:21 -0700 Subject: [PATCH 03/13] Clean up rxjava-groovy Gradle build --- build.gradle | 57 ++++++++++++--- language-adaptors/codegen/build.gradle | 13 +--- .../main/java/rx/codegen/CodeGenerator.java | 5 -- language-adaptors/rxjava-groovy/build.gradle | 69 +++++-------------- 4 files changed, 66 insertions(+), 78 deletions(-) diff --git a/build.gradle b/build.gradle index 3e8a9cfde7..85d83ea12d 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,22 +15,55 @@ 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') - -ext.coreJarDir = new File(rootDir, "/rxjava-core/build/libs").getCanonicalPath() - subprojects { + apply plugin: 'java' + apply plugin: 'eclipse' + apply plugin: 'idea' + apply plugin: 'osgi' group = "com.netflix.${githubProjectName}" - sourceSets.test.java.srcDir 'src/main/java' + ext.coreJarDir = new File(rootDir, "/rxjava-core/build/libs").getCanonicalPath() + ext.outputDir = file("build/rewritten_classes") + + // make 'examples' use the same classpath + configurations { + core + examplesCompile.extendsFrom compile + examplesRuntime.extendsFrom runtime + } + + sourceSets.test.java.srcDirs.add('src/main/java') tasks.withType(Javadoc).each { it.classpath = sourceSets.main.compileClasspath } + + sourceSets { + //include /src/examples folder + 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/language-adaptors/codegen/build.gradle b/language-adaptors/codegen/build.gradle index f97f16ae72..7967131270 100644 --- a/language-adaptors/codegen/build.gradle +++ b/language-adaptors/codegen/build.gradle @@ -9,19 +9,8 @@ dependencies { compile 'org.javassist:javassist:3.17.1-GA' provided 'junit:junit:4.10' - provided 'org.mockito:mockito-core:1.8.5' } -//task createDynamicallyAdaptedObservable(type: JavaExec) { -// main = 'rx.lang.utils.LanguageAdaptorCodeGenerator' -// classpath = sourceSets.main.runtimeClasspath -// args dynamicClassDir - -// FileTree coreTree = fileTree('../../rxjava-core/src/main').include('**/*.java') -// FileTree adaptorTree = fileTree('src/main').include("**/*.java") -// inputs.files (coreTree + adaptorTree) -//} - eclipse { classpath { // include 'provided' dependencies on the classpath @@ -41,7 +30,7 @@ idea { jar { manifest { - name = 'rxjava-language-adaptor-utils' + name = 'rxjava-codegen' instruction 'Bundle-Vendor', 'Netflix' instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava' instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java index a67bff1714..02d17d793d 100644 --- a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java +++ b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java @@ -61,11 +61,6 @@ private static void addSupportFor(Class observableClass, FunctionLanguageAdap } try { rewriteMethodsWithRxArgs(clazz, adaptor); - - for (CtMethod cm: clazz.getMethods()) { - System.out.println(cm.getName() + " : " + cm.getSignature() + " : " + cm.getDeclaringClass().getName()); - } - writeClassFile(clazz, file); } catch (Exception e) { e.printStackTrace(); diff --git a/language-adaptors/rxjava-groovy/build.gradle b/language-adaptors/rxjava-groovy/build.gradle index 5164254586..fedb8bf395 100644 --- a/language-adaptors/rxjava-groovy/build.gradle +++ b/language-adaptors/rxjava-groovy/build.gradle @@ -1,10 +1,7 @@ -apply plugin: 'java' apply plugin: 'groovy' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'osgi' dependencies { + core project(':rxjava-core') compile project(':rxjava-core') compile project(':language-adaptors:codegen') groovy 'org.codehaus.groovy:groovy-all:2.+' @@ -12,65 +9,33 @@ dependencies { provided 'org.mockito:mockito-core:1.8.5' } -// include /src/examples folder -sourceSets { - examples -} +task createAdaptedObservable(type: JavaExec) { + main = 'rx.codegen.ClassPathBasedRunner' + classpath = sourceSets.main.runtimeClasspath + args = ["Groovy", outputDir] -// make 'examples' use the same classpath -configurations { - examplesCompile.extendsFrom compile - examplesRuntime.extendsFrom runtime + inputs.files(sourceSets.main.runtimeClasspath) + outputs.dir(outputDir) } -// include 'examples' in build task -build.dependsOn examplesClasses -test.dependsOn jar +tasks.test { + dependsOn(createAdaptedObservable) -task createAdaptedObservable(type: JavaExec) { - main = 'rx.codegen.ClassPathBasedRunner' - classpath = sourceSets.main.runtimeClasspath - args = ["Groovy", sourceSets.main.output.classesDir] + //Reorders the classpath so that the newly-create Observables win + classpath = createAdaptedObservable.outputs.files + sourceSets.test.runtimeClasspath } -task jar(overwrite: true, type: Jar, dependsOn: "createAdaptedObservable") { - description = 'Copies the RxJava core JAR and replaces Observable with Groovy-friendly versions.' - destinationDir = jar.archivePath.getParentFile() - archiveName = baseName + "-" + version + "." + extension +tasks.jar { + dependsOn(createAdaptedObservable) - from (zipTree(coreJarDir + "/rxjava-core-" + version + ".jar")) { + from (zipTree(configurations.core.singleFile)) { exclude "rx/Observable.class" exclude "rx/observables/BlockingObservable.class" - } - from (sourceSets.main.output.classesDir) { - include "rx/Observable.class" - include "rx/observables/BlockingObservable.class" } + from(outputDir) - /* manifest { - name = 'rxjava-core' - attributes('Bundle-Vendor': 'Netflix', 'Bundle-DocURL': 'https://github.com/Netflix/RxJava', 'Import-Package': '!org.junit,!junit.framework,!org.mockito.*,*') - }*/ -} - -eclipse { - classpath { - // include 'provided' dependencies on the classpath - plusConfigurations += configurations.provided - - downloadSources = true - downloadJavadoc = true - } -} + exclude('**/*$UnitTest*') -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } -} - -/*jar { manifest { name = 'rxjava-groovy' instruction 'Bundle-Vendor', 'Netflix' @@ -78,4 +43,4 @@ idea { instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*' instruction 'Fragment-Host', 'com.netflix.rxjava.core' } -}*/ \ No newline at end of file +} From 698508f39e7c65192bd0fbac98363a7796c1133f Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 16:04:35 -0700 Subject: [PATCH 04/13] Get rxjava-clojure build working in Gradle --- language-adaptors/rxjava-clojure/build.gradle | 58 +++++++++---------- .../java/rx/lang/clojure/ClojureAdaptor.java | 9 +++ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/language-adaptors/rxjava-clojure/build.gradle b/language-adaptors/rxjava-clojure/build.gradle index 7b2c8275c4..78cc056b41 100644 --- a/language-adaptors/rxjava-clojure/build.gradle +++ b/language-adaptors/rxjava-clojure/build.gradle @@ -1,17 +1,13 @@ -apply plugin: 'java' apply plugin: 'clojure' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'osgi' dependencies { + core project(':rxjava-core') compile project(':rxjava-core') - provided 'org.clojure:clojure:1.4.+' + compile project(':language-adaptors:codegen') + compile 'org.clojure:clojure:1.4.+' + compile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http 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 } /* @@ -26,47 +22,45 @@ buildscript { } repositories { - mavenCentral() clojarsRepo() } /* - * Add Counterclockwise and include 'provided' dependencies + * Add Counterclockwise to Eclipse */ 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 - } +task createAdaptedObservable(type: JavaExec) { + main = 'rx.codegen.ClassPathBasedRunner' + classpath = sourceSets.main.runtimeClasspath + args = ["Clojure", outputDir] + + inputs.files(sourceSets.main.runtimeClasspath) + outputs.dir(outputDir) } +tasks.test { + dependsOn(createAdaptedObservable) -// include /src/examples folder -sourceSets { - examples + //Reorders the classpath so that the newly-create Observables win + classpath = createAdaptedObservable.outputs.files + sourceSets.test.runtimeClasspath } -// make 'examples' use the same classpath -configurations { - examplesCompile.extendsFrom compile - examplesRuntime.extendsFrom runtime -} +tasks.jar { + dependsOn(createAdaptedObservable) -// include 'examples' in build task -build.dependsOn examplesClasses + from (zipTree(configurations.core.singleFile)) { + exclude "rx/Observable.class" + exclude "rx/observables/BlockingObservable.class" + } + from(outputDir) + + exclude('**/*$UnitTest*') -jar { manifest { name = 'rxjava-clojure' instruction 'Bundle-Vendor', 'Netflix' @@ -74,4 +68,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/main/java/rx/lang/clojure/ClojureAdaptor.java b/language-adaptors/rxjava-clojure/src/main/java/rx/lang/clojure/ClojureAdaptor.java index 594ee51802..31cff79786 100644 --- 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 @@ -16,7 +16,9 @@ package rx.lang.clojure; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.junit.Before; import org.junit.Test; @@ -46,6 +48,13 @@ public Map, Class> getActionClassRewritingMap() { return m; } + @Override + public Set> getAllClassesToRewrite() { + Set> classes = new HashSet>(); + classes.add(IFn.class); + return classes; + } + public static class UnitTest { @Mock From 5ac401dedd9ba1402179ae3e47adaa647033d33a Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 16:19:03 -0700 Subject: [PATCH 05/13] Get rxjava-jruby build working in Gradle --- language-adaptors/rxjava-jruby/build.gradle | 44 +++++++++++-------- .../main/java/rx/lang/jruby/JRubyAdaptor.java | 9 ++++ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/language-adaptors/rxjava-jruby/build.gradle b/language-adaptors/rxjava-jruby/build.gradle index cf7d9533e2..f4aaf194cf 100644 --- a/language-adaptors/rxjava-jruby/build.gradle +++ b/language-adaptors/rxjava-jruby/build.gradle @@ -1,33 +1,39 @@ -apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'osgi' - dependencies { + core project(':rxjava-core') compile project(':rxjava-core') - provided 'org.jruby:jruby:1.6+' + compile project(':language-adaptors:codegen') + compile '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 +task createAdaptedObservable(type: JavaExec) { + main = 'rx.codegen.ClassPathBasedRunner' + classpath = sourceSets.main.runtimeClasspath + args = ["JRuby", outputDir] - downloadSources = true - downloadJavadoc = true - } + inputs.files(sourceSets.main.runtimeClasspath) + outputs.dir(outputDir) } -idea { - module { - // include 'provided' dependencies on the classpath - scopes.PROVIDED.plus += configurations.provided - } +tasks.test { + dependsOn(createAdaptedObservable) + + //Reorders the classpath so that the newly-create Observables win + classpath = createAdaptedObservable.outputs.files + sourceSets.test.runtimeClasspath } -jar { +tasks.jar { + dependsOn(createAdaptedObservable) + + from (zipTree(configurations.core.singleFile)) { + exclude "rx/Observable.class" + exclude "rx/observables/BlockingObservable.class" + } + from(outputDir) + + exclude('**/*$UnitTest*') + manifest { name = 'rxjava-jruby' instruction 'Bundle-Vendor', 'Netflix' 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 index 1b6b71abe0..f210d64917 100644 --- 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 @@ -20,7 +20,9 @@ import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import org.jruby.RubyProc; import org.jruby.embed.ScriptingContainer; @@ -52,6 +54,13 @@ public Map, Class> getActionClassRewritingMap() { return m; } + @Override + public Set> getAllClassesToRewrite() { + Set> classes = new HashSet>(); + classes.add(RubyProc.class); + return classes; + } + public static class UnitTest { @Mock From d4efc294aff86d8752fdaef63d4afd52e3d50088 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 16:37:20 -0700 Subject: [PATCH 06/13] Added rxjava-dynamic language-adaptor * Adds an Object overload to Observable methods via code generation --- language-adaptors/rxjava-dynamic/build.gradle | 43 ++++++++++++++ .../rx/lang/dynamic/DynamicActionWrapper.java | 38 +++++++++++++ .../java/rx/lang/dynamic/DynamicAdaptor.java | 48 ++++++++++++++++ .../lang/dynamic/DynamicFunctionWrapper.java | 57 +++++++++++++++++++ .../java/rx/util/functions/Functions.java | 16 ++++++ settings.gradle | 1 + 6 files changed, 203 insertions(+) create mode 100644 language-adaptors/rxjava-dynamic/build.gradle create mode 100644 language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicActionWrapper.java create mode 100644 language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicAdaptor.java create mode 100644 language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicFunctionWrapper.java diff --git a/language-adaptors/rxjava-dynamic/build.gradle b/language-adaptors/rxjava-dynamic/build.gradle new file mode 100644 index 0000000000..570142943f --- /dev/null +++ b/language-adaptors/rxjava-dynamic/build.gradle @@ -0,0 +1,43 @@ +dependencies { + core project(':rxjava-core') + compile project(':rxjava-core') + compile project(':language-adaptors:codegen') + provided 'junit:junit-dep:4.10' + provided 'org.mockito:mockito-core:1.8.5' +} + +task createAdaptedObservable(type: JavaExec) { + main = 'rx.codegen.ClassPathBasedRunner' + classpath = sourceSets.main.runtimeClasspath + args = ["Dynamic", outputDir] + + inputs.files(sourceSets.main.runtimeClasspath) + outputs.dir(outputDir) +} + +tasks.test { + dependsOn(createAdaptedObservable) + + //Reorders the classpath so that the newly-create Observables win + classpath = createAdaptedObservable.outputs.files + sourceSets.test.runtimeClasspath +} + +tasks.jar { + dependsOn(createAdaptedObservable) + + from (zipTree(configurations.core.singleFile)) { + exclude "rx/Observable.class" + exclude "rx/observables/BlockingObservable.class" + } + from(outputDir) + + exclude('**/*$UnitTest*') + + manifest { + name = 'rxjava-dynamic' + 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' + } +} diff --git a/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicActionWrapper.java b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicActionWrapper.java new file mode 100644 index 0000000000..697176c80f --- /dev/null +++ b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicActionWrapper.java @@ -0,0 +1,38 @@ +/** + * 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.dynamic; + +import rx.util.functions.Action0; +import rx.util.functions.Action1; +import rx.util.functions.Functions; + +public class DynamicActionWrapper implements Action0, Action1 { + private Object object; + + public DynamicActionWrapper(Object object) { + this.object = object; + } + + @Override + public void call() { + Functions.from(object).call(); + } + + @Override + public void call(T1 t1) { + Functions.from(object).call(t1); + } +} \ No newline at end of file diff --git a/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicAdaptor.java b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicAdaptor.java new file mode 100644 index 0000000000..636e0e54ea --- /dev/null +++ b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicAdaptor.java @@ -0,0 +1,48 @@ +/** + * 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.dynamic; + +import java.util.HashMap; +import java.util.Map; + +import rx.util.functions.FunctionLanguageAdaptor; + +import java.util.HashSet; +import java.util.Set; + +public class DynamicAdaptor implements FunctionLanguageAdaptor { + + @Override + public Map, Class> getFunctionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(Object.class, DynamicFunctionWrapper.class); + return m; + } + + @Override + public Map, Class> getActionClassRewritingMap() { + Map, Class> m = new HashMap, Class>(); + m.put(Object.class, DynamicActionWrapper.class); + return m; + } + + @Override + public Set> getAllClassesToRewrite() { + Set> dynamicClasses = new HashSet>(); + dynamicClasses.add(Object.class); + return dynamicClasses; + } +} diff --git a/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicFunctionWrapper.java b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicFunctionWrapper.java new file mode 100644 index 0000000000..897d9f8d81 --- /dev/null +++ b/language-adaptors/rxjava-dynamic/src/main/java/rx/lang/dynamic/DynamicFunctionWrapper.java @@ -0,0 +1,57 @@ +/** + * 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.dynamic; + +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.FunctionLanguageAdaptor; +import rx.util.functions.Functions; + +public class DynamicFunctionWrapper implements Func0, Func1, Func2, Func3, Func4 { + private Object object; + + public DynamicFunctionWrapper(Object object) { + this.object = object; + } + + @Override + public R call() { + return (R) Functions.from(object).call(); + } + + @Override + public R call(T1 t1) { + return (R) Functions.from(object).call(t1); + } + + @Override + public R call(T1 t1, T2 t2) { + return (R) Functions.from(object).call(t1, t2); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3) { + return (R) Functions.from(object).call(t1, t2, t3); + } + + @Override + public R call(T1 t1, T2 t2, T3 t3, T4 t4) { + return (R) Functions.from(object).call(t1, t2, t3, t4); + } +} \ No newline at end of file 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 42af15cf17..0581e46e13 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Functions.java +++ b/rxjava-core/src/main/java/rx/util/functions/Functions.java @@ -20,6 +20,22 @@ */ public class Functions { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static FuncN from(final Object 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); + } else if (function instanceof Action) { + return fromAction((Action) function); + } + // no support found + throw new RuntimeException("Unsupported closure type: " + function.getClass().getSimpleName()); + } + @SuppressWarnings({ "unchecked", "rawtypes" }) private static FuncN fromFunction(Function function) { // check Func* classes diff --git a/settings.gradle b/settings.gradle index d6cc324181..93c3e179ed 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,5 +4,6 @@ include 'rxjava-core', \ 'language-adaptors:rxjava-jruby', \ 'language-adaptors:rxjava-clojure', \ 'language-adaptors:rxjava-scala', \ +'language-adaptors:rxjava-dynamic', \ 'language-adaptors:codegen', \ 'rxjava-contrib:rxjava-swing' From 4d45c10357277cc879eb323c2b0481b6d0ceca56 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 17:20:44 -0700 Subject: [PATCH 07/13] Reworked Scala adaptor to use implicits in RxImplicits, rather than code generation --- language-adaptors/rxjava-scala/build.gradle | 46 +- .../scala/rx/lang/scala/RxImplicits.scala | 592 ++++++++++++++++++ .../scala/rx/lang/scala/ScalaAdaptor.scala | 197 ------ 3 files changed, 609 insertions(+), 226 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/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 43704248d6..527766691e 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -1,11 +1,9 @@ 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 +11,36 @@ 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-compiler:2.10+' + 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' - - testCompile 'org.scalatest:scalatest_2.10:1.9.1' + compile 'junit:junit-dep:4.10' + compile 'org.mockito:mockito-core:1.8.5' + compile 'org.scalatest:scalatest_2.10:1.9.1' } task test(overwrite: true, dependsOn: testClasses) << { ant.taskdef(name: 'scalatest', classname: 'org.scalatest.tools.ScalaTestAntTask', - classpath: sourceSets.test.runtimeClasspath.asPath + classpath: 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..56f9ab679e --- /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: RuntimeException) => 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: RuntimeException) => 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: RuntimeException) => 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: RuntimeException) => "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 d2d2138976..0000000000 --- a/language-adaptors/rxjava-scala/src/main/scala/rx/lang/scala/ScalaAdaptor.scala +++ /dev/null @@ -1,197 +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]) - } - - 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) - } -} From 5d10dbfb52c4128d025c21707ded252e9f8f988d Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 23:02:15 -0700 Subject: [PATCH 08/13] Added license to files I touched and moved Gradle config around --- build.gradle | 4 +--- language-adaptors/codegen/build.gradle | 19 ++-------------- .../java/rx/codegen/ClassPathBasedRunner.java | 16 ++++++++++++++ .../main/java/rx/codegen/CodeGenerator.java | 19 ++++++++++++++-- language-adaptors/rxjava-clojure/build.gradle | 7 +++--- language-adaptors/rxjava-dynamic/build.gradle | 8 ++++--- language-adaptors/rxjava-groovy/build.gradle | 7 +++--- language-adaptors/rxjava-jruby/build.gradle | 8 ++++--- language-adaptors/rxjava-scala/build.gradle | 2 +- rxjava-contrib/rxjava-swing/build.gradle | 22 ++----------------- .../java/rx/observables/SwingObservable.java | 2 ++ rxjava-core/build.gradle | 20 ----------------- .../main/java/rx/util/functions/Action.java | 16 ++++++++++++++ .../main/java/rx/util/functions/Function.java | 18 ++++++++++++++- 14 files changed, 92 insertions(+), 76 deletions(-) diff --git a/build.gradle b/build.gradle index 85d83ea12d..29b55f5c1a 100644 --- a/build.gradle +++ b/build.gradle @@ -19,12 +19,10 @@ subprojects { apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' - apply plugin: 'osgi' group = "com.netflix.${githubProjectName}" - ext.coreJarDir = new File(rootDir, "/rxjava-core/build/libs").getCanonicalPath() - ext.outputDir = file("build/rewritten_classes") + ext.codeGenOutputDir = file("build/rewritten_classes") // make 'examples' use the same classpath configurations { diff --git a/language-adaptors/codegen/build.gradle b/language-adaptors/codegen/build.gradle index 7967131270..1541b10429 100644 --- a/language-adaptors/codegen/build.gradle +++ b/language-adaptors/codegen/build.gradle @@ -11,24 +11,9 @@ dependencies { provided 'junit:junit:4.10' } -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 { + exclude('**/*$UnitTest*') + manifest { name = 'rxjava-codegen' instruction 'Bundle-Vendor', 'Netflix' diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java b/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java index 5630724abd..ace0a316d2 100644 --- a/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java +++ b/language-adaptors/codegen/src/main/java/rx/codegen/ClassPathBasedRunner.java @@ -1,3 +1,19 @@ +/** + * 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.codegen; import java.io.File; diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java index 02d17d793d..8acfd1759f 100644 --- a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java +++ b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java @@ -1,3 +1,18 @@ +/** + * 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.codegen; import java.io.File; @@ -174,8 +189,8 @@ private static List getRewrittenMethods(CtClass clazz, CtMethod method newBody.append(makeArgList(argumentList)); newBody.append(")"); newBody.append(";}"); - System.out.println(method.getReturnType().getName() + " " + method.getName() + "(" + initialArgString + ") --> " + newMethod.getReturnType().getName() + " " + newMethod.getName() + "(" + finalArgString + ")"); - System.out.println(" " + newBody.toString()); + //System.out.println(method.getReturnType().getName() + " " + method.getName() + "(" + initialArgString + ") --> " + newMethod.getReturnType().getName() + " " + newMethod.getName() + "(" + finalArgString + ")"); + //System.out.println(" " + newBody.toString()); newMethod.setBody(newBody.toString()); newMethods.add(newMethod); } diff --git a/language-adaptors/rxjava-clojure/build.gradle b/language-adaptors/rxjava-clojure/build.gradle index 78cc056b41..6fb4ea8c30 100644 --- a/language-adaptors/rxjava-clojure/build.gradle +++ b/language-adaptors/rxjava-clojure/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'clojure' +apply plugin: 'osgi' dependencies { core project(':rxjava-core') @@ -37,10 +38,10 @@ eclipse { task createAdaptedObservable(type: JavaExec) { main = 'rx.codegen.ClassPathBasedRunner' classpath = sourceSets.main.runtimeClasspath - args = ["Clojure", outputDir] + args = ["Clojure", codeGenOutputDir] inputs.files(sourceSets.main.runtimeClasspath) - outputs.dir(outputDir) + outputs.dir(codeGenOutputDir) } tasks.test { @@ -57,7 +58,7 @@ tasks.jar { exclude "rx/Observable.class" exclude "rx/observables/BlockingObservable.class" } - from(outputDir) + from(codeGenOutputDir) exclude('**/*$UnitTest*') diff --git a/language-adaptors/rxjava-dynamic/build.gradle b/language-adaptors/rxjava-dynamic/build.gradle index 570142943f..18d03a8d9c 100644 --- a/language-adaptors/rxjava-dynamic/build.gradle +++ b/language-adaptors/rxjava-dynamic/build.gradle @@ -1,3 +1,5 @@ +apply plugin: 'osgi' + dependencies { core project(':rxjava-core') compile project(':rxjava-core') @@ -9,10 +11,10 @@ dependencies { task createAdaptedObservable(type: JavaExec) { main = 'rx.codegen.ClassPathBasedRunner' classpath = sourceSets.main.runtimeClasspath - args = ["Dynamic", outputDir] + args = ["Dynamic", codeGenOutputDir] inputs.files(sourceSets.main.runtimeClasspath) - outputs.dir(outputDir) + outputs.dir(codeGenOutputDir) } tasks.test { @@ -29,7 +31,7 @@ tasks.jar { exclude "rx/Observable.class" exclude "rx/observables/BlockingObservable.class" } - from(outputDir) + from(codeGenOutputDir) exclude('**/*$UnitTest*') diff --git a/language-adaptors/rxjava-groovy/build.gradle b/language-adaptors/rxjava-groovy/build.gradle index fedb8bf395..edb9cb30ea 100644 --- a/language-adaptors/rxjava-groovy/build.gradle +++ b/language-adaptors/rxjava-groovy/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'groovy' +apply plugin: 'osgi' dependencies { core project(':rxjava-core') @@ -12,10 +13,10 @@ dependencies { task createAdaptedObservable(type: JavaExec) { main = 'rx.codegen.ClassPathBasedRunner' classpath = sourceSets.main.runtimeClasspath - args = ["Groovy", outputDir] + args = ["Groovy", codeGenOutputDir] inputs.files(sourceSets.main.runtimeClasspath) - outputs.dir(outputDir) + outputs.dir(codeGenOutputDir) } tasks.test { @@ -32,7 +33,7 @@ tasks.jar { exclude "rx/Observable.class" exclude "rx/observables/BlockingObservable.class" } - from(outputDir) + from(codeGenOutputDir) exclude('**/*$UnitTest*') diff --git a/language-adaptors/rxjava-jruby/build.gradle b/language-adaptors/rxjava-jruby/build.gradle index f4aaf194cf..d7a0d82d39 100644 --- a/language-adaptors/rxjava-jruby/build.gradle +++ b/language-adaptors/rxjava-jruby/build.gradle @@ -1,3 +1,5 @@ +apply plugin: 'osgi' + dependencies { core project(':rxjava-core') compile project(':rxjava-core') @@ -10,10 +12,10 @@ dependencies { task createAdaptedObservable(type: JavaExec) { main = 'rx.codegen.ClassPathBasedRunner' classpath = sourceSets.main.runtimeClasspath - args = ["JRuby", outputDir] + args = ["JRuby", codeGenOutputDir] inputs.files(sourceSets.main.runtimeClasspath) - outputs.dir(outputDir) + outputs.dir(codeGenOutputDir) } tasks.test { @@ -30,7 +32,7 @@ tasks.jar { exclude "rx/Observable.class" exclude "rx/observables/BlockingObservable.class" } - from(outputDir) + from(codeGenOutputDir) exclude('**/*$UnitTest*') diff --git a/language-adaptors/rxjava-scala/build.gradle b/language-adaptors/rxjava-scala/build.gradle index 527766691e..be61f1d846 100644 --- a/language-adaptors/rxjava-scala/build.gradle +++ b/language-adaptors/rxjava-scala/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'scala' +apply plugin: 'osgi' tasks.withType(ScalaCompile) { scalaCompileOptions.fork = true @@ -11,7 +12,6 @@ tasks.withType(ScalaCompile) { } } - sourceSets { test { scala { diff --git a/rxjava-contrib/rxjava-swing/build.gradle b/rxjava-contrib/rxjava-swing/build.gradle index 986f7ca6b9..0076915eee 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" @@ -40,6 +20,8 @@ javadoc { } jar { + exclude('**/*$UnitTest*') + manifest { name = 'rxjava-swing' instruction 'Bundle-Vendor', 'Netflix' 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..fa9ecd3095 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,6 +15,8 @@ */ 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-core/build.gradle b/rxjava-core/build.gradle index 72a984c88d..39232193e8 100644 --- a/rxjava-core/build.gradle +++ b/rxjava-core/build.gradle @@ -11,23 +11,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 +31,4 @@ 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*') } - 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..95b3176971 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Action.java +++ b/rxjava-core/src/main/java/rx/util/functions/Action.java @@ -1,3 +1,19 @@ +/** + * 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; /** 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..be3440323b 100644 --- a/rxjava-core/src/main/java/rx/util/functions/Function.java +++ b/rxjava-core/src/main/java/rx/util/functions/Function.java @@ -1,9 +1,25 @@ +/** + * 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; /** * All Func and Action interfaces extend from this. *

- * Marker interface to allow isntanceof checks. + * Marker interface to allow instanceof checks. */ public interface Function { From 73c863143911fde6e8d074cb4f439461a940a182 Mon Sep 17 00:00:00 2001 From: Matt Jacobs Date: Wed, 3 Jul 2013 23:22:40 -0700 Subject: [PATCH 09/13] Bugfix to codegeneration - explicitly call a static/instance method in body --- .../codegen/src/main/java/rx/codegen/CodeGenerator.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java index 8acfd1759f..ed737e4999 100644 --- a/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java +++ b/language-adaptors/codegen/src/main/java/rx/codegen/CodeGenerator.java @@ -23,7 +23,9 @@ import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; +import javassist.Modifier; import javassist.NotFoundException; + import rx.util.functions.Action; import rx.util.functions.Action0; import rx.util.functions.Action1; @@ -174,6 +176,11 @@ private static List getRewrittenMethods(CtClass clazz, CtMethod method List argumentList = new ArrayList(); StringBuffer newBody = new StringBuffer(); newBody.append("{ return "); + if (Modifier.isStatic(method.getModifiers())) { + newBody.append(clazz.getName() + "."); + } else { + newBody.append("this."); + } newBody.append(method.getName()); newBody.append("("); for (int i = 0; i < method.getParameterTypes().length; i++) { @@ -189,6 +196,7 @@ private static List getRewrittenMethods(CtClass clazz, CtMethod method newBody.append(makeArgList(argumentList)); newBody.append(")"); newBody.append(";}"); + //Uncomment these to see all of the rewritten methods //System.out.println(method.getReturnType().getName() + " " + method.getName() + "(" + initialArgString + ") --> " + newMethod.getReturnType().getName() + " " + newMethod.getName() + "(" + finalArgString + ")"); //System.out.println(" " + newBody.toString()); newMethod.setBody(newBody.toString()); From 227c44264bbd93e8ff4353db7766a77d318b753f Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Fri, 5 Jul 2013 15:45:53 -0700 Subject: [PATCH 10/13] Remove '? super' generic definitions I couldn't get these to work once we removed the Object overloads that was apparently being invoked instead of the staticly typed method so removing them. If someone else can get these generics working then please submit a new pull request. --- .../rx/operators/OperationCombineLatest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java b/rxjava-core/src/main/java/rx/operators/OperationCombineLatest.java index 77996bab67..c3c0ee3235 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(Exception 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."); } From b831bf86b6eac3358813731c3ae93cece99f4d1f Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Fri, 5 Jul 2013 16:00:20 -0700 Subject: [PATCH 11/13] Removing zip FuncN overloads - they conflict with dynamic languages These methods will need different names as they have the same argument count so break with dynamic overloads once we do static handling of dynamic languages. --- rxjava-core/src/main/java/rx/Observable.java | 57 -------------------- 1 file changed, 57 deletions(-) diff --git a/rxjava-core/src/main/java/rx/Observable.java b/rxjava-core/src/main/java/rx/Observable.java index 72c84cce70..cfa21e5ec2 100644 --- a/rxjava-core/src/main/java/rx/Observable.java +++ b/rxjava-core/src/main/java/rx/Observable.java @@ -1858,63 +1858,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 - * 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 invokations of the - * source Observable that emits the fewest items. - *

- * - * - * @param ws - * An Observable of source Observables - * @param reduceFunction - * 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 FuncN reduceFunction) { - return ws.toList().mapMany(new Func1>, Observable>() { - @Override - public Observable call(List> wsList) { - return create(OperationZip.zip(wsList, 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 - * 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 invokations of the - * source Observable that emits the fewest items. - *

- * - * - * @param ws - * A collection of source Observables - * @param reduceFunction - * 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, FuncN reduceFunction) { - return create(OperationZip.zip(ws, 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. From add859fa82bfa3b1233fbe35f45802d0d6144a65 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Fri, 5 Jul 2013 16:07:54 -0700 Subject: [PATCH 12/13] Upgrade to Gradle 1.6 - needed for Scala build to succeed --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From e8373fa2b8480e836236ba9438514079c8d46c65 Mon Sep 17 00:00:00 2001 From: Ben Christensen Date: Fri, 5 Jul 2013 16:08:47 -0700 Subject: [PATCH 13/13] Version 0.10.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9a1e264337..6230d72284 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.9.2-SNAPSHOT +version=0.10.0-SNAPSHOT