groovy little book

40
Groovy - Java { ダイナミック } スクリプト言語 Grails - ダイナミック Web アプリケーションフレームワーク 原文:マーク ボルクマン/ObjectComputing,Inc. 日本語訳: shintaro at kakutani.com 改訂版作成+Grails 追記+再編集: T.Yamamoto tyama at xmldo.jp 1

Upload: posi-sapi

Post on 07-Apr-2015

512 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Groovy Little Book

Groovy - Java用{ダイナミック}スクリプト言語Grails - ダイナミックWebアプリケーションフレームワーク

原文:マーク ボルクマン/ObjectComputing,Inc.

日本語訳: shintaro at kakutani.com

改訂版作成+Grails追記+再編集: T.Yamamoto tyama at xmldo.jp

1

Page 2: Groovy Little Book

目 次 目 次

目 次

第 I部 Groovy 4

はじめに 4

Groovy のダウンロードとインストール 5

Groovy の実行 5

文法の詳細 (の一部) 6

動的型付け 6

追加されたメソッド 6

Groovyな String 7

正規表現 (regex) 8

Groovy なスクリプト 9

演算子のオーバーロード 9

Groovy なクロージャ 10

Groovy Bean 11

Groovy List 12

Groovy Map 14

Groovy な switch文 15

Groovy Range 15

Groovy なループ 16

クロージャを受け付ける List/Map/String のメソッド 17

ファイル I/O 18

オーバーロードされた左シフト演算子 19

オブジェクト・ナビゲーション 20

Groovy なリフレクション 21

未実装メソッドをキャッチする 21

Groovy Markup 22

Groovy SQL 23

Groovlet 24

2

Page 3: Groovy Little Book

目 次 目 次

第 II部 Grails 26

Grailsとは 26

ダウンロード 26

インストール 26

クイックスタート 27

第 III部 付録 Appendix 30

Groovy リファレンス 30

Grails リファレンス 33

クラシックGroovyからの JSRシンタックスへのマイグレーション 34

Grails Tips! ドメインクラスのハック 38

Grails Tips! Grails Artefacts Class 39

参考資料 40

3

Page 4: Groovy Little Book

はじめに

第 I部

Groovy

はじめにGroovy はオープンソースのスクリプト言語である。Java で実装され、Java と緊密に統合されている。使

うにあたっては J2SDK 1.4 が必要だ。Groovy は Ruby と Python といったスクリプト言語の機能のいくつかを Java に追加している。Groovy の機能には、動的型付け、クロージャ、容易なオブジェクト・ナビゲーション、そして、List や Map を取り扱うための簡潔な文法が含まれている。こうした機能 (とさらに多くの機能)の詳細を本記事では取り上げる。

Groovy のウェブサイトから引用しよう。

”Groovy はあなたが Javaプラットフォームで手早く、簡潔に、そして楽しく作業できるように設計されました。―― Groovy は Pythonと Ruby の力強さを Java プラットフォームにもたらします。”

Groovy スクリプトではあらゆる Java クラスを利用できる。Groovy スクリプトは Javaのバイトコード(.class ファイル)へとコンパイルできるので、普通の Java クラスから呼び出すこともできる。Groovy コンパイラである groovyc は、Groovy スクリプトと Javaソースファイルの両方をコンパイルすることができるが、現状の groovyc ではいくつかの Java 文法 (たとえばネストしたクラス)が未サポートである。理論上は、アプリケーション全体を Groovy で書くことができ、そのパフォーマンス特性は Java アプリ

ケーションとほとんど等しくなるだろう。ここが、Groovy が他のスクリプト言語 (Ruby、Python、Perl、そして BeanShell)とは異なるところだ。しかし現在、Groovyの性能は Java よりも劣る。 その原因のひとつは、生成された Groovy のバイトコードがコンストラクタと private/protected メソッドを呼び出すのにリフレクションを利用しているためだ。これは将来のリリースで解決されるだろう。

Groovy の開発は James Strachan と Bob McWhirter によって始められた。James は他にもたくさんのオープンソース・プロダクトの開発に携わっている (Jelly、dom4j、Jaxen、Betwixt、そして Maven)。Bobは Jaxen と Drools(オープンソースでオブジェクト指向の Java ルールエンジン)の創始者でもある。本記事では Groovy の機能のすべてではないが、その多くを取り上げる。読者は Java の文法と Groovy の文法との比較ができる程度には Java の文法に親しんでいるものと想定する。我々が、プログラミング言語の文法を善きものとするのは何かについて全面的に合意できれば、プログラミ

ング言語の数はさほど多くは必要としないだろう。現実にはプログラミング言語が数多く存在していることを考えると、我々が合意に達していないことは明らかだ。本記事の読了後に、Java の文法でまったく充分で、Groovy の文法はシンタックス・シュガーが甘すぎて口に合わないな、と思うかもしれない。もし、あなたがそう判断したら、私としては Pat Niemeyer の BeanShell を http://www.beanshell.org から落としてきて調べてみることをお奨めする。そうではなく、Groovy の簡潔な文法が気に入ったなら、いやもうほんとグルーヴィだよね!!

4

Page 5: Groovy Little Book

GROOVY の実行

Groovy のダウンロードとインストールGroovyをダウンロードするには、以下の手順に従う。

1. http://groovy.codehaus.org/Download へアクセス2. 安定版であれば、Stable Release以下のリンクよりダウンロード時期リリース版であれば、Upcoming Release以下のリンクよりダウンロード

Groovyをインストールするには、以下の手順に従う。

1. ダウンロードした ZIPファイルを展開する。

2. 展開したディレクトリを環境変数GROOVY HOMEに設定する。

3. 環境変数 PATHに$GROOVY HOME/bin(UNIXの場合)または、%GROOVY HOME%Ubin(Windowsの場合)を設定する。

Groovy の実行Groovyのスクリプトを実行するには 4種類の方法がある。 どの方法であっても、スクリプトはパースされ

て Javaソースに変換されたうえで、 Java バイトコードへとコンパイルされる。groovysh コマンドは、Groovy のステートメントを入力できる 対話的シェルを起動する。ステートメント

は Enter キーを押すことで複数行入力できる。 ステートメントは、execute コマンド1が入力されるまで評価されない。

対話的 Swing コンソールgroovyConsole コマンドは Swing のウィンドウを起動する。ウィンドウの下部ペインにGroovy ステートメ

ントを入力する。Actions メニューから Run を選ぶとステートメントが実行される。出力は上部ペインに表示される。File メニューを使用して、スクリプトをファイルから開いたり、ファイルに保存することができる。

スクリプトファイルによる実行Groovy のスクリプトファイル (一般的には拡張子 .groovy のファイル)を次のようなコマンドから実行する

ことができる。groovy script-name.groovy

コンパイル済スクリプトによる実行Groovy スクリプトは groovyc script-name.groovy コマンドを使用して Java の .classファイルへとコンパ

イルできる。スクリプトにはルーズ・ステートメント2があったとしても、生成された .classファイルには mainメソッドが含まれているので、java scriptname コマンドを使って Java アプリケーションとして実行できる。main メソッドの内容については後述する。実行にあたってはクラスパスに Groovy の lib ディレクトリにある groovy*.jar と asm*.jar を追加する必要がある。なんと、この作業を行うためのカスタム Ant タスクも用意されている! org.codehaus.groovy.ant.Groovyc

クラスがそうだ。

1”go”コマンドでも実行可能。2明示的にはどのクラスにも属さないステートメント。

5

Page 6: Groovy Little Book

追加されたメソッド

文法の詳細 (の一部)まずは Java と Groovy の文法上の主な違いを取り上げる。細かいものについては後述する。

• 最終的なゴールは、すべての正当な Java 文法をサポートすることなのだが、まだ達成はされていない

• ステートメント終端のセミコロンは省略可能。

• メソッド引数を囲む括弧は省略可能だ。ただし、引数が無い場合や、意味が曖昧になる場合は省略できない。一方、コンストラクタ呼び出しには必ず括弧が必要だ。常に括弧を使いたい人はそうしてもよい。本記事では、括弧については省略可能な場合は省略する。

• ”return”の記述が省略可能な場合がある。メソッドが値を返す際、メソッド記述の閉じブレース (’}’)到達直前にステートメントがあれば、その値が呼び出し元に返される。

• Groovy のプロパティとメソッドのスコープはデフォルトでは public であり、Javaのように protectedではない 3。 詳細は、後述するGroovy Beanのセクションを参照

