プログラマメモ2 - programmer no memo2

jsr-223 - 追記中 2017/01/09
2021/03/14

jsr-223です。


javaからJVM言語をスクリプト実行したいです。
主観ですが、メジャーな言語と思えるものを調べてみました。
かなりおおざっぱです。

対象
 clojure,groovy,scala,jruby,jython,kotlin, javascript


言語 engine name(shortName) Factoryクラス JAR 特記
Clojure Clojure clojure.contrib.jsr223.ClojureScriptEngineFactory clojure-jsr223-1.2.jar  
Groovy Groovy org.codehaus.groovy.jsr223.GroovyScriptEngineFactory groovy-jsr223-2.4.7.jar  
Scala scala scala.tools.nsc.interpreter.IMain$Factory scala-compiler-2.11.8.jar -Dscala.usejavacp=true
Kotlin kotlin org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory kotlin-jsr223-local-example-1.1-M04-eap-14.jar  
JRuby jruby org.jruby.embed.jsr223.JRubyEngineFactory jruby-complete-9.1.6.0.jar -Dpython.import.site=FALSE
Jython jython org.python.jsr223.PyScriptEngineFactory jython-2.7.0.jar  
javascript javascript com.sun.script.javascript.RhinoScriptEngineFactory#java7 resources.jar java8はNashorn


jsr-223って、もともとサーバーサイドで各種スクリプト言語の実行を目指したもののようですね。

こうやってみてみるとJVM言語っていろいろありますね。かなり貪欲というか。

呼び出し方は、ScriptEngineManagerにたいして、エンジン名を指定して、ScriptEngineを取得します。取得できない場合は、nullが返ってくるようです。

ちなみに、各ScriptEngineFactoryはプログラムの起動時に行われるようです。ScriptEngineFactoryの定義は、各ライブラリ(jar)のMETA-INF/services/javax.script.ScriptEngineFactory ファイルに記述されています。
ですので、このファイルを探せばよいというのがわかります。ただし、このファイルに記述されているのに実際のクラスがない場合、不幸なことにプログラム全体が起動しません。
# 遅延ロードでできないのかしら?

参考 clojure


以下、呼び出しソース

