BeanShell その2

今回はBeanShellの使い方をメモっておく。

 

1)Beanshellのダウンロード先 : 

http://www.beanshell.org/download.html

ここでbsh-X.XXX.jarをダウンロードする。

  

2)実行

BeanshellにはコンソールモードとGUIモードがある

 

テキストモードの実行方法:

java -jar bsh-X.XXX.jar

又は

java -cp bsh-X.XXX.jar; bsh.Interpreter

 

GUIモードは

java -cp bsh-X.XXX.jar; bsh.Console

 

3)基礎

文法はJavaと同じ。

違うのはInterpreterなので一行ずつ解析するということ。

また、クラス宣言ができないなどの一部制限もあるようだ。

 

BeanShellを実行すると以下のようなプロンプトが現れる。

 

bsh %

 

このプロンプト上でコードを一行ずつ実行させることができる。

以下は試しに打ってみたもの。

bsh % System.out.println("Hello");

Hello

bsh % import java.io.File;

bsh % File file = new File(".");

bsh % System.out.println(file.getCanonicalPath());

D:\down

bsh %

 

BeanShellでは変数宣言時に型宣言を省略することができる。

bsh % import java.math.BigDecimal

bsh % money = new BigDecimal("500"); // 型宣言を省略。 

bsh % System.out.println(money);

500

 

もちろん、LinuxのshファイルやWindowsのbat・cmdファイルのように

シェルスクリプトとしても活躍できる。

 

以下のソースをtest.bshに保存しておく。

import java.io.File; 

File current = new File("."); 

for (file : current.listFiles()) {

    System.out.println(file);

}

   

それから、コマンドプロンプトから以下を入力して実行できる。

java -cp down\bsh-2.0b4.jar bsh.Interpreter test.bsh

  

又は、BeanShellのプロンプト上から

 bsh % run("test.bsh");

  

という風にrunコマンドで実行できる。

 

 

runコマンドの代わりにsourceコマンドを利用すると、runコマンドと

結果は同じだが、スクリプト内の変数が続けて利用できる。

bsh % source("test.bsh")

...

結果....

...

bsh % System.out.println(current); // test.bshで宣言したcurrent変数が使える。

 

 

しかし、runコマンドではスクリプトファイル内で使った変数の利用はできない。

Java標準パッケージ以外に自作のJavaクラスも勿論利用できる。

 

4)Scripted Methods

BeanShellではメソッドを定義することができる。

 

int addTwoNumbers( int a, int b ) {

    return a + b;

}

sum = addTwoNumbers( 5, 7 );  // 12

 

マニュアルに出てるサンプルだが、public / staticなどの修飾子を

わざとつけてみてもエラーにはならなかった。

しかし、何の効果もないだろう。クラス内にメソッドがあるわけでないので...

まるでJavascriptでグロバール関数を定義したのと同じ感じ。

 

 

BeanShellではメソッド定義時、型宣言を省略することができる。

add( a, b ) {

    return a + b;

}

foo = add(1, 2);            // 3

System.out.println(foo);

foo = add("Oh", " baby");   // "Oh baby"

System.out.println(foo);

まさにJavascriptのような感じ。

 

5)Scripted Object

BeanShellではJavaと同じ文法でクラスを定義することはできないが、

Scripted Objectというのを使って複数のメソッドと変数をまとめた

オブジェクトを返すことができる。

 

例)

person(pName, pAge) {

String name = pName;

int age = pAge;

    toString() {

        return "name : " + name + ", age : " + age;

    }

    isOlderThan(other) {

        return age > other.age;

    }

    return this; // 最後にthisを返すのは必須だ。

}

bsh % duke = person("duke", 31);

bsh % java = person("java", 16)

bsh % print(duke.toString());

name : duke, age : 31

bsh % print(java.toString());

name : java, age : 16

bsh % print(duke.isOlderThan(java));

true

 

 

 

6)JavaからBeanShellを使う。

以下のサンプルソースで説明を省略する。

 

package dukelab.beanshell.test;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.StringReader;

import bsh.EvalError;

import bsh.Interpreter;

 

/**

 * BeanShellとJavaとの連携をテストします。

 *

 * @author dUkE

 */