• java.lang と groovy.lang、そして groovy.util のクラスは自動的にインポートされる。

動的型付け変数、プロパティ、メソッド/クロージャの引数、そしてメソッドの戻り値において、型の宣言は省略でき

る。それらはどんな型でもとることができる。また、後から異なる型を割り当てることもできる。もちろん、プリミティブ型も利用可能だ (auto-boxing される)。型変換の多くは必要に応じて自動的に行われる。たとえば、String やプリミティブ型 (intとか)と型ラッパークラス (Integerとか)との間での型変換がそうだ。このおかげで、プリミティブ型をコレクションに追加することができる。

追加されたメソッドGroovy は java.lang.Object や java.lang.String といった標準 Javaクラスに数多くのメソッドを追加してい

る。詳細は http://groovy.codehaus.org/groovy-jdk.html を参照のこと。ここでは Object クラスに追加されたものを示す。その他のものについては後述する。

dump <class-name@hashcode property-name=property-value ...>の形式で文字列を返す。たとえば、 <Car@ef5502 make=Toyota model=Camry>といった具合だ。

print と println これらの static な print メソッドはオブジェクトの toString 値を出力する。 たとえば、 print car あるいは println car と書く。

invokeMethod リフレクションを利用して動的なメソッド呼び出しを行う。文法は、 object.invokeMethod(method-name, argument-array) だ。 次のサンプルは、4を出力する。

s = ’abcabc’ // Java の文字列method = ’indexOf’

args = [’b’, 2]

println s.invokeMethod(method, args) // 4

3これは原文の誤り。Javaのメソッドスコープのデフォルトは package-private。

6

Page 7: Groovy Little Book

GROOVYな STRING

GroovyなStringリテラル文字列は、シングルクォートまたはダブルクォートで囲む。ダブルクォートを使った場合は、埋め込み

値を利用できる。埋め込み値の文法は、 ${expression} だ。Rubyでの#の代わりに$を使用する。ダブルクォートで囲まれた文字列にひとつ以上の埋め込み値が含まれる場合、その文字列は groovy.lang.GStringオブジェクトで表現される。そうでない文字列は java.lang.Stringだ。GStringは必要に応じて java.lang.String

へと強制的に変換される。groovy.lang.GString といった Groovy クラスの Javadoc は、http://groovy.codehaus.org/api/index.html

で読むことができる。埋め込み値は toString メソッドを実装する際にとても便利だ。たとえば、

String toString() { "${name} is ${age} years old." }

複数行文字列を生成する方法は 3種類ある。以下のサンプルはすべて同じ結果になる。最後のサンプルはヒアドキュメント ("here-doc")と呼ばれるものだ。3字以内の文字をデリミタ文字列として指定すると、文字列の値には最初と 2番目のデリミタ間に現れる文字が値として設定される。"EOS" ("End Of String" の略)

はよく使われるデリミタ値だが、もちろん他の文字も使用できる。

s = " This string

spans three \"lines\"

and contains two newlines."

s = """ This string

spans three "lines"

and contains two newlines."""

s = <<<EOS

This string

spans three "lines"

and contains two newlines.

EOS

contains

引数の部分文字列を含んでいるかを調べる。 ’Groovy’.contains(’oo’) は true を返す。

count

引数の部分文字列の出現回数をカウントする。 ’Groovy Tool’.count(’oo’) は 2 を返す。

tokenize

引数で与えられたデリミタを使用して文字列をトークン化し、そのトークンのリストを返す。デリミタ引数の指定は省略できる。デフォルトでは空白文字が使用される。

’apple^banana^grape’.tokenize(’^’) は [’apple’, ’banana’, ’grape’] を返す。

minus

対象文字列から、引数として与えられた部分文字列のうち最初に出現するものを削除する。’GroovyTool’-’oo’は’GrvyTool’を返す。

multiply

引数で与えられた回数だけ対象文字列を繰り返す。’Groovy’*3は’GroovyGroovyGroovy’を返す。

7

Page 8: Groovy Little Book

正規表現 (REGEX)

正規表現 (regex)まずは、J2SE 1.4 での正規表現をおさらいしておこう。次に、Groovy がどのようにこれを拡張しているか

を議論する。J2SE 1.4 の正規表現は java.util.regexパッケージのクラスでサポートされる。Patternオブジェクト

は、コンパイルされた正規表現を表し、Pattern.compile("pattern")メソッドで生成される。正規表現の文法は Patternクラスの Javadocで解説されている。Matcherオブジェクトはマッチ対象文字列に対するマッチングの結果を保持する。Matcherオブジェクトは pattern.matcher("text")メソッドで生成される。単に文字列がパターンにマッチするのかを知りたいのであれば、matcher.matches()メソッドを使う。パターン内でバックスラッシュを使うには、さらに追加のバックスラッシュが必要だ。Groovyは正規表現を 3種類の演算子でサポートする。~"pattern"は Patternオブジェクトを生成する。こ

れは、Pattern.compile("pattern")と同じ意味である。"text"=~"pattern"は Matcherオブジェクトを生成する。これは Pattern.compile("pattern").matcher("text")と同じ意味である。"text"==~"pattern"は boolean値を返す。これは Pattern.compile("pattern").matcher("text").matches()と同じ意味である。他の追加されたメソッドについては Patternクラスと Matcherクラスの Javadocを参照のこと。

サンプルを示そう。

pattern = "\\d{5}" // 郵便番号にマッチ (5桁)

text = "63304" // 郵便番号

println text ==~ pattern // "true" が出力される

m = text =~ pattern

println m.matches() // "true" が出力される

// 次の例では、パターンはリテラル文字列でなければならない。// 変数は使えない。p = ~"\\d{5}"

m = p.matcher(text)

println m.matches() // "true" が出力される

8

Page 9: Groovy Little Book

演算子のオーバーロード

Groovy なスクリプトGroovy で書かれたスクリプトのソースは、普通は拡張子 ”.groovy” のファイルだ。スクリプトには (自由

な順序で)ルーズ・ステートメント、クラスに属さないメソッド定義、そしてクラス定義が含まれている。たとえば、

// ルーズ・ステートメントprintln ’loose statement’myMethod ’Mark’, 19println new MyClass(a1:’Running’, a2:26.2)

// クラスに属さないメソッドの定義def myMethod(p1, p2) {

println "myMethod: p1=${p1}, p2=${p2}"}

// 2つのプロパティと 1つのメソッドを持つクラスの定義class MyClass {

a1; a2String toString() { "MyClass: a1=${a1}, a2=${a2}" }

}

メソッドとクラスの定義は、使用されるよりも前になくてもよい。ルーズ・メソッド 4 は該当するスクリプトファイルに対応するクラスの static メソッドとしてコンパイルされる。たとえば、foo という名前のルーズ・メソッドが、Bar.groovy という名前のスクリプトファイルにあれば、Bar クラスの static メソッド foo としてコンパイルされる。 ルーズ・ステートメントは、自動生成される main メソッドから呼び出される run メソッドにまとめられる。groovyc を使用してスクリプトをコンパイルした場合、コンパイル後のクラスには、すべてのルーズ・ス

テートメントがまとめられた run メソッドと、この run メソッドを呼び出す main メソッドが自動で追加される。いまのところ、スクリプトから他のスクリプトを実行するためには、実行したいスクリプトをコンパイルし、

インポートしなければならない。この不具合は近いうちに修正されるはずだ。

演算子のオーバーロードGroovy は特定の演算子のオーバーロードをサポートしている。オーバーロード可能な演算子はそれぞれ、

特定のメソッドに対応づけられる。対応づけられたメソッドを実装することで、そのクラスのオブジェクトはメソッドに対応する演算子をオーバーロードできる。オーバーロード対応メソッドを、様々なパラメータの型に向けてオーバーロードすることもできる。

比較演算子a == b は a.equals(b) に対応する。a != b は !a.equals(b) に対応する。a === b は Java の a == b に

対応する。a <=> b は a.compareTo(b) に対応する。a > b は a.compareTo(b) > 0 に対応する。a >= b は a.compareTo(b) >= 0 に対応する。a < b は a.compareTo(b) < 0 に対応する。a <= b は a.compareTo(b) <= 0 に対応する。比較演算子は null をハンドルするので、NullPointerException は絶対に発生しない。null はどんな

