プログラマメモ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\")"); } }


 参考

縦と横を入れ替える 2014/06/08

転置行列 - Wikipedia

javaです。java8です。

以前から、そうかなり以前から、エクセルの操作で、行と列を入れ替えて、ペーストするやり方になにかしらの思いがあるのでした。

たまに思い出したように、javaで書くのですが、まあ、すっきりしません。

groovyにはtransposeがあるので、さくっとできました。
def ssss = [ ["1", "2", "3"], ["a", "b", "c"], ["A", "B", "C"] ] ssss.each { a -> println "$a" } ssss.transpose().each { a -> println "$a" }

結果
[1, 2, 3]
[a, b, c]
[A, B, C]
[1, a, A]
[2, b, B]
[3, c, C]

縦と横の値の数が一緒であれば、配列であれば添字を入れ替えるだけで実現できます。
これが不思議なんですよね。この不思議な性質というか、これをコードにおとすとエラーチェックしなければすごくシンプルなんですよね。
ループとか繰り返しとか、関係なくて、もちろん実現するのにはループを使いますが、この入れ替えるだけが、何にか不思議で、うまく説明できませんが。
とりあえず以下
package a; public class TestKaiten2 { public static void main(String[] args) { a(); } static void a() { String[][] ssss = { { "1", "2", "3" }, { "a", "b", "c" }, { "A", "B", "C" } }; int len = ssss.length; // 行と列の数が一致していること String[][] ssss2 = new String[len][len]; for (int i = 0; i < len; i++) { for (int j = 0; j < len; j++) { ssss2[j][i] = ssss[i][j]; } } print(ssss); print(ssss2); } static void print(String[][] ssss) { for (String[] ss : ssss) { for (String s : ss) { System.out.printf("%s ", s); } System.out.println(); } } }

結果
 1 2 3
a b c
A B C
1 a A
2 b B
3 c C

java8のラムダ式の練習がてらに
package a; import static java.util.Arrays.asList; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.IntStream; public class Test2 { public static void main(String[] args) { a(); } static void a() { List<List<String>> listoflists = asList(asList("1", "2", "3"), asList("a", "b", "c"), asList("A", "B", "C")); listoflists.stream().map(list -> list).forEach(System.out::println); // 結果の入れ物 Map<Integer, List<String>> map = new HashMap<Integer, List<String>>(); // IntStream.range(0, listoflists.size()).forEach(i -> { List<String> list = listoflists.get(i); IntStream.range(0, list.size()).forEach(j -> { // getOrDefault List<String> l = map.getOrDefault(j, new ArrayList<>()); String s = list.get(j); l.add(s); // putIfAbsent map.putIfAbsent(j, l); }); }); // 結果の出力 map.entrySet().forEach(e -> { List<String> l = e.getValue(); l.forEach(s -> { System.out.printf("%s ", s); }); System.out.println(); }); } }

結果
[1, 2, 3]
[a, b, c]
[A, B, C]
1 a A
2 b B
3 c C

ふとエクセルのIF関数みたいなものをぐるーびーで表現したいと思った - groovy 2013/10/17

ふとエクセルのIF関数みたいなものをぐるーびーで表現したいと思ったわけですが、エクセルの関数がふと好ましいなと思えている自分がいることに気がついたのでした。

VBAで書くマクロは、面倒なのでさけて通りたいのですが、セルの中にイコールで記述できるのがいいなーと。
ただ、結果を返さないといけないのと、同時に他のセルをコントロールするようなことができなかったり、プログラムするというものではないので、将来いろいろ変わってくれないかしらと思いつつ。僕が期待する方向にはならないと思うけど。

僕は、むかし、エクセル嫌いだったんだけどねー

エクセルの歴史に関して、日本語のwikipediaの記述より、USのほうがこまかい


ここから本題、下のように定義してみた。
def IF = { a, b ,c -> if (a) { b() } else { c() } }

使い方は
IF(true, { print "OK" }, { print "NG" })
{}括弧でくるんであげないとだめだけど。


ふとエクセルのAND関数,OR関数みたいのをぐるーびーで表現してみようと思いたった。 2013/10/16
2014/02/23

ふとエクセルのAND関数,OR関数みたいのをgroovyで表現してみようと思いたった。
まずは可変長引数は、


つぎに、2番目の配列から最後尾までを取得は、tailでよいようだ。
というわけで、作成した結果


def and = { ... arg -> return arg[0] && (( 1 < arg.size() )? call(arg.tail()) : true) } // println and(true, true, true, false) // 適当にテスト assert and(true) == true assert and(false) == false assert and(true, true) == true assert and(true, false) == false assert and(true, true, true) == true assert and(true, true, true, false) == false assert and(true, true, false, true) == false def or = { ... arg -> return arg[0] || (( 1 < arg.size() )? call(arg.tail()) : false) } // 適当にテスト assert or(true) == true assert or(false, false) == false assert or(true, false) == true assert or(true, true) == true assert or(false, false, false) == false

ぐれいずのどめいんおぶじぇくとの自前生成のための - groovy 2013/10/12

groovyです。
grailsのドメインオブジェクトを自力で生成しようとして四苦八苦してたりしている最中です。
javaで書いたほうが実ははやいかなと思いつつも、短いコードで書けるので調べ調べしつつトライしております。

とりあえず、現状のテンプレートの感じ

/* * テンプレートの定義 */ template = { clazz -> """\ class ${ clazz.name } { ${ clazz.fields.findAll{ it != '' }.collect{ ' ' + it }.join('\n') } } """ }

若干の説明、フィールド変数をとりあえず書き出す部分。fieldsはリストです。
findAllで空の項目をはじくようにしてます。
次にcollectで先頭4文字を半角にしてインデントつけます。
最後に改行区切りでjoinして出力文字列を生成終了するイメージです。
collectでひとつひとつの項目を編集できるのは便利ですねー

1文字目を小文字にしたくて - groovy 2013/10/12

groovyです。
capitalizeはデフォルトであるんですが、その逆のuncapitalizeがないんだなーというわけで、どうしようかなと悩んでたのですが、commonsにあるのでそれを使おう。

import org.apache.commons.lang.WordUtils String.metaClass.uncapitalize { WordUtils.uncapitalize(delegate) }

metaclass使って文字列処理を拡張してみます。
便利ですね!!

で、ほんとはどういことがしたかったというと
xxx_yyy_zzz
のような文字列を
xxxYyyZzz
というふうにしたかったわけです。

こんなコードを用意してみました。

conveter2 = { s -> s.tokenize('_')*.capitalize().join().uncapitalize() } assert conveter2('xxx_yyy_zzz') == 'xxxYyyZzz'

うまくいってる気はする。

ワークブックからシートを読み込むのよ その2 - groovy 2013/10/12

groovyです。
前回からのつづき。
プログラマメモ2: ワークブックからシートを読み込むのよ - groovy
forを使わずやってみた。工夫したつもりだけど。 あとはlogicの中身を実装する感じ。
今回やってて学習したこと、メソッドをクロージャに変換できること。このやり方使えばxxx.yyyが減るから、すっきりするかな。
しかし、はまったのは、比較時に()をつけないと、クロージャーそのままとして比較してしまい、エラーになった。

いろいろためしたけど、この案はぼつにしてforまわし使うんだろうな。

// wbはpoiのワークブックのインスタンス // ワークブックのメソッドをクロージャにする def numberOfSheets = wb.&getNumberOfSheets def getSheetAt = wb.&getSheetAt // ルール定義シート読み飛ばし // @含んでいるシート名のみ対象とする def ruleSkipSheet = { name -> if( name.contains('@') ) return false true } // ルール定義シート読み込み終了 def ruleStop = { pos -> if( numberOfSheets() <= pos ) return false true } // main loop処理 def loop = { pos, logic -> if ( ruleStop(pos) ){ def sheet = getSheetAt(pos) // シート処理 logic(sheet) // 次のシートへ pos += 1 // 再帰呼び出し call(pos, logic) } return } // sheetごとの処理を行う def logic = { sheet -> if( ruleSkipSheet( sheet.getSheetName() ) ) return println " *****OK logic ${ sheet }" } // 処理実行 loop(0, logic)

ワークブックからシートを読み込むのよ - groovy 2013/10/11
2013/10/11

grailsをさわりはじめて、groovyいいなーと最近ふたたび思っているところです。

POIを使って、エクセルのシートを読み込む際に、indexを指定しないととれないのが面倒です。
groovy使うならどういうふうにするかなーというわけで、こんな感じ。

// workbookからシートをある数分読み込む
wb.getNumberOfSheets().times { i ->
    def sheet = wb.getSheetAt(i)
    println "*** ${ i } ${ sheet.getSheetName() } "
}

times使ってます。
いろいろloopのやり方があってこまります。。。

プログラマメモ2: groovy 基本ループとか
each系クロージャの中断はできない - marsのメモ
が、ここまでやっていてわかったのはgroovyのloopでクロージャなのは、break,とかcontinueが使えない

なので、やはりforを使う....

def ruleSkipSheet = { name -> if(name.contains('@')) return false true } // workbookからシートをある数分読み込む for (int i in 0..wb.getNumberOfSheets() -1 ) { def sheet = wb.getSheetAt(i) def name = sheet.getSheetName() if( ruleSkipSheet( name ) ) continue println "*** ${ i } ${ sheet.getSheetName() } " }

これで読み込むシートを名前で決定できるうえのコードだと@が入っているシートのみOKというルールにしている。

groovy mapのmap 2013/07/23

groovyです。使ったのは、2.1.6です。
 PHPをちょっと触った経験から、連想配列の連想配列をとりだすときに、

 $arr['key']['key'] 

って感じでかけたのが結構すきでした。

なんか縦x横って感じがして。

で、groovyでできるのかしらと試してみました。

結論はできました。

コード

mapOfmap = [ "a":["b":777] ]
println mapOfmap
println mapOfmap.a
println mapOfmap.a.b
println mapOfmap['a']
println mapOfmap['a']['b']

結果

[a:[b:777]]
[b:777]
777
[b:777]
777

groovyのクロージャ 練習 2008/09/02

Groovyです。
クロージャです。


Groovyのクロージャの書き方が好きかも。

def localMethod() {
def v = new Date()
return { println v }
}

def clos = localMethod()
Thread.sleep(3000)

println new Date()

// 実行
clos()


結果
Tue Sep 02 22:05:48 JST 2008
Tue Sep 02 22:05:45 JST 2008


次に下記のような書き方ができることに僕は何かしらの可能性をみているのだった。

def c = [
"a1": { println "==>a1"},
"a2": { println "==>a2"},
"a3": { println "==>a3"}
]
c.a1()
c['a2']()
def clos = c['a3']
clos()


結果
==>a1
==>a2
==>a3


ふたつめのこのc['a2']()の書き方がかっこいいと思うのだけど。

あと僕がJSONにたいしてなんとなく可能性をみているのは、キー:値の値にやはりプログラムを載せれそうなところなんだよね。

groovyでmixin 2008/07/24


Mixins - Groovy JSR - Codehausをみてるといろいろあって混乱してしまう。

自分がmixinを使いたくなる場面がいまのところ想像できないけど、惹かれるんですよねmixinに。

適当に試してみました。
犬と猫を混合させてみようとしたのですが....

class Dog {
static void bow(t, String s) {
println "bow-wow $s"
}
}
class Cat {
static void mew(t, String s) {
println "mew $s"
}
}

Cat.mixin(Dog)
new Cat().bow('a')
Dog.mixin(Cat)
new Dog().mew()

class DoggyCat {

}

DoggyCat.mixin(Dog, Cat)
new DoggyCat().bow('o_o')
new DoggyCat().mew('o_o')


bow-wow a
mew null
bow-wow o_o
mew o_o

ネタ Ruby + Groovyって? 2008/05/15

Ruby + Groovyって?

grubyとか思って、検索かけると、
gRuby Project
がでてきました。

他には、gruvyか、gruuvyとかgroobyとか。
無理ありますね。

7以上、10以下で実行 - 事前条件を少し考えた。 2008/04/27

値が7以上、10以下の場合にのみ実行 されるメソッドを考えてみた。
Javaを想定してます。

簡単に、そのメソッド自体に条件判定をさしこむ。
こんな感じになると思う。

static void a(int v){
if(!(7 <= v && v <= 10)) return;
System.out.println("processing...");
}


次に、そのメソッドの実行条件はメソッドの外で保証されいると考えてみる。
こんな感じになると思う。

{
if(!(7 <= v && v <= 10)) return;
a();
}


この実行が許される条件を、ガード条件と呼んでよいと思うのだけど、どこにおくかっていうのは、重要かなと。
AOPのような手法を使って後から、メソッドに差し込むっていうのもあるかな。
アノテーションとか使って解決するっていうのもあるかもしれない(多分)、その場合って別の処理系が必要なのかなぁ。

で、次にGroovyでクロージャで考えてみた。
ガード条件、ロジック、実行者
ガード条件はあとから差しかえやすくなることをイメージしてるんだけど...

// ガード条件
def guard = {p, v ->
if(!(7 <= v && v <= 10)) return
p()
}

// ロジック
def a = { println "processing..." }

// 実行者
def exe = {g, p, v -> g(p, v) }

exe(guard, a, 7)

無理矢理感がただよいますが、強引にjsonをgroovyにしています。 2008/04/14

groovyでjsonもどき。
無理矢理感がただよいますが、強引にjsonをgroovyにしています。
あくまでも、jsonもどきです。

単純に{}を[]にしているだけなんですが。
evalして、mapにしています。データが入っているだけならば、しかし、データ(キー、値)に{}が入ってたらアウトですが...

class G_JSON {
static void main(args) {
def s = "{'k':{'oo':'test'}}"
s = s.replaceAll("\\{", "[").replaceAll("\\}", "]")
s = new Eval().me(s)
println s.k.oo
}
}

3値論理 - 論理積 論理和 2008/03/29

3値論理 です。Groovyを使って、論理積 論理和を出力してみました。

論理積
t ^ t = t
t ^ f = f
t ^ u = u
f ^ t = f
f ^ f = f
f ^ u = f
u ^ t = u
u ^ f = f
u ^ u = u
論理和
t ∨ t = t
t ∨ f = t
t ∨ u = t
f ∨ t = t
f ∨ f = f
f ∨ u = u
u ∨ t = t
u ∨ f = u
u ∨ u = u


やはりクロージャーが使えるのはいいですね。
NullPointer例外を発生させるという小手先な方法をとっています。


class PrintThreeValued {
static void main(args) {

def printLogicalProduct = { p, q ->
try {
if(p==null || q==null) throw new NullPointerException()
printf("%s ^ %s = %s%n", p?"t":"f", q?"t":"f", (p && q)?"t":"f");
} catch (e) {
printf("%s ^ %s = %s%n", p == null ? "u" : p?"t":"f",
q == null ? "u" : q?"t":"f", ((p!=null&&!p) || (q!=null&&!q))?"f":"u");
}
}

def printLogicalDisconjunction = { p, q ->
try {
if(p==null || q==null) throw new NullPointerException()
printf("%s ∨ %s = %s%n", p?"t":"f", q?"t":"f", (p || q)?"t":"f");
} catch (e) {
printf("%s ∨ %s = %s%n", p == null ? "u" : p?"t":"f",
q == null ? "u" : q?"t":"f", ((p!=null&&p) || (q!=null&&q))?"t":"u");
}
}

def bs = [true, false, null];

def process = {c ->
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
c(bs[i], bs[j]);
}
}

}
println "論理積";
process(printLogicalProduct)
println "論理和";
process(printLogicalDisconjunction)

}
}

手習い しゅうごうのえんざん 2008/02/28
2008/02/28

Groovyです。

集合の計算


def a = [1, 2, 4]
def b = [1, 2, 3, 4]
def c = [3, 4]
def d = [1, 4]

// a ∩ (b ∪ c ∪ d)
// b ∩ (c ∪ d)
// c ∩ d

a = a - (b + c + d)
b = b - (c + d)
c = c - d
println a
println b
println c
println d


結果
[]
[2]
[3]
[1, 4]

Groovyで配列 2008/01/15
2008/01/20

うーん
そういわれれば、はてどうしたものかと一瞬悩んだ。

ついつい

def a = [1,2,3,4,5,6,7]

こうしてしまいます。これだとListなので、

def Object[] a = [1,2,3]
def b = [1,2,3] as Object[]


このどちらかでつくるっぽい。

参考
2007-12-18 - marsのメモ - Groovyで配列を作成する方法

Java コレクションを演算できるのはやはり便利だと思う。 2008/01/13
2008/01/15

コレクションを演算できるはやはり便利だと思う。
CommonsのCollectionsはまだジェネリックに対応していないようですね。




import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.collections.CollectionUtils.subtract;

public class A {

public static void main(String[] args) {
List<String> a = new ArrayList<String>(){{add("1");add("2");add("3");}};
List<String> b = new ArrayList<String>(){{add("6");add("2");add("7");}};

//差
List<String> c = (List<String>) subtract(a, b);
System.out.println(c);

}

}


Groovyで同じことをしてみます。
import static org.apache.commons.collections.CollectionUtils.subtract;

def a = [1,2,3,4,5,6,7]
def b = [1,2,4]

def c = subtract(a, b)

print c



Groovyだともっと直感的にできるっぽい。
そのまま引けばよい。

import static org.apache.commons.collections.CollectionUtils.subtract;

def a = [1,2,3,4,5,6,7]
def b = [1,2,4]

def c = subtract(a, b)
def d = a - b

assert c == d


といってもこの使い方でよいかわからないけど。

あと、共通の値を求めることができるintersectは、Groovyに用意されていた。
で、commonsのものとあわせてためしてみた。要sort。
import static org.apache.commons.collections.CollectionUtils.intersection

def a = [1,2,3]
def b = [1,2,3]

def c = intersection(a, b).sort()
def d = a.intersect(b)

assert c == d


グーグルのコレクション


Rubyのほうをちらりと見てみたら、いろいろできるようです。
Rubyリファレンスマニュアル - 機能別索引

JRubyのコンソールで試してみた。



関連

Arrays - Computing Union, Intersection, or Difference of Unique Lists

Groovy + Processingでドーナツをまわす。 2008/01/07


http://deiji.jp/tools/websupport/groovyconsole2/g.jnlp?processing=true&load=http://deiji.jp/tools/websupport/groovyconsole2/groovy/Toroid_3D.groovy&autorun=on

上記のリンクでJava Web Startが起動します。

わざわざ、Groovy + Processingで書く必要性はまったくないのだけど。
よくみるとドーナツの形がおかしいのは、適当にintでキャストしてしまったからか...


使ったコードは下記のサイトから。
Toroid \ Learning \ Processing 1.0 (BETA)

Groovyでインナークラスってまだ対応していないようです。 2008/01/07

[#GROOVY-917] Cannot instantiate Java inner class - jira.codehaus.org

インナークラスを使おうとしたら無理だったので調べたらまだ使えないようです。
1.6から対応するということなのかしら。

Groovyを本格的に使っているわけではないので、気にならなかったのですが、Javaのコードをそのまま使おうとすると怒られますね...

このコードが怒られる。

class A{

void main(args){
new A()
}

class B {

}
}