package jsr223; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class TestMain { public static void main(String[] args) throws ScriptException { a(); } static void a() throws ScriptException { // まとめて実行するとjava.lang.OutOfMemoryErrorする.... jsr223_noengine(); jsr223_Clojure(); jsr223_Groovy(); jsr223_Scala(); jsr223_JRuby(); jsr223_Jython(); jsr223_Javascript(); jsr223_Kotlin(); } static void jsr223_noengine() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "xxxx";// 存在しないものを指定 final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); if (scriptEngine == null) { System.out.println("*** 存在しないものを指定した場合は、script engineはnullになります。"); } else { scriptEngine.eval(""); } } static void jsr223_Clojure() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Clojure"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("(println \"clojure \")"); } static void jsr223_Groovy() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "Groovy"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println \"groovy \""); } static void jsr223_Scala() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "scala"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"scala \")"); } static void jsr223_JRuby() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jruby"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("printf \"jruby \n\""); } static void jsr223_Jython() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "jython"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print 'jython'"); } static void jsr223_Javascript() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "javascript"; // java7 Rhino java8 Nashorn final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("print('javascript')"); } static void jsr223_Kotlin() throws ScriptException { final ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); final String shortName = "kotlin"; final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(shortName); scriptEngine.eval("println(\"Kotlin\")"); } }


 参考

org.jruby.Rubyをシンクロして使う。 2008/09/04

JRubyです。

org.jruby.Rubyオブジェクトを使いまわしてスクリプトを実行する際に、グローバル変数を使ってJRubyに値を渡すとき、org.jruby.Rubyをシンクロしないといけないよというお話。

以下、スレッドをぽこぽこ起こして、org.jruby.Rubyにグローバル変数経由で値をわたすと意図せずまざります。
org.jruby.Rubyを生成するコストはばかにならないので、newしてぽこぽこ生成したくはないです。

あたりまえといえばあたりまえですが、使うorg.jruby.Rubyをsynchronizedブロックにしてしまいます。

テスト用のjrubyのスクリプト

p $a + ' ' + $b + ' ' + $c + ' ' + $d + ' ' + $e + ' ' + $f + ' ' + $g + ' ' + $h


このスクリプトの意図はグローバル変数が途中で書き換わると、値に一貫性がなくなることをチェックするためです。

シンクロしないとものの見事に、一貫性がなくなることが確認されます。

以下うまくいったコード

package test_jruby;

import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;

public class Test_multi {

public static void main(String[] args) throws IOException {

final Ruby ruby = Ruby.newInstance();
final String script = script("test_multi_glv_1.jruby", "MS932");
for (int i = 0; i < 10000; i++) {

final int FI = i;
new Thread(new Runnable() {

@Override
public void run() {

String result = evalByJRuby_GLV(ruby, script,
new Object[][] { { "a", "" + FI },
{ "b", "" + FI }, { "c", "" + FI },
{ "d", "" + FI }, { "e", "" + FI },
{ "f", "" + FI }, { "g", "" + FI },
{ "h", "" + FI } });

System.out.println(result);
}
}).start();
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}

}

static public String script(String filename, String enc) throws IOException {
String script = IOUtils.getStringFromReader(new InputStreamReader(
ExperimentationJRubyScriptBase.class
.getResourceAsStream(filename), enc));
return script;
}

/**
* <p>
* Rubyスクリプトにグローバル変数で値を渡します。
* </p>
*
* @param ruby
* @param script
* @param objects
* @return
*/
public static String evalByJRuby_GLV(Ruby ruby, String script,
Object[][] objects) {

synchronized (ruby) {

if (objects != null) {
for (int i = 0; i < objects.length; i++) {
Object[] objects2 = objects[i];
if (2 <= objects2.length) {

ruby.defineVariable(new GlobalVariable(ruby, "$"
+ objects2[0].toString(), JavaEmbedUtils
.javaToRuby(ruby, objects2[1])));
}
}

}
IRubyObject result = ruby.evalScriptlet(script);
ruby.tearDown();
if (result instanceof org.jruby.RubyString) {
org.jruby.RubyString s = (org.jruby.RubyString) result;
return s.getUnicodeValue();
}
return result.toString();

}

}
}


以下うまくいかなかったコード
org.jruby.RubyのdefineVariableをする間隔で、Tread.sleepさせるとさらにまざる感じがします。

package test_jruby;

import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;

public class Test_multi {

public static void main(String[] args) throws IOException {

final Ruby ruby = Ruby.newInstance();
final String script = script("test_multi_glv_1.jruby", "MS932");
for (int i = 0; i < 10000; i++) {

final int FI = i;
new Thread(new Runnable() {

@Override
public void run() {

String result = evalByJRuby_GLV(ruby, script,
new Object[][] { { "a", "" + FI },
{ "b", "" + FI }, { "c", "" + FI },
{ "d", "" + FI }, { "e", "" + FI },
{ "f", "" + FI }, { "g", "" + FI },
{ "h", "" + FI } });

System.out.println(result);
}
}).start();
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}

}

static public String script(String filename, String enc) throws IOException {
String script = IOUtils.getStringFromReader(new InputStreamReader(
ExperimentationJRubyScriptBase.class
.getResourceAsStream(filename), enc));
return script;
}

/**
* <p>
* Rubyスクリプトにグローバル変数で値を渡します。
* </p>
*
* @param ruby
* @param script
* @param objects
* @return
*/
public static String evalByJRuby_GLV(Ruby ruby, String script,
Object[][] objects) {

// synchronized (ruby) {

if (objects != null) {
for (int i = 0; i < objects.length; i++) {
Object[] objects2 = objects[i];
if (2 <= objects2.length) {

ruby.defineVariable(new GlobalVariable(ruby, "$"
+ objects2[0].toString(), JavaEmbedUtils
.javaToRuby(ruby, objects2[1])));
}
}

}
IRubyObject result = ruby.evalScriptlet(script);
ruby.tearDown();
if (result instanceof org.jruby.RubyString) {
org.jruby.RubyString s = (org.jruby.RubyString) result;
return s.getUnicodeValue();
}
return result.toString();

// }

}
}

ルビーの練習 - メソッド 2008/09/04

JRubyです。


いまいちクロージャーとブロックとメソッドの仕組みがわかってないです。

とりあえず、メソッドで実験。
メソッドをハッシュに格納してとりだして利用するって感じのことがしたいのでした。
callを使うといいようです。callを使わないでも実行できないのかしら。

サンプル
#
def hello( name )
p "hello, " + name
end

hello "ugo!!"

hello_m = method :hello
(method :hello).call "ugo"
hello_m.call "o_o!"
hello("-_-!")
n = {"hello" => hello_m , "hey" => :hello }
p hello_m
n['hello'].call("OKo_o!")
p n['hey']


結果
"hello, ugo!!"
"hello, ugo"
"hello, o_o!"
"hello, -_-!"
#<Method: Object#hello>
"hello, OKo_o!"
:hello



Javaコード
package test_jruby;

import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;

public class Test_Executor {

public static void main(String[] args) throws IOException {

final Ruby ruby = Ruby.newInstance();
final String script = script("test_method.jruby", "MS932");
evalByJRuby_GLV(ruby, script, new Object[][] {});

}

static public String script(String filename, String enc) throws IOException {
String script = IOUtils.getStringFromReader(new InputStreamReader(
ExperimentationJRubyScriptBase.class
.getResourceAsStream(filename), enc));
return script;
}

/**
* <p>
* Rubyスクリプトにグローバル変数で値を渡します。
* </p>
*
* @param ruby
* @param script
* @param objects
* @return
*/
public static String evalByJRuby_GLV(Ruby ruby, String script,
Object[][] objects) {

synchronized (ruby) {

if (objects != null) {
for (int i = 0; i < objects.length; i++) {
Object[] objects2 = objects[i];
if (2 <= objects2.length) {

ruby.defineVariable(new GlobalVariable(ruby, "$"
+ objects2[0].toString(), JavaEmbedUtils
.javaToRuby(ruby, objects2[1])));
}
}

}
IRubyObject result = ruby.evalScriptlet(script);
ruby.tearDown();
if (result instanceof org.jruby.RubyString) {
org.jruby.RubyString s = (org.jruby.RubyString) result;
return s.getUnicodeValue();
}
return result.toString();

}

}
}

JavaからJRubyへStringしてgetBytesしたい 2008/09/03

JavaからStringをJRubyに渡してgetBytesしたい。

こんな感じにしてみた。

Java::java::lang::String::new(s).getBytes("shift_jis").length

直接、s.getBytes()みたいにしたいんだけど.....

org.jruby.Rubyのイニシャルコスト 2008/08/31

JRubyです。

どうもjavaからJRubyにスクリプトを喰わせて実行させる際に、カクカクとなってしまいました。何度やってもカクカクするので、どうしてこんなに遅いんだろうと思って、いろいろ試してみてどうも毎回、org.jruby.Ruby.newInstance()するのがいけないようです。

下手すると 充分回数実行すると,outofmemoryが....

org.jruby.Rubyを使い回した場合、ものすごーくはやくなりました。

しかし、別の問題がおきました。
実ははじめ、スクリプト側に値を渡すときに、ruby.defineVariableを使っていて、毎回、newしていたので、別にいいやと考えていたのですが、グローバル変数であるなら複数回の呼び出しがある場合には、スクリプト側に値を渡すに不向き(値がまざってしまうから)ということになってしまいます。

bsf経由でJrubyを使うときも、同じ問題(初期化コストが馬鹿にならない)がありそうな気がします。

org.jruby.javasupportパッケージのJavaUtilとJavaEmbedUtils 2008/08/31

JRubyです。

しばらく、Javaからスクリプトを呼び出すところで試行錯誤しています。
いろいろ試していてまあこれでいいかなぁと思ったところで、困ったことが。

Javaから生成されたインスタンスを渡すのですが、JRuby側でどうしてもそのインスタンスのメソッドにアクセスできなかったのです。

NoMethodErrorとかでてしまいました。

前できたのにどうしてかなぁと悩んでいましたら、Java側のオブジェクトをJRuby側に変換する際に使用していたユーティリィがJavaUtil.convertJavaToRubyであることに気がつきました。

Java側の機能をそのまま引き継ぎたい場合は、JavaEmbedUtils.javaToRubyを使うのが正しいようです(多分)。

ちなみに,JavaEmbedUtils.javaToRubyの実装みてなるほどとわかるのですが、内部では、JavaEmbedUtils.javaToRubyを使用しています。そこで変換されたオブジェクトがorg.jruby.javasupport.JavaObjectであった場合,Java.wrapでラップするとかいう処理になっています。

あと、JavaEmbedUtils.javaToRubyは、2つ引数と、3つ引数があるのですが、Classを指定する3つ引数をわざわざ使わなくても2つ引数でいいようです。内部で、object.getClass()して3つ引数のメソッドを使っているので。

結論は、僕は、JavaEmbedUtils.javaToRubyを使うでしょうかね。

JRubyにJavaから日本語渡して返してもらう。 2008/08/31

JRubyです。

Javaから日本語を渡してJRuby側で判断して文字列を返すというコードを目指します。

ここ数日いろいろトライして結構検討はずれなことしてます。
※ここでやっていることは徒労なのかもしれませんが....

require "kconv"
を使ってスクリプト側で、日本語をtoutf8して、Java側から渡された文字列と比較するといい感じでした。
あとスクリプト側からJavaに返す際に、utf8してあげると、Java側でうまく表示できました。

使ったJavaはjava6です。
JRubyは、jruby-complete-1.1.2.jarです。実行は、eclipseで行いコンソールで出力を確認しています。

うまくいかなかったスクリプト

case v
when "沖縄"
"沖縄!!"
when "東京"
"東京!!"
when "神戸"
"神戸!!"
else
"該当せず。"
end


結果
?Y???????B



うまくいったスクリプト
require "kconv"して、文字列をtoutf8していってます。
こんなことしなくてもいいのかもしれないです。
require "kconv"
case v
when "沖縄".toutf8
"沖縄!!".toutf8
when "東京".toutf8
"東京!!".toutf8
when "神戸".toutf8
"神戸!!".toutf8
else
"該当せず。".toutf8
end


結果
沖縄!!


以下、Javaコードです。

package test_jruby;

import java.io.IOException;

import org.jruby.Ruby;

import static test_jruby.ExperimentationJRubyScriptBase.*;

public class Test_japanese_1 {

public static void main(String[] args) throws IOException {

Ruby ruby = Ruby.newInstance();

String script = script("test_japanese_1.jruby", "MS932");

String result = evalByJRuby(ruby, script, new Object[][]{{"v", "沖縄"}});

System.out.println(result);
}

}


package test_jruby;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.builtin.IRubyObject;

public class ExperimentationJRubyScriptBase {


/**
* <p>
* このメソッドで受け取るscriptはメソッド定義のされていない裸のスクリプトを想定しています。
* </p>
*
* @param ruby
* @param script
* @param objects
* @return
*/
public static String evalByJRuby(Ruby ruby, String script,
Object[][] objects) {

/*
* メソッド引数を作成する
*/
List<IRubyObject> list = new ArrayList<IRubyObject>();

//
final String M = "doprocess" + System.nanoTime();

StringBuilder builder = new StringBuilder();

builder.append("def " + M + " (");
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
Object[] objects2 = objects[i];
if (2 <= objects2.length) {
builder.append(objects2[0].toString() + ",");
list.add(JavaUtil.convertJavaToRuby(ruby, objects2[1],
objects2[1].getClass()));
}
}

}

// 最後のカンマがあれば削除
if (builder.charAt(builder.length() - 1) == ',') {
builder.deleteCharAt(builder.length() - 1);
}
final String LS = System.getProperty("line.separator");
builder.append(")").append(LS).append(script).append("end");

script = builder.toString();
// System.out.println(script);
RubyRuntimeAdapter rubyRuntimeAdapter = JavaEmbedUtils
.newRuntimeAdapter();

IRubyObject[] params = new IRubyObject[list.size()];

list.toArray(params);

IRubyObject result = rubyRuntimeAdapter.eval(ruby, script).callMethod(
ruby.getCurrentContext(), M, params);

ruby.tearDown();

// System.out.println("*** " + result.getClass());

if (result instanceof org.jruby.RubyString) {
org.jruby.RubyString s = (org.jruby.RubyString) result;
return s.getUnicodeValue();
}
return result.toString();
}

static public String script(String filename, String enc) throws IOException {
String script = IOUtils.getStringFromReader(new InputStreamReader(
ExperimentationJRubyScriptBase.class
.getResourceAsStream(filename), enc));
return script;
}

}

