Как вернуть Jruby proc / block / closure в java и вызвать его - PullRequest
4 голосов
/ 31 июля 2011

Мне бы хотелось иметь возможность возвращать блоки из встроенного экземпляра jruby в обычную java.Мой код Java должен быть в состоянии передать требуемые параметры (допустим, он знает правильную арность) и затем получить результат.Любые образцы будут оценены.

1 Ответ

1 голос
/ 11 сентября 2011

Если вы можете выполнять прямое встраивание, используйте 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/

...