オブジェクトよりも小さいものとして扱われる。Groovy の == 演算子は、両辺のオブジェクトが等価であるかをテストし、=== 演算子は両辺がメモリ上で

同一のオブジェクトであるかをテストすることに注意。compareTo メソッドは int を返す。返す数値は、a < b の場合は負の値、a > b の場合は正の値、同値

の場合は 0である。

その他の演算子a + b は a.plus(b) に対応する。a - b は a.minus(b) に対応する。a * b は a.multiply(b) に

対応する。a / b は a.divide(b) に対応する。a++ と ++ a は a.increment(b) に対応する。a-- と --a は a.decrement(b) に対応する。a[b] は a.get(b) に対応する。a[b] = c は a.put(b, c) に対応する。

4明示的にはどのクラスにも属さないメソッド。

9

Page 10: Groovy Little Book

GROOVY なクロージャ

Groovy なクロージャクロージャとは、パラメータを受け取ることも可能なコード片のことである。

個々のクロージャは、groovy.lang.Closure を継承した新しいクラスとしてコンパイルされる。クロージャの継承クラスは call メソッドを持つ。このメソッドはクロージャの実行と、パラメータを渡すために利用される。クロージャは、自身が生成されたスコープにある変数を読み書きできる。クロージャ内部で生成された変数は、クロージャが起動されたスコープで有効になる。クロージャは変数に代入しておくことができ、それをメソッドに引数として渡すこともできる。この特徴は List や Map、そして String のメソッドで威力を発揮する。詳しくは後述する。クロージャを定義する文法は、{ comma-separated-parameter-list -> statements } となっている。たとえば、

closure = { bill, tipPercentage -> bill * tipPercentage / 100 }tip = closure.call(25.19, 15)tip = closure(25.19, 15) // 上の行と同じ意味

間違った数のパラメータを渡すと、 IncorrectClosureArgumentException が発生する。パラメータが 1つのクロージャでは、it キーワードを使うことができる。このとき、パラメータリストを省

略して、代わりに it を使ってステートメント中で参照できる。たとえば、以下のクロージャはいずれも同じ意味である。

{ x -> println x }

{ println it }

以下は List とクロージャとを引数に取るメソッドのサンプルである。このサンプルではルーズ・メソッドとして書いたが、もちろんクラスのメソッドにもできる。このメソッドは list の各要素を引数にクロージャを実行させながら list をイテレートする。各クロージャを実行した結果として true を返してきた要素を newList に追加する。呼び出し元には newList を返す。Groovy は find と findAll メソッドを提供しているので、普通は以下のサンプルのようには書かないことに注意。

def List myFind(List list, Closure closure) {List newList = []for (team in list) {

if (closure.call team) newList.add team}newList

}

myFind メソッドを使用するコードも示しておこう

class Team { name; wins; losses }teams = []teams.add new Team(name:’Rams’, wins:12 , losses:4)teams.add new Team(name:’Raiders’, wins:4 , losses:12)teams.add new Team(name:’Packers’, wins:10 , losses:6)teams.add new Team(name:’49ers’, wins:7 , losses:9)

winningTeams=myFind(teams){ it.wins>it.losses }winningTeams.each{ println it.name }

実際には myFindのようなメソッドは必要ない。というのも、Listクラスにはあらかじめ findAllメソッドが用意されているからだ。使い方はこうだ。

winningTeams=teams.findAll{it.wins>it.losses}

10

Page 11: Groovy Little Book

GROOVY BEAN

Groovy Bean以下は Groovy Bean のシンプルなサンプルだ。

class Car {

String make

String model

}

このクラスはプロパティを 2つ宣言しているが、メソッドは定義していない。しかし、その舞台裏では様々なことが行われている。クラスやプロパティ、そしてメソッドのスコープはデフォルトでは public である。public と protected のプロパティは、結果としては public/protected な getter/setter メソッドが自動生成された private フィールドになる。これらのメソッドをオーバーライドすることで独自の振る舞いを持たせられる。 プロパティが明示的に private と宣言された場合には、getter/setter は自動生成されない。

上記の Groovy コードは、以下の Java コードと同じ意味である。

public class Car {

private String make;

private String model;

public String getMake() {

return make;

}

public String getModel() {

return model;

}

public void setMake(String make) {

this.make = make;

}

public void setModel(String model) {

this.model = model;

}

}

Groovy Beanとして生成されるクラスは java.lang.Objectクラスを継承し、かつ groovy.lang.GroovyObjectインタフェースを実装する。このクラスに追加されるメソッドは、getProperty、setProperty、getMetaClass、setMetaClass そして invokeMethod である。groovy.lang.MetaClass はクラスに対してメソッドを実行時に追加することを可能にする。

Groovy Bean では名前付きパラメータを利用してインスタンスを生成することができる。たとえば次のコードでは、まず Car の引数無しコンストラクタが呼ばれ、次にそれぞれのプロパティの setter メソッドが呼ばれる。

myCar = new Car(make:’Toyota’, model:’Camry’)

11

Page 12: Groovy Little Book

GROOVY LIST

Groovy ListGroovy List は java.util.ArrayList のインスタンスだ。リストはカンマ区切りで並べた値を角括弧で囲むこ

とで生成できる。たとえば、

cars = [new Car(make:’Honda’, model:’Odyssey’),

new Car(make:’Toyota’, model:’Camry’)]

println cars[1] // Camry を参照するfor (car in cars) { println car } // Car の toString メソッドを呼び出すclass Car {

make; model

String toString() { "Car: make=${make}, model=${model}" }

}

リストの要素をリストの最後からアクセスするには、負の値をインデックスに使用する。空のリストは []で生成できる。例としては、

cars = []

リストへ要素を追加する方法は 2種類ある。

cars.add car

cars << car

リストは配列から array.toList() メソッドで生成できる。配列はリストから list.toArray() メソッドで生成できる。

Groovy はいくつかのメソッドを java.util.List に追加している。

count引数に与えられたオブジェクトと等価な要素がリスト内にいくつあるかを数える。[1, 2, 3, 1].count(1)

は 2 を返す。

immutableコレクションの immutable(変更不能)なコピーを生成する。生成にあたっては java.util.Collectionsの static

な unmodifiableList メソッドを利用している。たとえば、

list = [1, 2, 3].immutable()

list.add 4 // java.lang.UnsupportedOperationException がスローされる

intersect2つのリストに共通の要素を含んだ新しいリストを生成する。[1, 2, 3, 4].intersect([2,4,6]) は [2, 4]

を返す。

joinリストの要素それぞれに対する toStringの値の間に、引数の文字列を挿入して連結する。たとえば、キャレット

を区切り文字としてリストに含まれるすべての文字列を連結したければ[’one’, ’two’, ’three’].join(’^’) と書く。これは "one^two^three" を返す。

sortリストの要素を並び替えた新しいリストを作成する。java.util.Comparator かクロージャを渡すことでソー

ト順を変更することができる。

12

Page 13: Groovy Little Book

min / max GROOVY LIST

fruits = [’kiwi’, ’strawberry’, ’grape’, ’banana’]

// 次の行は [banana, grape, kiwi, strawberry] を返す。sortedFruits = fruits.sort()

// 次の行は [kiwi, grape, banana, strawberry] を返す。sortedFruits = fruits.sort { l, r -> return l.length() <=> r.length() }

上記の最後にある sort メソッド呼び出しは、クロージャをパラメータとして渡すサンプルでもある。Groovyにはクロージャをパラメータとして渡せるメソッドが数多く用意されている。

Groovy Bean では複数のプロパティを使用したソートが簡単にできる。たとえば、Playerという Bean にname、age、score というプロパティがあるとしよう。この Bean のリストが players に格納されていて、それを age と score の値を基に並び替えるには、次のように書く。

players.sort { [ it.age, it.score ] }

min / maxリストの要素または文字列にある文字から、最小値あるいは最大値を検索する。java.util.Comparator か

クロージャを渡すことで、判定方法を変更できる。たとえば、以下のコードはリストから最小値と最大値を検索する。[5, 9, 1, 6].min() は 1 を返す。[5, 9, 1, 6].max() は 9 を返す。

reverseリストの要素または文字列にある文字を、逆順に並び替える。[1, 2, 3].reverse()は [3, 2, 1] を返

す。Groovy は java.util.List オブジェクトで使用できるように、加算と減算の演算子をオーバーロードしている。

加算2つのリストを結合した新しいリストを生成する。重複する要素があっても削除されない。

