Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language adaptors #2

Merged
merged 6 commits into from
Jan 11, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added gradle/doclet-exclude.jar
Binary file not shown.
59 changes: 59 additions & 0 deletions gradle/javadocStyleSheet.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# originally from http://sensemaya.org/files/stylesheet.css and then modified
# http://sensemaya.org/maya/2009/07/10/making-javadoc-more-legible

/* Javadoc style sheet */

/* Define colors, fonts and other style attributes here to override the defaults */

/* Page background color */
body { background-color: #FFFFFF; color:#333; font-size: 100%; }

body { font-size: 0.875em; line-height: 1.286em; font-family: "Helvetica", "Arial", sans-serif; }

code { color: #777; line-height: 1.286em; font-family: "Consolas", "Lucida Console", "Droid Sans Mono", "Andale Mono", "Monaco", "Lucida Sans Typewriter"; }

a { text-decoration: none; color: #16569A; /* also try #2E85ED, #0033FF, #6C93C6, #1D7BBE, #1D8DD2 */ }
a:hover { text-decoration: underline; }


table[border="1"] { border: 1px solid #ddd; }
table[border="1"] td, table[border="1"] th { border: 1px solid #ddd; }
table[cellpadding="3"] td { padding: 0.5em; }

font[size="-1"] { font-size: 0.85em; line-height: 1.5em; }
font[size="-2"] { font-size: 0.8em; }
font[size="+2"] { font-size: 1.4em; line-height: 1.3em; padding: 0.4em 0; }

/* Headings */
h1 { font-size: 1.5em; line-height: 1.286em;}
h2.title { color: #c81f08; }

/* Table colors */
.TableHeadingColor { background: #ccc; color:#444; } /* Dark mauve */
.TableSubHeadingColor { background: #ddd; color:#444; } /* Light mauve */
.TableRowColor { background: #FFFFFF; color:#666; font-size: 0.95em; } /* White */
.TableRowColor code { color:#000; } /* White */

/* Font used in left-hand frame lists */
.FrameTitleFont { font-size: 100%; }
.FrameHeadingFont { font-size: 90%; }
.FrameItemFont { font-size: 0.9em; line-height: 1.3em;
}
/* Java Interfaces */
.FrameItemFont a i {
font-style: normal; color: #16569A;
}
.FrameItemFont a:hover i {
text-decoration: underline;
}


/* Navigation bar fonts and colors */
.NavBarCell1 { background-color:#E0E6DF; } /* Light mauve */
.NavBarCell1Rev { background-color:#16569A; color:#FFFFFF} /* Dark Blue */
.NavBarFont1 { }
.NavBarFont1Rev { color:#FFFFFF; }

.NavBarCell2 { background-color:#FFFFFF; color:#000000}
.NavBarCell3 { background-color:#FFFFFF; color:#000000}

7 changes: 7 additions & 0 deletions language-adaptors/rxjava-groovy/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apply plugin: 'java'
dependencies {
compile project(':rxjava-core')
compile 'org.codehaus.groovy:groovy:1.8.8'
provided 'junit:junit:4.10'
provided 'org.mockito:mockito-core:1.9.5'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/**
* 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 org.rx.lang.groovy;

import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.GroovyClassLoader;

import java.util.Arrays;

import org.codehaus.groovy.runtime.InvokerHelper;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.rx.functions.FunctionLanguageAdaptor;
import org.rx.reactive.Notification;
import org.rx.reactive.Observable;
import org.rx.reactive.Observer;
import org.rx.reactive.Subscription;

public class GroovyAdaptor implements FunctionLanguageAdaptor {

@Override
public Object call(Object function, Object[] args) {
return ((Closure<?>) function).call(args);
}

public Class<?> getFunctionClass() {
return Closure.class;
}

public static class UnitTest {

@Mock
ScriptAssertion assertion;

@Mock
Observer<Integer> w;

@Before
public void before() {
MockitoAnnotations.initMocks(this);
}

@Test
public void testCreateViaGroovy() {
runGroovyScript("o.create({it.onNext('hello');it.onCompleted();}).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received("hello");
}

@Test
public void testFilterViaGroovy() {
runGroovyScript("o.filter(o.toObservable(1, 2, 3), {it >= 2}).subscribe({ result -> a.received(result)});");
verify(assertion, times(0)).received(1);
verify(assertion, times(1)).received(2);
verify(assertion, times(1)).received(3);
}

@Test
public void testLast() {
String script = "mockApiCall.getObservable().last().subscribe({ result -> a.received(result)});";
runGroovyScript(script);
verify(assertion, times(1)).received("hello_1");
}

@Test
public void testMap() {
String script = "mockApiCall.getObservable().map({v -> 'say' + v}).subscribe({ result -> a.received(result)});";
runGroovyScript(script);
verify(assertion, times(1)).received("sayhello_1");
}

@Test
public void testMapViaGroovy() {
runGroovyScript("o.map(o.toObservable(1, 2, 3), {'hello_' + it}).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received("hello_" + 1);
verify(assertion, times(1)).received("hello_" + 2);
verify(assertion, times(1)).received("hello_" + 3);
}

@Test
public void testMaterializeViaGroovy() {
runGroovyScript("o.materialize(o.toObservable(1, 2, 3)).subscribe({ result -> a.received(result)});");
// we expect 4 onNext calls: 3 for 1, 2, 3 ObservableNotification.OnNext and 1 for ObservableNotification.OnCompleted
verify(assertion, times(4)).received(any(Notification.class));
verify(assertion, times(0)).error(any(Exception.class));
}

@Test
public void testMergeDelayErrorViaGroovy() {
runGroovyScript("o.mergeDelayError(o.toObservable(1, 2, 3), o.merge(o.toObservable(6), o.error(new NullPointerException()), o.toObservable(7)), o.toObservable(4, 5)).subscribe({ result -> a.received(result)}, { exception -> a.error(exception)});");
verify(assertion, times(1)).received(1);
verify(assertion, times(1)).received(2);
verify(assertion, times(1)).received(3);
verify(assertion, times(1)).received(4);
verify(assertion, times(1)).received(5);
verify(assertion, times(1)).received(6);
verify(assertion, times(0)).received(7);
verify(assertion, times(1)).error(any(NullPointerException.class));
}

@Test
public void testMergeViaGroovy() {
runGroovyScript("o.merge(o.toObservable(1, 2, 3), o.merge(o.toObservable(6), o.error(new NullPointerException()), o.toObservable(7)), o.toObservable(4, 5)).subscribe({ result -> a.received(result)}, { exception -> a.error(exception)});");
// executing synchronously so we can deterministically know what order things will come
verify(assertion, times(1)).received(1);
verify(assertion, times(1)).received(2);
verify(assertion, times(1)).received(3);
verify(assertion, times(0)).received(4); // the NPE will cause this sequence to be skipped
verify(assertion, times(0)).received(5); // the NPE will cause this sequence to be skipped
verify(assertion, times(1)).received(6); // this comes before the NPE so should exist
verify(assertion, times(0)).received(7);// this comes in the sequence after the NPE
verify(assertion, times(1)).error(any(NullPointerException.class));
}

@Test
public void testScriptWithMaterialize() {
String script = "mockApiCall.getObservable().materialize().subscribe({ result -> a.received(result)});";
runGroovyScript(script);
// 2 times: once for hello_1 and once for onCompleted
verify(assertion, times(2)).received(any(Notification.class));
}

@Test
public void testScriptWithMerge() {
String script = "o.merge(mockApiCall.getObservable(), mockApiCall.getObservable()).subscribe({ result -> a.received(result)});";
runGroovyScript(script);
verify(assertion, times(1)).received("hello_1");
verify(assertion, times(1)).received("hello_2");
}

@Test
public void testScriptWithOnNext() {
String script = "mockApiCall.getObservable().subscribe({ result -> a.received(result)})";
runGroovyScript(script);
verify(assertion).received("hello_1");
}

@Test
public void testSkipTakeViaGroovy() {
runGroovyScript("o.skip(o.toObservable(1, 2, 3), 1).take(1).subscribe({ result -> a.received(result)});");
verify(assertion, times(0)).received(1);
verify(assertion, times(1)).received(2);
verify(assertion, times(0)).received(3);
}

@Test
public void testSkipViaGroovy() {
runGroovyScript("o.skip(o.toObservable(1, 2, 3), 2).subscribe({ result -> a.received(result)});");
verify(assertion, times(0)).received(1);
verify(assertion, times(0)).received(2);
verify(assertion, times(1)).received(3);
}

@Test
public void testTakeViaGroovy() {
runGroovyScript("o.take(o.toObservable(1, 2, 3), 2).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received(1);
verify(assertion, times(1)).received(2);
verify(assertion, times(0)).received(3);
}

@Test
public void testToSortedList() {
runGroovyScript("mockApiCall.getNumbers().toSortedList().subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received(Arrays.asList(1, 2, 3, 4, 5));
}

@Test
public void testToSortedListStatic() {
runGroovyScript("o.toSortedList(o.toObservable(1, 3, 2, 5, 4)).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received(Arrays.asList(1, 2, 3, 4, 5));
}

@Test
public void testToSortedListWithFunction() {
runGroovyScript("mockApiCall.getNumbers().toSortedList({a, b -> a - b}).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received(Arrays.asList(1, 2, 3, 4, 5));
}

@Test
public void testToSortedListWithFunctionStatic() {
runGroovyScript("o.toSortedList(o.toObservable(1, 3, 2, 5, 4), {a, b -> a - b}).subscribe({ result -> a.received(result)});");
verify(assertion, times(1)).received(Arrays.asList(1, 2, 3, 4, 5));
}

private void runGroovyScript(String script) {
ClassLoader parent = getClass().getClassLoader();
@SuppressWarnings("resource")
GroovyClassLoader loader = new GroovyClassLoader(parent);

Binding binding = new Binding();
binding.setVariable("mockApiCall", new TestFactory());
binding.setVariable("a", assertion);
binding.setVariable("o", org.rx.reactive.Observable.class);

/* parse the script and execute it */
InvokerHelper.createScript(loader.parseClass(script), binding).run();
}

private static interface ScriptAssertion {
public void error(Exception o);

public void received(Object o);
}

private static class TestFactory {
int counter = 1;

@SuppressWarnings("unused")
public Observable<Integer> getNumbers() {
return Observable.toObservable(1, 3, 2, 5, 4);
}

@SuppressWarnings("unused")
public TestObservable getObservable() {
return new TestObservable(counter++);
}
}

private static class TestObservable extends Observable<String> {
private final int count;

public TestObservable(int count) {
this.count = count;
}

public Subscription subscribe(Observer<String> observer) {

observer.onNext("hello_" + count);
observer.onCompleted();

return new Subscription() {

public void unsubscribe() {
// unregister ... will never be called here since we are executing synchronously
}

};
}
}
}

}
7 changes: 7 additions & 0 deletions language-adaptors/rxjava-jruby/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apply plugin: 'java'
dependencies {
compile project(':rxjava-core')
compile 'org.jruby:jruby:1.7.2'
provided 'junit:junit:4.10'
provided 'org.mockito:mockito-core:1.9.5'
}
Loading