jruby エンコード実験 その2 2008/08/30

JRubyです。

Javaから一部の処理をJRubyにまかせてその結果をJava側に戻すというプログラむをしたいのですが、日本語を渡してJRuby側でマッチさせようとしてくれません。
※僕が単純にまちがっている可能性大。

$paramにはJava側で"沖縄"を入れているとして、

if $param == "沖縄" then

をしたいのですが、失敗します。

いろいろ試してみました。
その結果、jruby側での値をいったんto_java_bytesを使って配列にしてそれをjava側でStringにして比較するという方法でマッチしました。

参考

JRubyスクリプト
p "沖縄"
p $param
b = String.from_java_bytes "沖縄".to_java_bytes
p b
$jruby_support::out("沖縄".to_java_bytes)
$jruby_support::out($param)

if $param == $jruby_support::convert("沖縄".to_java_bytes) then
print "yes okinawa \n"
else
print "not okinawa \n"
end

if $param == "沖縄" then
print "yes okinawa \n"
else
print "not okinawa \n"
end

if $param == Java::java::lang::String::new("沖縄".to_java_bytes) then
print "yes okinawa \n"
else
print "not okinawa \n"
end


結果
"\211\253\223\352"
"\346\262\226\347\270\204"
"\211\253\223\352"
*** out arg bytes
-119 -85 -109 -22
*** out arg string
-119 -85 -109 -22
yes okinawa
not okinawa
not okinawa


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.bsf.BSFException;
import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.KCode;