[1, 2, 3] + [2, 3, 4] は [1, 2, 3, 2, 3, 4] を返す。

減算最初のリストから二番目のリストにある要素すべてを取り除いたリストを生成する。

[1, 2, 3, 4] - [2, 4, 6] は [1, 3] を返す。リストの要素にプリミティブ型が含まれていなければ、要素の比較には equalsが使われる。

13

Page 14: Groovy Little Book

GROOVY MAP

Groovy MapGroovy Map は、java.util.HashMap のインスタンスだ。マップはカンマ区切りで並べたキー / 値のペアを

角括弧で囲むことで生成できる。キーと値とはコロンで区切る。たとえば、

players=[’baseball’:’AlbertPujols’, ’golf’:’TigerWoods’]

println players[’golf’]//TigerWoodsを出力するprintln players.golf//TigerWoodsを出力するfor ( player in players ) {

println"${player.value}plays${player.key}"

}

//これは上のループと同じ意味players.each{player ->

println"${player.value}plays${player.key}"

}

空のマップは [:]で生成できる。以下はその例だ。

players = [ : ]

14

Page 15: Groovy Little Book

GROOVY RANGE

Groovy な switch文Groovy の switch 文では、クラス、List、Range、Pattern など、あらゆるオブジェクトを使える。case 文

は isCase メソッドを使って値を比較する。数多くのオーバーライドされた isCase メソッドが提供されている。特定の型に向けておいてオーバーロードされない限り、isCase は equals メソッドを使用する。 case がクラス名である場合には、isCaseメソッドは instanceof を使用する。 isCase メソッドは、独自に作成したクラスでオーバーライドすることができる。

様ざまな異なる型の値に対応する switch 文のサンプルを示す。

