Groovy では、クロージャを使って若干の下準備(下例では TableBuilder)をしておくと、以下のようなコードが書ける。
static void main(args) {
new TableBuilder().with {
sheet( "test"
)( style(header)
)( "No" )( "名前" )( nextRow
)( style(normal)
)( 1 )( "琵琶湖" )( nextRow
)( 2 )( "多来加湖" )( nextRow
)( 3 )( "富内湖" )( endTable )
}.write(new FileOutputStream("sample.xls"));
}
TableBuilder の中では、Apache POI を使っていて、実行すると 下のような Excel ファイルが sample.xls に書き出される。
カッコの開き方が気に入らないが、しょうがないらしい。下の A、B は等価だけど、C は別ものに解釈される。上例を C のようなカッコのに直すと、動作しない。
| A | B | C |
|---|---|---|
("A1")("B1")(
"A2")("B2") | ("A1")("B1"
)("A2")("B2") | ("A1")("B1")
("A2")("B2") |
TableBuilder は下のコードのようになる。
class TableBuilder {
def book
TableBuilder() { book = new HSSFWorkbook() }
def nextRow = { cell, style ->
cursor.curry(cell.offset(1, -cell.columnIndex), style)
}
def endTable = { cell, style -> book }
def cursor = { cell, style, arg ->
if (arg instanceof Closure) { arg(cell, style) }
else {
cell.setCellValue(arg)
if (null != style) cell.cellStyle = style
cursor.curry(cell.next(), style)
}
}
def start(sheet){ cursor.curry(sheet.cellAt(0, 0), null) }
def sheet(name) { start(book.createSheet(name)) }
def style(styleClosure) {
{ cell, style-> cursor.curry(cell, styleClosure(book))}}
}
また、POI の API が Groovy コードの中で馴染むように、Mixin でメソッドを追加した。
class CellMix {
def next() { offset(0, 1) }
def offset(r, c) {
sheet.cellAt(rowIndex + r, columnIndex + c) }
}
class RowMix {
def cellAt(c) { getCell(c) ?: createCell(c) }
}
class SheetMix {
def rowAt(r) { getRow(r) ?: createRow(r) }
def cellAt(r, c) { rowAt(r).cellAt(c); }
}
class CellStyleMix {
def borderMethodName = { s-> "setBorder" + s.capitalize() }
def setBorder = { arg, edge ->
owner."${borderMethodName(edge)}"(arg."$edge" ?:BORDER_NONE);
setBorder.curry(arg) }
def setBorder(Map arg) {
setBorder.curry(arg)("top")("left")("bottom")("right") }
}
カッコを連鎖させるやり方にしたのは、単にクロージャとカリー化を試したかっただけで、実は、普通のクラスと leftShift() のオーバライドだけで、 下のような C++風の書き方もできて、こっちの方がむしろスッキリしたコードになる。
sheet("test") <<
"A1" << "B1" << endRow <<
"A2" << "B2" << endTable
0 件のコメント:
コメントを投稿