public class JRUBYTest4 {

public static void main(String[] args) throws BSFException,
UnsupportedEncodingException, IOException {
String script = IOUtils
.getStringFromReader(new InputStreamReader(TestBSF_jruby.class
.getResourceAsStream("test_jruby_4.jruby"), "utf8"));
Ruby ruby = Ruby.newInstance();
//ruby.setKCode(KCode.SJIS);
//ruby.setKCode(KCode.UTF8);
//ruby.setKCode(KCode.NONE);

IRubyObject param = JavaEmbedUtils.javaToRuby(ruby, "沖縄");
IRubyObject param2 = JavaEmbedUtils.javaToRuby(ruby, "abcd");
IRubyObject jrubySupport = JavaEmbedUtils.javaToRuby(ruby, new JRubySupport());
ruby.defineVariable(new GlobalVariable(ruby, "$param", param));
ruby.defineVariable(new GlobalVariable(ruby, "$param2", param2));
ruby.defineVariable(new GlobalVariable(ruby, "$jruby_support", jrubySupport));

Object obj = ruby.evalScriptlet(script);
System.out.println(obj);
ruby.tearDown();
}

static public class JRubySupport {
public void out(String s) throws UnsupportedEncodingException {
System.out.println("*** out arg string");
for (byte b : s.getBytes()) {
System.out.print(b + " ");
}
System.out.println();

}
public void out(byte[] s) throws UnsupportedEncodingException {
System.out.println("*** out arg bytes");
for (byte b : s) {
System.out.print(b + " ");
}
System.out.println();

}
public String convert(byte[] b){
return new String(b);
}
public String convert(String s){
return s;
}
}

}