switch (x) {

case ’Mark’:

println "got my name"

break

case 3..7:

println ’got a number in the range 3 to 7 inclusive’

break

case [’Moe’, ’Larry’, ’Curly’]:

println ’got a Stooge name’

break

case java.util.Date:

println ’got a Date object’

break

case ~"\\d{5}":

println ’got a zip code’

break

default:

println "got unexpected value ${x}"

Groovy RangeRange(範囲オブジェクト)は ".." と "..<" 演算子を使用して生成する。サンプルを示そう。

3..7 は「3 から 7」を表す Range を生成する。3..<7 は「3 から 6」を表す Range を生成する。"A".."D"

は「”A” から ”D”」を表す Range を生成する。"A"..<"D" は「”A” から ”C”」を表す Range を生成する。

範囲オブジェクト は java.util.AbstractList を継承した groovy.lang.Range インターフェースを実装するクラスで表現される。Range オブジェクトは immutable なリストだ。Range インタフェースは getFrom とgetTo メソッドを追加しているので、下限と上限を取得できる。2 種類の Range 実装が提供されている。groovy.lang.IntRange は整数値に限った範囲を扱う。IntRange には contains メソッドが追加されており、値が範囲内にあるかをテストできる。 groovy.lang.ObjectRange ではその他のいかなる型でも範囲に含めることができる。ここでも contains メソッドが追加されているが、使えるのは範囲に含まれるオブジェクトがjava.lang.Comparable を実装している場合に限られる。

範囲オブジェクトはループ構造で役に立つ。利用例は次セクションで取り上げる。

15

Page 16: Groovy Little Book

GROOVY なループ

Groovy なループ値の範囲を通じた繰り返し処理を行うには 6つの方法がある。

forfor( i in 1..1000 ){ println i }

whilei=1

while( i <= 1000 ){ println i; i++ }

each( 1..1000 ).each{ println it }

times1000.times{ println it }

//0から 999まで。

upto1.upto( 1000 ){ println it }

step1.step( 1001 , 1 ) { println it }

//1から 1000まで。//パラメータの値のひとつ手前で終了する。

16

Page 17: Groovy Little Book

クロージャを受け付ける LIST/MAP/STRING のメソッド

クロージャを受け付ける List/Map/String のメソッドList、Map、そして String のメソッドのなかにはクロージャをパラメータとして渡せるメソッドがある。

eachコレクションの要素または文字列内の文字に対して繰り返し処理を行う。java.util.Iterator の代わり

に利用することで、より簡潔なコードを記述できる。たとえば、リストの要素の数値をそれぞれ表示させようと思えば、[5, 9, 1, 6].each { x -> println x } あるいは [5, 9, 1, 6].each { println it }と書ける。

collectコレクションまたは文字列を変換して、新しいコレクション(または文字列)を作成する。たとえば、リストの各

要素の値を2倍した新しい要素を持つリストを作成するには、doubles = [5, 9, 1, 6].collect { x -> x * 2}

とする。これは doubles に [10, 18, 2, 12] をセットする。

find与えられた条件に合致するものをコレクションの要素また文字列内の文字から検索し、最初に出現した要素を返

す。たとえば、リストの中から5よりも大きい最初の要素を検索したければ、[5, 9, 1, 6].find {x -> x > 5} と書くと 9 が返ってくる。

findAll与えられた条件に合致するものをコレクションの要素または文字列内の文字から検索し、出現した要素すべ

ての配列を返す。たとえば、リストの中から 5よりも大きい要素をすべて検索したければ、[5, 9, 1, 6].findAll{x-> x > 5} と書くと [9, 6] が返ってくる。

everyコレクションの要素または文字列内の文字すべてが、与えられた条件に合致するかを調べる。たとえば、リ

ストに含まれる数字がすべて 7より小さいかを調べたいのであれば、[5, 9, 1, 6].every {x-> x < 7} と書くと false が返ってくる。

anyコレクションの要素または文字列内の文字に、与えられた条件に合致するものがひとつでも存在するか

を調べる。たとえば、リストに含まれる数字に 7より小さいものが含まれているかを調べたいのであれば、[5, 9, 1, 6].any {x-> x < 7} と書くと true が返ってくる。

inject繰り返しの初回には、引数に渡された値が使われ、それぞれの繰り返しでの評価結果が次回以降に渡されて

いく。たとえば、5の階乗を求めるには、次のように書ける (あまり見かけないやり方ではあるが)。

factorial = [2, 3, 4, 5].inject( 1 ) {

prevResult , x|prevResult*x

}

このクロージャは、4回実行される。1回目: 1 * 2 2回目: 2 * 3 3回目: 6 * 4 4回目: 24*5結果は、120になる。

17

Page 18: Groovy Little Book

ファイル I/O

ファイル I/Oファイルから行を読み込む (2種類の方法)

サンプルコードの (...) はコードの省略を示す。

file = new File(’myFile.txt’)

file.eachLine { println it }

lineList = file.readLines()

ファイルからバイト列を読み込む (2種類の方法)file = new File(’myFile.txt’)

file.eachByte { println it }

byteList = file.readBytes()

ディレクトリにあるファイルを読むdir = new File(’directory-path’)

dir.eachFile { file-> . . . }

読み込み完了時にリソースを閉じるReader または InputStream から読み込むこれらのメソッドは、例外が起きてもリソースを閉じることが保

証されている。

file.withReader { reader -> . . . }

reader.withReader { reader -> . . . }

inputStream.withStream { is -> . . . }

書き込み完了時にリソースを閉じる処理中に例外が投げられたとしても、Writer または OutputStream への書き込みを閉じることを保証する。

file.withWriter { writer -> . . . }

file.withPrintWriter { pw -> . . . }

file.withOutputStream { os -> . . . }

writer.withWriter { writer -> . . . }

outputStream.withStream { os -> . . . }

18

Page 19: Groovy Little Book

オーバーロードされた左シフト演算子

オーバーロードされた左シフト演算子Stringに追加するには、

s=’foo’

s=s<<’bar’

StringBufferに追加するには

sb=newStringBuffer(’foo’)

sb<<’bar’

Listに追加するには、

colors=[’red’,’green’]

colors<<’blue’

出力ストリームの末尾に追加するには、

w=newFile(’myFile.txt’).newWriter()

w<<’foo’<<’bar’

w.close()

19

Page 20: Groovy Little Book

オブジェクト・ナビゲーション

オブジェクト・ナビゲーションオブジェクト構造 (ObjectGraphs)を XPath風の文法で辿るには、ドット (".")演算子を使用する。

NullPointerException の危険を回避するには、"?." を"." の代わりに使用する。たとえば、

class Team{

String name

Person coach

def players=[]

}

class Person{

String name

}

def p = new Person( name:’MikeMartz’ )

def t = new Team( name:’Rams’, coach:p )

//次の行は、team.getCoach().getNameと同じ結果を出力するprintln "coach=${ t.coach.name }"

def t = new Team( name:’Blues’ )

//次の行は nullを返すのだが、//NullPointerExceptionは発生しないprintln "coach=${ t?.coach?.name}"

//次の行は NullPointerExceptionが発生するprintln "coach=${ t.coach.name }"

20

Page 21: Groovy Little Book

未実装メソッドをキャッチする

Groovy なリフレクションあるオブジェクトの Class オブジェクトを取得したい場合に、Java では someObject.getClass() と書く。

Groovyで同じことを行うには、someObject.classと書く。クラス名から Class オブジェクトを取得したい場合は、Java でもGroovy でも SomeClass.classまたは Class.forName(”pkg.SomeClass”)と書く。GroovyのGStringクラスのメソッド名を一覧表示したければ、次のように書く。

GString.class.methods.each{

println it.name

}

Javaの java.util.Listインタフェースのメソッド名を一覧表示したければ、次のように書く

java.util.List.class.methods.each{

println it.name

}

未実装メソッドをキャッチするクラスには、未実装のメソッドに対する呼び出しをキャッチするコードを書くことができる。

たとえば、

def o=new CatchCall()

//次の行は"unknown method Mark called with [19]"と表示するprintln o.foo( "Mark" , 19 )

class CatchCall{

invokeMethod( String name , Object args ) {

try{

return metaClass.invokeMethod( this , name , args )

} catch ( MissingMethodException e ){

//ここに確実に呼び出せるメソッド名と引数での呼び出しを//行うロジックを書いてもよいreturn " unknown method ${name} called with ${args}"

}

}

}

21

Page 22: Groovy Little Book

GROOVY MARKUP

Groovy MarkupGroovy Markup は 前述の invokeMethodメソッドを使用して存在しないメソッドの呼び出しをキャッチし、

それを「ノード」に変換する。メソッドの引数はノードの属性として扱われる。メソッドに渡されたクロージャはノードのコンテンツとして扱われる。GroovyMarkupでは様ざまな利用法が用意されている:

• 一般的なデータ構造のツリー構造 (NodeBuilder)

• DOM ツリー (DOMBuilder)

• SAX イベントの点火 (SAXBuilder)

• HTML または XML 文字列の生成 (MarkupBuilder)

• Ant タスクの実行 (AntBuilder)

• Swing ユーザーインタフェースの生成 (SwingBuilder)

これに加えて、独自のビルダを作成するには groovy.util.BuilderSupport クラスを継承すればよい。

HTMLの生成MarkupBuilder を使用して HTML を生成するサンプルを示す。

import groovy.xml.MarkupBuilder

def mb = new MarkupBuilder()

mb.html() {

head() {

title("This is my title.")

}

body() {

p("This is my paragraph.")

}

}

println mb

これが生成する HTML は次のようになる。

<html>

<head>

<title>This is my title.</title>

</head>

<body>

<p>This is my paragraph.</p>

</body>

</html>

XMLの生成MarkupBuilder を使用して XML を生成するサンプルを示す。

import groovy.xml.MarkupBuilder;

def mb = new MarkupBuilder()

mb.autos() {

auto(year:2001, color:’blue’) {

make(’Toyota’)

model(’Camry’)

}

}

println mb

22

Page 23: Groovy Little Book

GROOVY SQL

これが生成するXMLは次のようになる。

<autos>

<auto year=’2001’ color=’blue’>

<make>Toyota</make>

<model>Camry</model>

</auto>

</autos>

Groovy SQLGroovyは JDBCを簡単にする。groovy.sql.Sqlクラスはクエリの実行とResultSet行のイテレートを簡単に

行う方法を提供する。次のサンプルでは、MusicCollection はデータベースの名前 (この場合は、登録されたODBCデータソース)で、Artistsがデータベースのテーブル名、Nameがテーブルのカラム名だ。

import groovy.sql.Sql

dbURL=’jdbc:odbc:MusicCollection’

jdbcDriver=’sun.jdbc.odbc.JdbcOdbcDriver’

sql=Sql.newInstance(dbURL,jdbcDriver)

sql.eachRow(’select * from Artists’){

println it.Name

}

23

Page 24: Groovy Little Book

GROOVLET

GroovletGroovletは Groovyによる、サーブレットと JSPの代替案である。Groovletは以下の暗黙変数を提供する。

• out - HttpServletResponse#getWriter メソッドが返すもの

• request - HttpServletRequest

• session - HttpSession

Groovlet のサンプルを示す。このコードは SimpleGroovlet.groovy みたいな名前で保存する。また、コードは HTML の出力にヒアドキュメントを使用している。

out.println <<<EOS

<html>

<head>

<title>My Simple Groovlet</title>

</head>

<body>

<h1>My Simple Groovlet</h1>

<p>Today is ${new java.util.Date()}.</p>

</body>

</html>

EOS

GroovyServlet は Groovlet をコンパイルし、ファイルが変更されるまでキャッシュする。再コンパイルは変更時に自動的に行われる。 GroovyServlet は web.xml に登録しなければならない。以下は web.xml ファイルのサンプルだが、GroovyServlet の登録部分だけしか示していない。

<?xml version="1.0"?>

<!DOCTYPE web-app

PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

<servlet>

<servlet-name>Groovy</servlet-name>

<servlet-class>groovy.servlet.GroovyServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Groovy</servlet-name>

<url-pattern>*.groovy</url-pattern>

</servlet-mapping>

</web-app>

Groovlet のデプロイには Ant を使うのが良いだろう。基本的な手順は:

1. 次の内容を含む WAR ファイルを作成する。

• Groovlet ソースファイル (*.groovy) をトップレベルの階層に配置• WEB-INF ディレクトリに web.xml を配置• groovy*.jar と asm*.jar ファイルを WEB-INF/lib ディレクトリに配置

2. WAR ファイルをサーブレットエンジン (Tomcat 等)にデプロイする。

これを行うための Ant ビルドファイルはこうだ。

24

Page 25: Groovy Little Book

GROOVLET

build.propertiesbuild.dir=build

src.dir=src

# Groovlet の置かれているディレクトリgroovy.dir=${src.dir}/groovy

# web.xml の置かれているディレクトリweb.dir=${src.dir}/web

# WAR ファイルの生成先パスwar.file=${build.dir}/${ant.project.name}.war

# WAR ファイルのデプロイ先webapps.dir=${env.TOMCAT_HOME}/webapps

# WAR ファイルに含めるべき JAR ファイルasm.jar=${env.GROOVY_HOME}/lib/asm-1.4.1.jar

groovy.jar=${env.GROOVY_HOME}/lib/groovy-1.0-beta-4-snapshot.jar

build.xml<project name="GroovletExample" default="deploy">

<property environment="env"/>

<property file="build.properties"/>

<target name="prepare">

<mkdir dir="${build.dir}"/>

</target>

<target name="war" depends="prepare" description="creates WAR file">

<war destfile="${war.file}" webxml="${web.dir}/web.xml">

<fileset dir="${groovy.dir}"/>

<lib file="${groovy.jar}"/>

<lib file="${asm.jar}"/>

</war>

</target>

<target name="deploy" depends="war" description="deploys WAR file">

<delete dir="${webapps.dir}/${ant.project.name}"/>

<delete file="${webapps.dir}/${war.file}"/>

<copy file="${war.file}" todir="${webapps.dir}"/>

</target>

</project>

サンプルの Groovlet がデプロイされたら、ウェブブラウザからhttp://localhost:8080/GroovletExamples/SimpleGroovlet.groovyでアクセスできる。GroovletExampleはWeb アプリケーションの名前で、SimpleGroovylet.groovy がGroovlet の名前だ。このマッピングはweb.xmlに登録されているGroovyServletの url-patternで行われる。

25

Page 26: Groovy Little Book

インストール

第 II部

Grails

GrailsとはGrailsとは、JavaとGroovyで構築され、JEE分野で最も使用されている、Spring、Hibernate、SiteMesh

等のAPIを使用した、ダイナミックWebアプリケーションフレームワークです。Grailsは、JavaとGroovy開発者に、既存の知識、長年 Java開発者が利用してきた実績有る信頼されたAPIを使用した、規約によるラピッド開発の楽しさをもたらします。

ダウンロード以下のサイトより安定版、又は、開発版スナップショットをダウンロードすることができます。

http://grails.org/Downloadhttp://grails.org/Japanese+Download (日本語ページ)

インストールGrailsを始めるには以下の条件を満たしている必要が有ります。

• Java SDK 1.4 以上がインストールされている。

• 環境変数 JAVA HOMEが設定されていることを確認してください。

• UTF-8が使用可能なテキストエディター又は Eclipse等の IDE

Grailsインストール手順

1. 最新リリースのGrailsをダウンロード

2. 適切な位置に解凍

3. 解凍した位置を環境変数 GRAILS HOMEとして設定。

4. Grailsディレクトリ内の”bin”ディレクトリを環境変数 PATHに追加

5. コマンドプロンプトで ”grails”を実行以下のWelcomeメッセージが表示されたらインストール完了です。

# grails

Welcome to Grails 0.6 - http://grails.org/Licensed under Apache Standard License 2.0Grails home is set to: /opt/snap/grails-0.x

No script name specified. Use ’grails help’ for more info

26

Page 27: Groovy Little Book

クイックスタート

クイックスタートGrailsプロジェクトを作成

Grailsのインストールが完了したら、組込ターゲット (コマンド)を使用して新規にプロジェクトを作成します。# grails create-app sampleappターゲットを実行しプロジェクト名を入力すると以下のディレクトリ構造が自動的に作成されます。

/sampleap/|-- application.properties|-- build.xml|-- /grails-app/| |-- /conf/ ---> データソースなどの設定情報アーティファクト置き場| |-- /controllers/ ---> コントローラアーティファクト置き場| |-- /domain/ ---> ドメインクラス置き場| |-- /i18n/ ---> i18n用メッセージプロパティー置き場| |-- /services/ ---> サービス置き場| |-- /taglib/ ---> タグライブラリー置き場| |-- /utils/ ---> ユーティル置き場| ‘-- /views/ ---> ビュー置き場|-- /hibernate/ ---> hibernateオプション設定置き場|-- /lib/|-- /plugins/|-- sampleapp.launch|-- sampleapp.tmproj|-- /scripts/|-- /spring/ ---> オプション設定置き場|-- /src/|-- /test/‘-- /web-app/ ---> webアプリケーションルート

データソースを定義"create-app" ターゲットを実行した際に、"<..>/grails-app/conf" ディレクトリに、それぞれの標準

環境用:DevelopmentDataSource, TestDataSource, ProductionDataSource等、いくつかの Grailsデータソース成果物を作成します。 注5

デフォルトでのデータソースは、メモリ上のHSQLDBデータベースで定義されます。(テストには良いが、実際の開発にはあまり便利ではないので注意)データソースの設定は、データベースのドライバー jarファイルを<..>/libに入れて、データベースとドライバーの値を単純に変更するだけです。以下は、DevelopmentDataSource.groovyの例です。

class DevelopmentDataSource {boolean pooling = trueString dbCreate = "create-drop" // one of ’create’, ’create-drop’,’update’String url = "jdbc:hsqldb:mem:testDB"String driverClassName = "org.hsqldb.jdbcDriver"String username = "sa"String password = ""

}

5Grails-0.6より、DataSource.groovyの単一ファイルに変更

27

Page 28: Groovy Little Book

ドメインクラスを作成 クイックスタート

ドメインクラスを作成プロジェクトのルートディレクトリにいるのを確かめ、(プロジェクト名は”sampleapp”と仮定)”cd sam-

pleapp”と入力、”grails create-domain-class book”ターゲットを実行。# grails create-domain-class bookプロジェクトディレクトリ/grails-app/domain/以下に、book.groovyファイルが生成されます。book.groovyファイルを以下のように編集します。

class Book {String titleString author

}

コントローラを作成コントローラは、ウェブリクエストやURLからのリクエストをコントローラクラスとクラス内のクロージャ

へマップするGrailsアプリケーションの中で中心的な役割をしています。コントローラ作成を行うには以下のターゲットを実行します。# grails create-controller book/grails-app/controlers/以下に、BookController.groovyファイルが生成されます。BookController.groovyファイルを以下のように編集します。

class BookController {def scaffold = Book

}

28

Page 29: Groovy Little Book

Grailsの起動 クイックスタート

Grailsの起動Grailsアプリケーションを起動するには、以下のターゲットを使用します。# grails run-app

ブラウザを起動して、以下のURL入力。http://localhost:8080/sampleapp/ 注6

http://localhost:8080/sampleapp/book/list Bookリストのページ

図 1: Grailsアプリケーショントップ画面

図 2: リスト画面

60.6-SNAPSHOT版で、scaffoldを指定した場合は、http://localhost:8080/sampleapp/book/ へ直接アクセスするとページが見つからないバグがあります。

29

Page 30: Groovy Little Book

GROOVY リファレンス

第 III部

付録 Appendix

Groovy リファレンス文法

as import type as idassert assert expr expr?break break lbl?case switch expr case expr stmt*catch try stmt* catch type id stmt*class mod* class idcontinue continue lbl?def def methodDeclarationdefault switch expr case defaultstmt*do do stmt* while exprelse if expr stmt* else if expr stmt*extends mod* class id extends typefinally try stmt* finally stmt*for for expr*;expr;expr stmt*for for id in id stmt*if if expr stmt* else if expr stmt*in for id in id stmt*implements mod* class id implements type*import import typeinstanceof expr instanceof typeinterface mod* interface idnew new typepackage package idproperty mod* property type? idreturn return expr?/switch switch expr case expr stmt*throw throw exprthrows methodDeclaration throws typetry try stmt* catch type id stmt*while do stmt* while expr

while expr stmt*

修飾子

abstract abstract class idAnnotations @AnnotationAnnotations @Annotation(x = 3, y = 5)

リストとマップ

type[] id = new type[size]

演算子id = expr 代入expr & expr ビット積id &= expr ビット積 代入id = ~ expr ビット否定expr | expr ビット和id |= expr ビット和 代入id = expr >>> expr ビット右シフトid >>>= expr ビット右シフト 代入

Groovy JDK

コレクションとプロパティー Collections and prop-erties注: 文章内の cltnは、リスト,セット,matcher,文字列,charシーケン

ス, 配列も含まれます.

cltn [index|indices|range|property ]指定した (場所 | 位置 | 領域) のオブジェクトを得る.

obj [index|property] = value指定した場所に value を代入

cltn << objコレクションに obj を追加

cltn + objコレクションに obj を追加

list − cltnリストからアイテムを除去

cltn ∗ numコレクション内のアイテムを回数分繰り返す

obj. getProperties()obj から Map のプロパティを得る

obj. getMetaPropertyValues()obj からメタプロパティリストを得る

cltn. count(obj) *コレクション内に存在する obj の数を数える

map. get(key, defaultValue) *cltn. size() *

cltn. collect() {closure} *closure を変換して新しいコレクションを作成

obj. each() {closure} *closure の内容でオブジェクトの繰り返し処理

30

Page 31: Groovy Little Book

文字列 Strings GROOVY リファレンス

obj. eachWithIndex() {closure}closure の内容を番号付きでオブジェクトの繰り返し処理

obj. find() {closure} *closure の条件に一致した最初のアイテムを探す

obj. findAll() {closure} *closure の条件に一致した全てのアイテムを返す

obj. findIndexOf() {closure}return first index that matches condition closure

obj. grep(regex|range|etc..) *cltn. inject(value) {closure}returns closure( closure( closure(value,item0) ,item1) ,item2) ...

cltn. max([comparator]) {closure} *コレクション内の最大値を返す

cltn. min([comparator]) {closure} *コレクション内の最小値を返す

list. reverseEach() {closure}closure の内容でオブジェクトの繰り返し処理を逆順で行う

cltn. sort([comparator]) *コレクションをリストへ並べ替える, オプションで comparator も使用可

cltn. sort() {closure} *クロージャを比較条件にしてコレクションをリストへ並べ替える

cltn. asImmutable()cltn. asSynchronized()list. flatten()list. intersect(cltn)リストとコレクションの共通内容を返す

cltn. join(separator) *cltn の全てのエレメントを連結して文字列にする

list. pop() *リストから最後のアイテムを削除して返す

cltn. reverse()map. subMap(keys)与えられたキーのマップを返す

cltn. toList()

文字列 Stringsstr ++str −−str + objstr と obj 連結する

str − obj最初の obj を str から除去

str << valuestr. padRight(size,[padding])size の範囲で左揃え

str. center(size, [padding])size の範囲で中央揃え

str. padLeft(size,[padding])size の範囲で右揃え

str. contains(str2) *str が str2 を含む場合 true を返す

str. eachMatch(regex) {closure} *指定された正規表現 regex に一致した内容に closure を適用

str. toCharacter()str. toList()str. toLong()str. toURL()str. tokenize([token]) *

入出力 Input/output注: ここでの url 意味は、url, file, stream,reader も含まれます.

dir. eachFile() {closure}dir 内のそれぞれのファイルに closure 内容を適用

dir. eachFileRecurse() {closure}再帰的に, dir 内のそれぞれのファイルに closure 内容を適用

url. eachByte() {closure}file の各バイトに closure 内容を適用

url. eachLine() {closure}入力各行に closure 内容を適用

file. readBytes()in. readLine()in から単一行, 全行の読込

file. readLines()file から行の List を取得

url. getText([charset])リソースから全てのテキストを取得

file. splitEachLine(regEx) {closure}regEx で分割された file の各行に closure を適用

url. withReader() {closure}closure を in に適用して in を閉じる

out << objobj を stream, process また socket に付加

file. append(text, [charset])bytes.encodeBase64()str. decodeBase64()in. filterLine([out]) {closure}in から読み込み、closure に一致する行のみ out へ書き出す

in. transformChar(out) {closure}in. transformLine(out) {closure}in から読み込み、out 書きだし時に各行に closure を適用

file. withOutputStream() {closure}file. withPrintWriter() {closure}

31

Page 32: Groovy Little Book

その他 GROOVY リファレンス

out. withStream() {closure}skt. withStreams() {closure}out. withWriter([charset]) {closure}file. withWriterAppend(charset) {closure}file. write(text, [charset]) *out. writeLine(line)

その他date ++date −−date + daysdate − daysobj. dump() *obj の詳細ダンプ文字列を返す

obj. inspect() *obj のインスタンス作成時に使用された groovy expression を返す

obj. invokeMethod(method, args) *obj. print(obj) *obj. print(out) *obj. println(object) *obj. println(out) *num. step(endNum, stepNum) {closure}closure 内容を num で開始して endNum まで繰り返す

num. times() {closure} *closure 内容を num 回数繰り返す

num. upto(endNum) {closure}closure 内容を num から endNum まで繰り返す

obj. use(categoryClass) {closure} *指定したクラスに closure を結びつける

obj. use(categoryClassList) {closure} *指定した複数クラスに closure を結びつける

ps. waitForOrKill(milliSecs)ps. getText()Thd. start() {closure}Thd. startDaemon() {closure}Mtr. getLastMatcher()

スニペット SnippetsBuilder Markup, Node, StreamingMarkup, DOM,

Ant, JavaDoc, Swt, JFace, Swing

farm = new NodeBuilder().farm(){animal(type:’pig’)}

GPath walks the tree

farm.animal.collect{it[’@type’]}.contains(’pig’)

Groovyコード例package com.exampleimport org.example.Cow// これは、Groovyのサンプルです。class HighlandCow extends Cow {

void mooAtPeople() {sql = Sql.newInstance("jdbc:foo:bar")sql.eachRow("select * from PERSON") {

println("Och-Aye ${it.firstname}")}

}}

