Как да върна Jruby proc/block/closure в java и да го извикам

Бих искал възможността да връщам блокове от вграден екземпляр на jruby към обикновена java. Моят Java код трябва да може да предава необходимите параметри (да приемем, че знае правилната арност) и след това да получава резултата. Всички проби ще бъдат оценени.


person mP.    schedule 31.07.2011    source източник


Отговори (1)


Ако можете да направите директно вграждане, използвайте JavaEmbedUtils и или извикайте eval на низ от ruby ​​код, който дефинира вашия proc/block/closure, или накарайте вашия ruby ​​код да реализира интерфейс, където определени методи връщат вашия proc/block/closure. Невероятно измислен пример за сумиране на две числа по-долу:

SampleApp.java

import org.jruby.Ruby;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.RubyFixnum;
import org.jruby.RubyProc;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import java.util.ArrayList;

class SampleApp {
        public static void main(String[] args) {

                // Create runtime instance
                Ruby runtime = JavaEmbedUtils.initialize(new ArrayList());

                // Parameters
                RubyFixnum paramA = new RubyFixnum(runtime, 1);
                RubyFixnum paramB = new RubyFixnum(runtime, 2);

                // Runtime eval method
                RubyRuntimeAdapter evaler = JavaEmbedUtils.newRuntimeAdapter();
                RubyProc additionProcFromEval = (RubyProc)evaler.eval(runtime, "Proc.new { |a, b| a + b }");
                printProcResult(runtime, additionProcFromEval, paramA, paramB);

                // Interface implementation method
                SomeInterfaceImpl someImpl = new SomeInterfaceImpl();
                RubyProc additionProcFromInterface = (RubyProc)someImpl.getAdditionProc();
                printProcResult(runtime, additionProcFromInterface, paramA, paramB);

                // Shutdown and terminate instance
                JavaEmbedUtils.terminate(runtime);
        }

        protected static void printProcResult(Ruby runtime, RubyProc proc, RubyFixnum paramA, RubyFixnum paramB) {
                Block block = proc.getBlock();
                ThreadContext threadContext = ThreadContext.newContext(runtime);
                int result = (Integer)block.call(threadContext, paramA, paramB).toJava(new Integer(0).getClass());
                System.out.println("Result = " + result);
        }
}

SomeInterface.java

interface SomeInterface {
    org.jruby.RubyProc getAdditionProc();
}

SomeInterfaceImpl.rb

require 'java'
class SomeInterfaceImpl

        include Java::SomeInterface

        java_signature 'org.jruby.RubyProc getAdditionProc()'
        def getAdditionProc()
                return Proc.new { |a, b| a + b }
        end

end

И ето как можете да тествате:

javac -classpath jruby.jar SomeInterface.java
jrubyc --javac -cp . SomeInterfaceImpl.rb
javac -cp jruby.jar:. SampleApp.java
java -cp jruby.jar:. SampleApp

Препратки:

https://github.com/jruby/jruby/wiki/DirectJRubyEmbedding

http://tommy.chheng.com/2010/06/20/call-a-jruby-method-from-java/

person marzagao    schedule 11.09.2011
comment
Благодаря за усилията, но вие сте направили някои предположения, като например да приемете, че proc е съвместим с java интерфейс. Търсех нещо по-динамично без лепилото. Надявах се, че средата за изпълнение предостави помощник или нещо, което уви Proc в някакъв Java обект с var args като java.lang.refl.Method.invoke() просто работи.. - person mP.; 11.09.2011