jruby エンコード実験 2008/08/30

JRubyです。

javaからjrubyにパラメータを渡してそのパラメータとjrubyスクリプト側で設定した値をマッチさせたいと思ったのですが、日本語だとどうも上手くいかないです。

解決策がみつからないのでとりあえず実験コードです。
osx上で動作させているeclipseで実験
jdk1.5 jruby 1.1.3

条件

スクリプトファイルはsjisで保存。
スクリプトを読み込ませるときにsjis指定で読み込ませます。
ruby.setKCode(KCode.NONE);


出力
"\211\253\223\352"
"\346\262\226\347\270\204"
"abcd"
"abcd"


条件
スクリプトファイルはsjisで保存。
スクリプトを読み込ませるときにsjis指定で読み込ませます。
ruby.setKCode(KCode.SJIS);


出力
"沖縄"
"豐也\270\204"
"abcd"
"abcd"


条件
スクリプトファイルはutf8で保存。
スクリプトを読み込ませるときにutf8指定で読み込ませます。
ruby.setKCode(KCode.NONE);


出力
"\211\253\223\352"
"\346\262\226\347\270\204"
"abcd"
"abcd"


条件
スクリプトファイルはutf8で保存。
スクリプトを読み込ませるときにutf8指定で読み込ませます。
ruby.setKCode(KCode.UTF8);


出力
"\211\253\223\352"
"豐也ク?"
"abcd"
"abcd"


jrubyスクリプト
p "沖縄"
p $param
p "abcd"
p $param2


使ったjavaコード
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.bsf.BSFException;
import org.apache.bsf.util.IOUtils;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.GlobalVariable;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.KCode;

public class JRUBYTest3 {

public static void main(String[] args) throws BSFException,
UnsupportedEncodingException, IOException {
String script = IOUtils
.getStringFromReader(new InputStreamReader(TestBSF_jruby.class
.getResourceAsStream("test_jruby_3_utf8.jruby"), "utf8"));
// String script = IOUtils
// .getStringFromReader(new InputStreamReader(TestBSF_jruby.class
// .getResourceAsStream("test_jruby_3_sjis.jruby"), "sjis"));
Ruby ruby = Ruby.newInstance();
//ruby.setKCode(KCode.SJIS);
ruby.setKCode(KCode.UTF8);
//ruby.setKCode(KCode.NONE);

IRubyObject param = JavaEmbedUtils.javaToRuby(ruby, "沖縄");
IRubyObject param2 = JavaEmbedUtils.javaToRuby(ruby, "abcd");

ruby.defineVariable(new GlobalVariable(ruby, "$param", param));
ruby.defineVariable(new GlobalVariable(ruby, "$param2", param2));

Object obj = ruby.evalScriptlet(script);
System.out.println(obj);
ruby.tearDown();
}

}

