diff --git a/language-adaptors/rxjava-jruby/README.md b/language-adaptors/rxjava-jruby/README.md
new file mode 100644
index 0000000000..da75bac1fb
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/README.md
@@ -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
+
+ com.netflix.rxjava
+ rxjava-jruby
+ x.y.z
+
+```
+
+and for Ivy:
+
+```xml
+
+```
+
+and for Gradle:
+
+```groovy
+compile 'com.netflix.rxjava:rxjava-jruby:x.y.z'
+```
diff --git a/language-adaptors/rxjava-jruby/build.gradle b/language-adaptors/rxjava-jruby/build.gradle
new file mode 100644
index 0000000000..eaefe7a81a
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/build.gradle
@@ -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'
+ }
+}
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..6beb4f1d59
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyActionWrapper.java
@@ -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
+ * @param
+ * @param
+ * @param
+ */
+public class JRubyActionWrapper implements Action, Action0, Action1, Action2, Action3 {
+
+ 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);
+ }
+
+}
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..f049827d8e
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/main/java/rx/lang/jruby/JRubyFunctionWrapper.java
@@ -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
+ * @param
+ * @param
+ * @param
+ * @param
+ */
+public class JRubyFunctionWrapper implements
+ Func0,
+ Func1,
+ Func2,
+ Func3,
+ Func4,
+ Func5,
+ Func6,
+ Func7,
+ Func8,
+ Func9,
+ FuncN {
+
+ 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);
+ }
+}
diff --git a/language-adaptors/rxjava-jruby/src/main/resources/rx/lang/jruby/interop.rb b/language-adaptors/rxjava-jruby/src/main/resources/rx/lang/jruby/interop.rb
new file mode 100644
index 0000000000..a080639728
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/main/resources/rx/lang/jruby/interop.rb
@@ -0,0 +1,115 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+module Rx
+ module Lang
+ module Jruby
+ class Interop
+ WRAPPERS = {
+ Java::RxUtilFunctions::Action => Java::RxLangJruby::JRubyActionWrapper,
+ Java::Rx::Observable::OnSubscribeFunc => false
+ }
+
+ WRAPPERS.default = Java::RxLangJruby::JRubyFunctionWrapper
+
+ KLASSES = [Java::Rx::Observable, Java::RxObservables::BlockingObservable]
+ FUNCTION = Java::RxUtilFunctions::Function.java_class
+ RUNTIME = JRuby.runtime
+
+ def self.instance
+ @instance ||= new
+ end
+
+ def initialize
+ KLASSES.each do |klass|
+ function_methods = (klass.java_class.declared_instance_methods + klass.java_class.declared_class_methods).select do |method|
+ method.public? && method.parameter_types.any? {|type| FUNCTION.assignable_from?(type)}
+ end
+
+ parameter_types = {}
+ function_methods.each do |method|
+ parameter_types[[method.name, method.static?]] ||= []
+
+ method.parameter_types.each_with_index do |type, idx|
+ next unless FUNCTION.assignable_from?(type)
+
+ constructor = WRAPPERS.find do |java_class, wrapper|
+ type.ruby_class.ancestors.include?(java_class)
+ end
+
+ # Skip OnSubscribeFuncs
+ next if constructor && constructor.last == false
+
+ constructor = (constructor && constructor.last) || WRAPPERS.default
+
+ parameter_types[[method.name, method.static?]][idx] ||= []
+ parameter_types[[method.name, method.static?]][idx] << constructor
+ end
+ end
+
+ parameter_types.each_pair do |_, types|
+ types.map! do |type|
+ next type.first if type && type.uniq.length == 1
+ nil
+ end
+ end
+
+ parameter_types.each_pair do |(method_name, static), types|
+ next if types.all?(&:nil?)
+
+ klass_to_open = static ? klass.singleton_class : klass
+
+ [method_name, underscore(method_name)].uniq.each do |name|
+ klass_to_open.send(:alias_method, "#{name}_without_wrapping", name)
+ klass_to_open.send(:define_method, name) do |*args, &block|
+ context = RUNTIME.get_current_context
+
+ args = args.each_with_index.map do |arg, idx|
+ if arg.is_a?(Proc) && types[idx]
+ types[idx].new(context, arg)
+ else
+ arg
+ end
+ end
+
+ if block && types[args.length]
+ block = types[args.length].new(context, block)
+ end
+
+ send("#{name}_without_wrapping", *(args + [block].compact))
+ end
+ end
+ end
+ end
+ end
+
+ private
+
+ # File activesupport/lib/active_support/inflector/methods.rb, line 89
+ def underscore(camel_cased_word)
+ word = camel_cased_word.to_s.dup
+ word.gsub!('::', '/')
+ word.gsub!(/(?:([A-Za-z\d])|^)((?=a)b)(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
+ word.tr!("-", "_")
+ word.downcase!
+ word
+ end
+ end
+ end
+ end
+end
+
+Rx::Lang::Jruby::Interop.instance
diff --git a/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/interop_spec.rb b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/interop_spec.rb
new file mode 100644
index 0000000000..222caf34ed
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/interop_spec.rb
@@ -0,0 +1,68 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+require_relative "spec_helper"
+
+describe Rx::Lang::Jruby::Interop do
+ subject { described_class.instance }
+
+ let(:observable) { Java::Rx::Observable.from([1, 2, 3]) }
+
+ context "with a normal, non-function method signature" do
+ it "calls straight through to the original Java method" do
+ observable.should_not_receive(:toBlockingObservable_without_wrapping)
+ observable.toBlockingObservable.should be_a(Java::RxObservables::BlockingObservable)
+ end
+ end
+
+ context "with a method with a function method signature" do
+ it "wraps function arguments if they're in the right position" do
+ observable.should_receive(:subscribe_without_wrapping).with(kind_of(Java::RxLangJruby::JRubyActionWrapper))
+ observable.subscribe(lambda {})
+ end
+
+ it "doesn't wrap function arguments if they're in the wrong position" do
+ proc = lambda {}
+ observable.should_receive(:subscribe_without_wrapping).with(1, 1, 1, proc)
+ observable.subscribe(1, 1, 1, proc)
+ end
+
+ it "doesn't wrap non-function arguments" do
+ observable.should_receive(:subscribe_without_wrapping).with(1)
+ observable.subscribe(1)
+ end
+
+ it "doesn't wrap OnSubscribeFunc arguments" do
+ proc = lambda {|observer| observer.onNext("hi")}
+ Java::Rx::Observable.__persistent__ = true
+ Java::Rx::Observable.should_not_receive(:create_without_wrapping)
+ Java::Rx::Observable.create(proc).should be_a(Java::Rx::Observable)
+ end
+
+ it "works with underscoreized method names" do
+ observable.
+ should_receive(:finally_do_without_wrapping).
+ with(kind_of(Java::RxLangJruby::JRubyActionWrapper)).
+ and_call_original
+
+ observable.finally_do(lambda {})
+ end
+
+ it "passes a block through as the last argument" do
+ proc = lambda {}
+ observable.should_receive(:subscribe_without_wrapping).with(1, 1, 1, 1, proc)
+ observable.subscribe(1, 1, 1, 1, &proc) # intentionally bogus call so it doesn't wrap the proc
+ end
+ end
+end
diff --git a/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_action_wrapper_spec.rb b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_action_wrapper_spec.rb
new file mode 100644
index 0000000000..dae1973625
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_action_wrapper_spec.rb
@@ -0,0 +1,46 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+require_relative "spec_helper"
+
+describe Java::RxLangJruby::JRubyActionWrapper do
+ let(:spy) { double(:spy, :call => nil) }
+ subject { described_class.new(JRuby.runtime.get_current_context, lambda {|*args| spy.call(args)}) }
+
+ let(:interfaces) do
+ [Java::RxUtilFunctions::Action,
+ Java::RxUtilFunctions::Action0,
+ Java::RxUtilFunctions::Action1,
+ Java::RxUtilFunctions::Action2,
+ Java::RxUtilFunctions::Action3]
+ end
+
+ it "implements the interfaces" do
+ interfaces.each do |interface|
+ subject.is_a?(interface)
+ end
+ end
+
+ it "successfully uses the interfaces" do
+ spy.should_receive(:call).with([])
+ spy.should_receive(:call).with([1])
+ spy.should_receive(:call).with([1, 2])
+ spy.should_receive(:call).with([1, 2, 3])
+
+ subject.call
+ subject.call(1)
+ subject.call(1, 2)
+ subject.call(1, 2, 3)
+ end
+end
diff --git a/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_function_wrapper_spec.rb b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_function_wrapper_spec.rb
new file mode 100644
index 0000000000..4c25f6ec1c
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/jruby_function_wrapper_spec.rb
@@ -0,0 +1,66 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+require_relative "spec_helper"
+
+describe Java::RxLangJruby::JRubyFunctionWrapper do
+ let(:spy) { double(:spy, :call => nil) }
+ subject { described_class.new(JRuby.runtime.get_current_context, lambda {|*args| spy.call(args); args}) }
+
+ let(:interfaces) do
+ [Java::RxUtilFunctions::Func0,
+ Java::RxUtilFunctions::Func1,
+ Java::RxUtilFunctions::Func2,
+ Java::RxUtilFunctions::Func3,
+ Java::RxUtilFunctions::Func4,
+ Java::RxUtilFunctions::Func5,
+ Java::RxUtilFunctions::Func6,
+ Java::RxUtilFunctions::Func7,
+ Java::RxUtilFunctions::Func8,
+ Java::RxUtilFunctions::Func9,
+ Java::RxUtilFunctions::FuncN]
+ end
+
+ it "implements the interfaces" do
+ interfaces.each do |interface|
+ subject.is_a?(interface)
+ end
+ end
+
+ it "successfully uses the interfaces" do
+ spy.should_receive(:call).with([])
+ spy.should_receive(:call).with([1])
+ spy.should_receive(:call).with([1, 2])
+ spy.should_receive(:call).with([1, 2, 3])
+ spy.should_receive(:call).with([1, 2, 3, 4])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5, 6])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5, 6, 7])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5, 6, 7, 8])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5, 6, 7, 8, 9])
+ spy.should_receive(:call).with([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+
+ subject.call.should == []
+ subject.call(1).should == [1]
+ subject.call(1, 2).should == [1, 2]
+ subject.call(1, 2, 3).should == [1, 2, 3]
+ subject.call(1, 2, 3, 4).should == [1, 2, 3, 4]
+ subject.call(1, 2, 3, 4, 5).should == [1, 2, 3, 4, 5]
+ subject.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, 4, 5, 6]
+ subject.call(1, 2, 3, 4, 5, 6, 7).should == [1, 2, 3, 4, 5, 6, 7]
+ subject.call(1, 2, 3, 4, 5, 6, 7, 8).should == [1, 2, 3, 4, 5, 6, 7, 8]
+ subject.call(1, 2, 3, 4, 5, 6, 7, 8, 9).should == [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ subject.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).should == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ end
+end
diff --git a/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/performance.rb b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/performance.rb
new file mode 100644
index 0000000000..fc9cde1b0b
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/performance.rb
@@ -0,0 +1,52 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+# Current execution times:
+# Without rxjava-jruby: 3.31s
+# With rxjava-jruby: 2.18s
+
+require 'optparse'
+
+options = {}
+OptionParser.new do |opts|
+ opts.banner = "Usage: jruby --profile.api performance.rb [options]"
+
+ opts.on("-c", "--core CORE-PATH", "Path to the rxjava-core.jar") {|core| options[:core] = core}
+ opts.on("-j", "--jruby [JRUBY-PATH]", "Path to the rxjava-jruby.jar (optional)") {|jruby| options[:jruby] = jruby}
+end.parse!
+
+require options[:core]
+
+if options[:jruby]
+ require options[:jruby]
+ require 'rx/lang/jruby/interop'
+end
+
+require 'jruby/profiler'
+
+profile_data = JRuby::Profiler.profile do
+ 10000.times do
+ o = Java::Rx::Observable.create do |observer|
+ observer.onNext("one")
+ observer.onNext("two")
+ observer.onNext("three")
+ observer.onCompleted
+ Java::RxSubscriptions::Subscription.empty
+ end
+ o.map {|n| n * 2}.subscribe {|n| n}
+ end
+end
+
+profile_printer = JRuby::Profiler::FlatProfilePrinter.new(profile_data)
+profile_printer.printProfile(STDOUT)
diff --git a/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/spec_helper.rb b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/spec_helper.rb
new file mode 100644
index 0000000000..99b095960f
--- /dev/null
+++ b/language-adaptors/rxjava-jruby/src/spec/ruby/rx/lang/jruby/spec_helper.rb
@@ -0,0 +1,15 @@
+# Copyright 2013 Mike Ragalie
+#
+# 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.
+
+require "rx/lang/jruby/interop"
diff --git a/settings.gradle b/settings.gradle
index 8750fab727..1412d8b263 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,6 +2,7 @@ rootProject.name='rxjava'
include 'rxjava-core', \
'language-adaptors:rxjava-groovy', \
'language-adaptors:rxjava-clojure', \
+'language-adaptors:rxjava-jruby', \
'language-adaptors:rxjava-scala', \
'language-adaptors:rxjava-scala-java', \
'rxjava-contrib:rxjava-swing', \