ツールAnt タスク<taskdef name="groovyc"

classname="org.codehaus.groovy.ant.Groovyc"classpathref="my.classpath"/>

<groovyc destdir="${build.classes.dir}"srcdir="${src.dir}" listfiles="true"><classpath refid="my.classpath"/>

</groovyc>

コマンドラインツール> groovy [options] cheese.groovy [args]指定された groovy スクリプトを解析して実行

> groovyc [options] cheese.groovy指定された groovy スクリプトをコンパイル

> groovysh対話式の groovy セッションを開始

> groovyConsoleGUI ベースの groovy セッションを開始

Copyright c⃝ 2004, 2007 Jeremy Rayner 翻訳:T.Yamamoto$Revision: 5826 $, $Date: 2007-03-30 22:21:17 +0000 (金, 30 3 2007) $.http://javanicus.com/

32

Page 33: Groovy Little Book

GRAILS リファレンス

Grails リファレンス

33

Page 34: Groovy Little Book

クラシックGROOVYからの JSRシンタックスへのマイグレーション

クラシックGroovyからのJSRシンタックスへのマイグレーションこれは新しいGroovy JSR構文との互換性を確保するためにGroovyクラシックコードに加える必要がある

であろう変更のチェックリストです。

セーフナビゲーションクラシックGroovyで、このような構文を使っていました。