public class BeanShellTest {

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

Interpreter ipr = new Interpreter();

// 単純に1行ずつ実行。

ipr.eval("int i = 2011;");

ipr.eval("print(i);");

// 結果 : 2011

 

// ReaderオブジェクトもOK.

StringReader sr = new StringReader(

"JOptionPane.showMessageDialog(null, \"こんなのもできるんだ。\");"

);

ipr.eval(sr);

// 結果 : ダイアログが表示される。

 

 

// スクリプトファイルの実行も勿論可能。

ipr.source("test.bsh");

// 結果 : ファイルのリストが出力される。

 

 

// Java側で変数をBeanShellのコンテキストに予め入れておくとスクリプト内で使用できる。

ipr.set("thisYear", 2011);

ipr.eval("print(\"this year : \" + thisYear);");

// 結果 : this year : 2011

 

 

// 実行した結果はJava側で使える。

File f = (File) ipr.eval("f = new File(\".\");");

System.out.println("path : " + f.getCanonicalPath());

// 結果 : path : 現在のディレクトリ。

}

}

7)自動importされるパッケージ

javax.swing.event

javax.swing

java.awt.event

java.awt

java.net

java.util

java.io

java.lang

8)BeahShellの主要コマンド

ディレクトリ関連

dir()

source()

run(),

cat()

load()

save()

mv()

rm()

addClassPath()

javap() - 指定したオブジェクトが持っているメンバーを見ることができる。

APIを調べたい時に便利だろう。

例)結果は皆同じ。

javap( Date.class );

javap( new Date() );

javap( "java.util.Date" );

javap( java.util.Date );

  

BeanShellの終了はexit()コマンドを使う。

 

importCommandsコマンドを使うと自分だけのコマンドが作れる。

 

9)BeanShellの活用

以下は私が個人的に注目する活用面だ。

 

実際、BeanShellだけでなく、Groovy、JRubyなど他のスクリプト言語でも

可能なことでもある。

だから「BeanShellの活用」ではなく「スクリプト言語の活用」

がより正しいタイトルだと思われるが、BeanShellのメモなので、

そのままおいておく。

 

1)プログラムの機能の一部をスクリプトで実装する。

=> コンパイルが要らないし、結果をその場で確認できるので、アジャイルな開発に役立ちそうだ。

   アジャイルな開発? 簡単に言って"効率よく、早く開発する"を意味する。

 

   コアな部分は、かなり重要なので以前のようにJavaで作るのが正しい。

それ以外の機能的な部分はスクリプトで作成したりすると、開発スピードがあがるような気がする。

 

   機能の一部にスクリプトを使うプログラムは数多くある。

   例えば、

   AutoCadではLisp言語を

   World of WarcraftではLua言語を

   EmacsではLisp言語を使う。

 

   そんな理由で私はCompile + Interpreterのハイブリッド形式を最近、注目しつつある。

 

2)設定ファイルに動的にな設定ロジックを組み込める。

=> 例えば、年齢制限を男性 : 30歳未満、女性 : 25歳未満とする。

   これは既存の方式ではどうしてもロジックの方(つまりJavaクラス)に入れなければならない。

 

   性別が男子か女性かを判別するロジックを設定ファイルに書くことができなかったからだ。

   しかし、スクリプトを使えば、例えば、

   age = (sex == "男性" && age < 30 || (sex == "女性" && age < 25)   

のように書くことができる。適当な例だが、私のためのメモなのでこれで十分だと思う(笑)。

 

10)総評

JavascriptJavaを連携するのと変わりないような気もしたが、

Javaをそのままスクリプトで活用できるということは非常に魅力的だ。

Java文法だけ知っていれば、Javaの全ての資産をスクリプトで利用できるからだ。

JSR-274 the BeanShell Scripting Languageという標準もあるので

ただのJavaライブラリではない、標準のものなので、習っておくのも

悪くはないと思う。

しかも実行に必要なjarファイルは機能の割りにスーリムそのままだ。

(フール版が276KB、コア版が141KB)

 

さあ、使ってみようじゃないか。

 

11)参考URL

http://www.beanshell.org/

http://allabout.co.jp/gm/gc/80686/2/

http://journal.mycom.co.jp/column/jsr/031/index.html