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', \