returnを省略できる言語 2008/07/19

Javaではreturnを省略して書くことができません。
どいうことかといいますと
ある処理が、何らかの値を返すとして、

return 何らかの値;

とは書けても
何らかの値;

という記述はしません。

perl,ruby,groovyとかそういう記述の仕方ができます。

普段とくにそういうことは、そういうもんだと理解して、気にもとめないのですが、
BSFを使ってJavaからスクリプトを実行する場合のそのスクリプトの記述で悩みました。

JRubyを使ったのですが、何気に
new BSFManager().eval("ruby", "(java)", 1, 1, "return 'OK'");

とついついしたわけです。
素直に文字列OKを返してくれるだろうと....
例外がでます。

evalは式を評価してその結果を返すわけです。
returnを書く必要などないわけですが、何故かreturnを書きたくて仕方がない自分(笑)

上記のコードは、
new BSFManager().eval("ruby", "(java)", 1, 1, "'OK'");

でevalがOKを返してくれます。
returnが使えるのは、
new BSFManager().eval("ruby", "(java)", 1, 1, "def a¥n 'OK' ¥n end ¥na()");

メソッド定義した場合のようです。

ちなみに
new BSFManager().eval("ruby", "(java)", 1, 1, "a='OK'");

としてもOKが返されます。

参考

jruby-complete.jarには必要なライブラリが含まれている。 2008/06/26
2008/06/27

同僚の方に教えてもらったのですが、jruby-complete.jarには必要なものが全部ふくまれているそうです。

参考



さらに教えてもらったのは、jruby-complete.jarの新しいバージョンだけど、
jrubyのhttp://dist.codehaus.org/jruby/にない場合はmavenのリポジトリ(レポジトリ)にあるかもよ。

JavaからJRubyメソッドに引数をわたしてみる。 2008/05/15

JavaからJRubyで定義したメソッドを呼び出します。
引数渡して結果をもらうことをしてみます。

下記の参考サイトを見よう見まねで試してみました。

参考



目指すはDSLですかね。

ここでは、rubyスクリプトを作ってevalしてますが、これがファイルならファイルを読み込んでevalすればよいわけですね。

ところでどこにjavadocあるんでしょうかね?
調べたいのは、RubyRuntimeAdapter,JavaEmbedUtils,JavaUtil,IRubyObject
とりあえずこれらのクラスは調べておいたほうがよいでしょう。

import java.util.ArrayList;
import org.jruby.Ruby;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.builtin.IRubyObject;
public class Ttt {
public static void main(String[] args) throws Exception {
// jrubyに必要なlibへのパスを指定する?
Ruby ruby = JavaEmbedUtils.initialize(new ArrayList<String>());
// evalするぞ
RubyRuntimeAdapter evaler = JavaEmbedUtils.newRuntimeAdapter();
final String LS = System.getProperty("line.separator");
String script = "def hi(f)" + LS + " return 'i am ' + f " + LS + "end";

// evalします。
IRubyObject robj = evaler.eval(ruby, script);
// IRubyObject eval = evaler.eval(ruby, "hi");
// 引数用意
IRubyObject param = JavaUtil.convertJavaToRuby(ruby, "o_o!");

// 結果
IRubyObject eval = robj.callMethod(ruby.getCurrentContext(), "hi",
param);
System.out.println(eval);
}
}

GroovyかJRubyか - ...Groovyが好きかなぁ... 2007/12/02

Martin Fowler's Bliki in Japanese - GroovyかJRubyか

JRubyはほとんど触ったことがないので、Groovyかなぁ

Rubyのこと考えるとJRubyとか面白そうだけど。

Groovyが好きなのは名前が好きだから、ノリノリな感じがするので好き。

Eclipseで、使えるエディターがもっともっとよくなるといいなぁ
コード補完と、コードフォーマッターとか。

結局、Eclipseでjavaでいろいろ済ませてしまうんですよね。
ファイルの整形とかも、Eclipse上からjavaでしてしまうし。