class Person = { String name }y = nullprintln "${y->name}" // -> これがクラシック Groovy構文でのオプショナル gpath演算子でした。

NullPointerExceptionを避ける為のセーフナビゲーション用矢印演算子のかわりに、これからは "?" を使用します。現在 JSRではこの構文を使います。class Person = { String name }def y = nullprintln "${y?.name}" // 現在 Groovy JSRでは、?. がオプショナル gpath演算子です。

クロージャ構文のパラメータセパレータThis allows us to use one single token for the separator between the closure in Classic Groovy we used to

use this syntax

cl = {a| ...}cl = {|a| ...}

Now in the JSR we use this syntax

def cl = {a -> ...}

This allows us to use one single token for the separator between the closure parameters and the code inin the closure which works with arbitrarily complex parameter list expressions and default values. e.g.

def cl = {String x = "hey", int y = a|b -> println "Values are $x and $y"}collection.each {int

プロパティーキーワード’def’ キーワードの導入

local variable declarations and fields currently need to be specified with ’def’, a modifier, and/or a type.e.g.

def foo() {int x = 123y = 456 // クラシック}

def foo() {int x = 123def y = 456 // JSR}

class Foo {telson // クラシックint sharna}class Foo {def telson // JSRint sharna}

(Syntactically, the new keyword ’def’ acts for methods as a modifier like ’public’.)

For Scripts (as opposed to explicitely declared classes) the syntax is not changed, i.e. variable declarationswithout ’def’ are still allowed, because those variables are automatically created in the script binding if theydon’t already exist.

34

Page 35: Groovy Little Book

’as’ キーワードの導入 クラシックGROOVYからの JSRシンタックスへのマイグレーション

’as’ キーワードの導入’as’ キーワードを使用してオブジェクトの方を変更出来ます。

def d0 = new Date(2005-1900, 5-1, 7) // クラシック Groovyまたは、Javaの場合println d0

def d1 = [2005-1900, 5-1, 8] as Date // jsr-01よりprintln d1

Date d2 = [2005-1900, 5-1, 9] as Date // jsr-01よりprintln d2

Date d3 = [2005-1900, 5-1, 10] // jsr-01よりprintln d3

// def n0 = new int[] { 1, 3, 5, 6 }// これは動作しません。 このスタイルは、groovy-1.0-jsr-01よりサポートされません。def n1 = [ 1, 3, 5, 7 ] as int[]println n1.classprintln n1.size()println n1.lengthprintln n1[0]println n1[-1]

// int[] n2 = [ 2, 4, 6, 8,10 ] as int[] // 動作しますint[] n2 = [ 2, 4, 6, 8, 10 ] // 動作しますprintln n2.classprintln n2.size()println n2.lengthprintln n2[0]println n2[-1]

// String[] n3 = [ "a", "ab", "abc", "abcd", "abcde", "abcdef" ] as String[] // 動作しますString[] n3 = [ "a", "ab", "abc", "abcd", "abcde", "abcdef" ] // 動作しますprintln n3.classprintln n3.size()println n3.lengthprintln n3[0]println n3[-1]

クラスメンバのデフォルトアクセスレベルGroovyクラスメンバのデフォルトアクセスレベルは ”public” から ”protected” へ変更されました。

クラシック Groovyclass Foo {readMe_a;readMe_b

}xyz = new Foo(readMe_a:"Hello",readMe_b:"World")println xyz.readMe_aprintln xyz.readMe_b

現在 JSR Groovyではclass Foo {public readMe_a;def readMe_b //def is now required because of the "def keyword" change mentioned earlier

}xyz = new Foo(readMe_a:"Hello",readMe_b:"World")println xyz.readMe_aprintln xyz.readMe_b //errors in JSR Groovy

35

Page 36: Groovy Little Book

配列作成 クラシックGROOVYからの JSRシンタックスへのマイグレーション

配列作成no special array syntax. To make the language much cleaner, we now have a single syntax to work with

lists and arrays in the JSR. Also note that we can now easily coerce from any collection or array to anyarray type

// クラシックargs = new String[] { "a", "b" }

// JSRString[] args = ["a", "b"]def x = [1, 2, 3] as int[]long[] y = x

Be careful: we don’t support native multi-dimensional array creation right now.

floatと doubleの表記法float and double literals cannot start with dot.

x = .123 // クラシックdef x = 0.123 // JSR

This is to avoid ambiguity with things like ranges (1..2) and so forth

明示的なメソッドポインタ構文In classic Groovy you could access method pointers automatically if there was no java bean property of

the given method name.

// クラシックmethodPointer = System.out.printlnmethodPointer("Hello World")

This often caused confusion; as folks would use a property access to find something and get a method byaccident (e.g. typo) and get confused. So now we make getting a method pointer explicit as follows

// JSRdef methodPointer = System.out.&printlnmethodPointer("Hello World")

def foo = ...def p = foo.&bar

// lets call the bar method on the foo objectp(1, 2, 3)

No ’do ... while()’ syntax as yet.Due to ambiguity, we’ve not yet added support for do .. while to Groovy

’No Dumb Expression’ ruleno dumb expression rule, so we will catch dumb expressions (where a carriage return has broken the

script).

def foo() {def x = 1+5 // dumb expression!return 8

}

マークアップとビルダmarkup / builders will change a little, but the classic syntax still applies. Not sure of the new syntax, but

we’ll have some kinda start/stop syntax to denote a markup block. Maybe a keyword, like

markup (builder) {// same stuff as before goes here}

// or something like thisbuilder.{// same stuff as before goes here}

36

Page 37: Groovy Little Book

StringsとGStrings クラシックGROOVYからの JSRシンタックスへのマイグレーション

StringsとGStringssingle and double quote strings can only span one line; for multiple lines use triple quotes

heredocs removal - they are kinda ugly anyway :). If you want to use them, just use treble quote instead

def foo = """thisisa verylongstring on manylines"""

escaping of $ inside GStrings must use \$

println ’amount is $100’// same asprintln "amount is \$100"

A new string definition is also supported which is escaping friendly, and thus particularly friendly forregex notation:

if (’abc’ =~ /.../) {}if (’abc’ ==~ /.../) {}’abc’.eachMatch(/.../) {}[’a’,’b’,’c’].grep(/a/)

switch(’abc’){case ~/.../ : whatever}

assert ’EUOUAE’.matches(/^[aeiou]*$/)assert ’EUOUAE’ ==~ /^[aeiou]*$/assert ’football’.replaceAll(/foo/, "Bar") == ’Bartball’

アサーションassert uses comma instead of colon to delimit the two parameter form of assertion statement

assert 0 <= value : "Must be non-negative" // classic

assert 0 <= value , "Must be non-negative" // JSR

クロージャ内の return/break/continueの意味return/break/continue to behave inside closures like these statements work in other blocks (such as the

block on a for() or while() loop. More details here

整数除算Previously, in Groovy Classic, we used the backward slash as the integer division operator. This operator

being confusing with escaping sequences was removed. So instead of please use the intdiv() method.

int result = 5 \ 3 // クラシックint result = 5.intdiv(3) // JSR

JDK5の forループはサポートされませんGroovy already supports a fair number of looping mechanisms, and in Classic, both for (... : ...) and for

(... in ...) were supported. For the moment, only the for (... in ...) notation is allowed.

for (e : myList) { } // 今後は使えませんfor (Element e : myList) { } // 今後は使えませんfor (e in myList) { } // JSRfor (Element e in myList) { } // JSR

排他的範囲The operator for creating ranges with the upper bound excluded from the range has changed.

range = 0...10 //クラシックdef range = 0..<10 //JSR

37

Page 38: Groovy Little Book

GRAILS TIPS! ドメインクラスのハック

Grails Tips! ドメインクラスのハックドメインクラスを名指しで取り出す。

def domainCls = grailsApplication.getDomainClass("Book")

ドメインクラスから色々取得println domainCls.name // クラス名println domainCls.propertyName // 頭も小文字の名前 Book -> bookprintln domainCls.clazz.list() // MetaMethods実行 clazz.findAll* 等println domainCls.getRelatedClassType("projects")//リレークラスの型取得//メソッド一覧domainCls.class.methods.each{

println it.name}

プロパティーリスト取得def comparator = org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator.classdef props = domainCls.properties.findAll { it.name != ’version’ }Collections.sort(props, comparator.constructors[0].newInstance([domainCls] as Object[]))

プロパティーリストから、色々取得props.each{prop->println "------"println "getName ${prop.name}"println "getType ${prop.type} ${prop.type.name}"println "getNaturalName ${prop.naturalName}" // fieldNameOne => Field Name Oneprintln "getDomainClass ${prop.domainClass}"println "getFieldName ${prop.fieldName}"

println "isOneToMany ${prop.isOneToMany()}"println "isManyToOne ${prop.isManyToOne()}"println "isBidirectional ${prop.isBidirectional()}"println "isAssociation ${prop.isAssociation()}"println "isPersistent ${prop.isPersistent()}"println "isManyToMany ${prop.isManyToMany()}"println "isOwningSide ${prop.isOwningSide()}"println "isOptional ${prop.isOptional()}"println "isOneToOne ${prop.isOneToOne()}"println "isCircular ${prop.isCircular()}"

println "getReferencedPropertyType ${prop.referencedPropertyType}"println "getReferencedDomainClass ${prop.referencedDomainClass}"println "getReferencedPropertyName ${prop.referencedPropertyName}"println "getFetchMode ${prop.getFetchMode()}"println "getOtherSide ${prop.getOtherSide()}"println "getTypePropertyName ${prop.name}"

println "isInherited ${prop.isInherited()}"println "isIdentity ${prop.isIdentity()}"

}

38

Page 39: Groovy Little Book

GRAILS TIPS! GRAILS ARTEFACTS CLASS

Grails Tips! Grails Artefacts ClassGrailsの、”規約によるコーディング”に使われる「Artefacts」(米語スペルだとArtifacts)、ドキュメント翻

訳時は、なんと翻訳して良いのかわからず、他の技術系の資料を参考にして「成果物」と訳しました。今回ここでは、カタカナで「アーティファクト」と書きます。

GrailsApplicationは、コントローラ、タグリブ、GSP内などで、grailsApplication と記述して呼びだすことができます。class DashboardController{def index = {println grailsApplication

}}

全アーティファクトクラスリストを返すGrailsが起動している際に、使用されているアーティファクトClassリストを返す。grailsApplication.allArtefacts.each{println it

}

アーティファクト以外grailsApplication.allClasses.each{//falseのみをアウトプットif(!grailsApplication.isArtefact(it)) println it

}

ドメインクラスを名前で取得def domainCls = grailsApplication.getDomainClass("Book")//又は、def domainCls = grailsApplication.getArtefact("Domain","Book")

ドメインクラスを名指しで取得する場合と同じように、grailsApplication.getArtefact(”Domain”,”Book”)と書いて、”Domain”の部分を各アーティファクト名に変更することで、他のアーティファクトクラスも取得できます。

• Domain - ドメインクラス

• Controller - コントローラクラス

• TagLib - タグリブクラス

• Service - サービスクラス

• Codec - コーデック

• Task - タスク

• DataSource - データソース

• UrlMappings - URLマッピング

• Bootstrap - ブートストラップ

全ドメインクラスを取得する例def domainsInfo = grailsApplication.getArtefactInfo("Domain")domainsInfo.getClassesByName().each{println "クラス名:${it.key} クラス:${it.value}"

}

各アーティファクトクラスの情報を色々取得してまとめると、概要仕様書 ( GrailsDocs )っぽいのもができそう。

39

Page 40: Groovy Little Book

参考資料

参考資料サイトgroovy公式サイト http://groovy.codehaus.org/

Googleグループ Grails-Japan http://groups.google.com/group/grails-ja

groovy公式サイト日本語版 http://groovy.codehaus.org/Japanese+Home (翻訳中)

kakutani氏の翻訳ページ http://kakutani.com/trans/ociweb/jnbFeb2004.html

Groovy,Grailsドキュメント翻訳協力者募集Groovy,Grailsドキュメント翻訳協力者募集しています。

詳細は、以下のサイトを参照ください。http://groovy.codehaus.org/Japanese+Translation+Project

40