Skip to content

Commit

Permalink
Merge pull request ReactiveX#422 from ragalie/jruby
Browse files Browse the repository at this point in the history
JRuby function wrapping support
  • Loading branch information
benjchristensen committed Oct 9, 2013
2 parents 2bd22d6 + 24807e9 commit abc8bec
Show file tree
Hide file tree
Showing 11 changed files with 705 additions and 0 deletions.
45 changes: 45 additions & 0 deletions language-adaptors/rxjava-jruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# JRuby Adaptor for RxJava

This adaptor improves the success and performance of RxJava when Ruby `Proc` is passed to an RxJava method.

This enables correct and efficient execution of code such as:

```ruby
Observable.from("one", "two", "three").
take(2).
subscribe {|val| puts val}
```

# Usage

Require the JAR file as usual. After requiring the JAR, you must also require the interop code:

```ruby
require "rx/lang/jruby/interop"
```

# Binaries

Binaries and dependency information for Maven, Ivy, Gradle and others can be found at [http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22rxjava-jruby%22).

Example for Maven:

```xml
<dependency>
<groupId>com.netflix.rxjava</groupId>
<artifactId>rxjava-jruby</artifactId>
<version>x.y.z</version>
</dependency>
```

and for Ivy:

```xml
<dependency org="com.netflix.rxjava" name="rxjava-jruby" rev="x.y.z" />
```

and for Gradle:

```groovy
compile 'com.netflix.rxjava:rxjava-jruby:x.y.z'
```
47 changes: 47 additions & 0 deletions language-adaptors/rxjava-jruby/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
apply plugin: 'osgi'

repositories {
maven {
url 'http://deux.gemjars.org'
}
mavenCentral()
}

configurations {
rspec
}

sourceSets {
test {
resources {
srcDir 'src/spec/ruby'
}
}
}

dependencies {
compile project(':rxjava-core')
compile 'org.jruby:jruby:1.7+'
provided 'junit:junit-dep:4.10'
provided 'org.mockito:mockito-core:1.8.5'
rspec 'org.jruby:jruby-complete:1.7.4'
rspec 'org.rubygems:rspec:2.14.1'
}

task(rspec, type: JavaExec) {
main 'org.jruby.Main'
classpath configurations.rspec + runtimeClasspath
args 'classpath:bin/rspec', 'src/spec/ruby'
}

tasks.build.dependsOn << 'rspec'

jar {
manifest {
name = 'rxjava-jruby'
instruction 'Bundle-Vendor', 'Netflix'
instruction 'Bundle-DocURL', 'https://github.com/Netflix/RxJava'
instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*'
instruction 'Fragment-Host', 'com.netflix.rxjava.core'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* 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.RubyProc;
import org.jruby.Ruby;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.javasupport.JavaUtil;

import rx.util.functions.Action;
import rx.util.functions.Action0;
import rx.util.functions.Action1;
import rx.util.functions.Action2;
import rx.util.functions.Action3;

/**
* Concrete wrapper that accepts a {@link RubyProc} and produces any needed Rx {@link Action}.
*
* @param <T1>
* @param <T2>
* @param <T3>
* @param <T4>
*/
public class JRubyActionWrapper<T1, T2, T3, T4> implements Action, Action0, Action1<T1>, Action2<T1, T2>, Action3<T1, T2, T3> {

private final RubyProc proc;
private final ThreadContext context;
private final Ruby runtime;

public JRubyActionWrapper(ThreadContext context, RubyProc proc) {
this.proc = proc;
this.context = context;
this.runtime = context.getRuntime();
}

@Override
public void call() {
IRubyObject[] array = new IRubyObject[0];
proc.call(context, array);
}

@Override
public void call(T1 t1) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1)};
proc.call(context, array);
}

@Override
public void call(T1 t1, T2 t2) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2)};
proc.call(context, array);
}

@Override
public void call(T1 t1, T2 t2, T3 t3) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3)};
proc.call(context, array);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/**
* 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.RubyProc;
import org.jruby.Ruby;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.javasupport.JavaUtil;

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.FuncN;
import rx.util.functions.Function;

/**
* Concrete wrapper that accepts a {@link RubyProc} and produces any needed Rx {@link Function}.
*
* @param <T1>
* @param <T2>
* @param <T3>
* @param <T4>
* @param <R>
*/
public class JRubyFunctionWrapper<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> implements
Func0<R>,
Func1<T1, R>,
Func2<T1, T2, R>,
Func3<T1, T2, T3, R>,
Func4<T1, T2, T3, T4, R>,
Func5<T1, T2, T3, T4, T5, R>,
Func6<T1, T2, T3, T4, T5, T6, R>,
Func7<T1, T2, T3, T4, T5, T6, T7, R>,
Func8<T1, T2, T3, T4, T5, T6, T7, T8, R>,
Func9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>,
FuncN<R> {

private final RubyProc proc;
private final ThreadContext context;
private final Ruby runtime;

public JRubyFunctionWrapper(ThreadContext context, RubyProc proc) {
this.proc = proc;
this.context = context;
this.runtime = context.getRuntime();
}

@Override
public R call() {
IRubyObject[] array = new IRubyObject[0];
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4),
JavaUtil.convertJavaToRuby(runtime, t5)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4),
JavaUtil.convertJavaToRuby(runtime, t5),
JavaUtil.convertJavaToRuby(runtime, t6)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4),
JavaUtil.convertJavaToRuby(runtime, t5),
JavaUtil.convertJavaToRuby(runtime, t6),
JavaUtil.convertJavaToRuby(runtime, t7)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4),
JavaUtil.convertJavaToRuby(runtime, t5),
JavaUtil.convertJavaToRuby(runtime, t6),
JavaUtil.convertJavaToRuby(runtime, t7),
JavaUtil.convertJavaToRuby(runtime, t8)};
return (R) proc.call(context, array);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) {
IRubyObject[] array = {JavaUtil.convertJavaToRuby(runtime, t1),
JavaUtil.convertJavaToRuby(runtime, t2),
JavaUtil.convertJavaToRuby(runtime, t3),
JavaUtil.convertJavaToRuby(runtime, t4),
JavaUtil.convertJavaToRuby(runtime, t5),
JavaUtil.convertJavaToRuby(runtime, t6),
JavaUtil.convertJavaToRuby(runtime, t7),
JavaUtil.convertJavaToRuby(runtime, t8),
JavaUtil.convertJavaToRuby(runtime, t9)};
return (R) proc.call(context, array);
}

@Override
public R call(Object... args) {
IRubyObject[] array = new IRubyObject[args.length];
for (int i = 0; i < args.length; i++) {
array[i] = JavaUtil.convertJavaToRuby(runtime, args[i]);
}
return (R) proc.call(context, array);
}
}
Loading

0 comments on commit abc8bec

Please sign in to comment.