Java8のLambda式を利用したライブラリ・フレームワークをいくつか試す

Java8 がリリースされてから半年ほど経過しました。
そろそろ Lambda 式を利用したライブラリやらフレームワークやらが出てないかなと GitHub で `java lambda` で検索したところ、いくつか目についたものがあったので試してみた。

#Lambda Behave

https://github.com/RichardWarburton/lambda-behave

##説明
テスティングフレームワーク。
Jasmine みたいな感じで、自然言語に近い形でテストケースを記述できる。

流れるようなインターフェースでテストが書けるのもいいけど、テストケース(spec)を文字列で定義できるのが何気に嬉しい。

##Hello World
###インストール
```groovy:build.gradle
testCompile 'com.insightfullogic:lambda-behave:0.3'
```

###実装
```java:
package sample.lambda_behave;

import static com.insightfullogic.lambdabehave.Suite.*;
import java.util.Stack;
import org.junit.runner.RunWith;
import com.insightfullogic.lambdabehave.JunitSuiteRunner;

@RunWith(JunitSuiteRunner.class)
public class StackSpec {{
    
    Stack<String> stack = new Stack<>();
    
    describe("a stack", it -> {
        
        it.isSetupWith(() -> {
            System.out.println("isSetupWith");
            stack.clear();
        });
        
        it.should("be empty when created", expect -> {
            expect.that(stack).isEmpty();
        });
        
        it.isConcludedWith(() -> {
            System.out.println("isConcludedWith");
            stack.clear();
        });
    });
}}
```

```text:実行結果
isSetupWith
21:22:13.268 [main] INFO  c.i.l.i.reports.SpecificationReport - be empty when created has succeeded
isConcludedWith
```

###説明
####JUnit で動かせる
- `com.insightfullogic.lambdabehave.JunitSuiteRunner` を `@RunWith` に指定することで、 JUnit で動かせる。

####インスタンス初期化ブロックにテストを書く
- テストコードを「インスタンス初期化ブロック」に記述しているけど、 must ではない。
- コンストラクタにテストコードを書いても動く。
- たぶん、コンストラクタの中に書くよりエレガントだから、インスタンス初期化ブロックに書いているのだと思う。

####suite を記述する
- `Suite.describe()` を使って suite を記述する。

####spec を記述する
- `describe()` メソッドの第二引数に Lambda 式を渡す。
- Lambda 式には `Description` のインスタンスが渡される。
- `Description` の `should()` メソッドを使って spec を記述する。

####メインのテストコードを記述する
- `should()` メソッドに渡した Lambda 式には、 `Expect` のインスタンスが渡される。
- `Expect` の `that()` メソッドを起点にして、流れるようなインターフェースで expectation が書ける。
- `com.insightfullogic.lambdabehave.expectations` パッケージの下に expectation を書くためのクラスがあり、メソッドを眺めてみるだけでも何となくどんなチェックができるかが分かる。
- `is()` メソッドは Hamcrest の Matcher を受け取るので、組み込みのメソッドじゃ足りないという場合は Matcher を自作したり、他のライブラリの Matchar を流用したりできる。

##依存関係
```text:
com.insightfullogic:lambda-behave:0.3
+--- junit:junit:4.11
|    \--- org.hamcrest:hamcrest-core:1.3
+--- org.hamcrest:hamcrest-all:1.3
+--- org.mockito:mockito-all:1.9.5
+--- org.slf4j:slf4j-api:1.5.6 -> 1.7.6
\--- ch.qos.logback:logback-classic:1.1.2
     +--- ch.qos.logback:logback-core:1.1.2
     \--- org.slf4j:slf4j-api:1.7.6
```

#micra

https://github.com/noelherrick/micra

##説明
Ruby の Sinatra にインスパイヤされて製作された Web フレームワーク。

ちょっとした Web アプリを作りたいときに便利かも。

ちなみに Sinatra は使ったことないです。

##Hello World
###インストール
Maven には公開されていないので、 zip で落とすか git clone してから `gradlew jar` する。

`build/libs` の下に jar が出力されるので、クラスパスに追加する。

###フォルダ構成
```text:
micra
|-lib/
|  `-micra-master.jar
|-src/main/
|  |-java/sample/micra/
|  |  `-SampleMicraServlet.java
|  `-webapp/WEB-INF/
|     `-web.xml
`-build.gradle
```

###build.gradle
```groovy:build.gradle
apply plugin: 'jetty'

repositories {
    mavenCentral()
}

dependencies {
    providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
    compile 'com.github.spullara.mustache.java:compiler:0.8.14'
    compile fileTree(dir: 'lib', include: '*.jar')
}
```

`mustache` は micra が利用している。

###実装
```java:SampleMicraServlet.java
package sample.micra;

import com.noelherrick.MicraServlet;

public class SampleMicraServlet extends MicraServlet {{
    
    get("/", (req, res) -> "Hello Micra!!");
    
}}
```

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
         version="3.0">

  <servlet>
    <servlet-name>SampleMicraServlet</servlet-name>
    <servlet-class>sample.micra.SampleMicraServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>SampleMicraServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>
```

###実行
```text:
> gradle jettyRun
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
> Building 75% > :jettyRun > Running at http://localhost:8080/micra
```

ブラウザを開いて `http://localhost:8080/micra/` にアクセスする。

![micra.JPG](https://qiita-image-store.s3.amazonaws.com/0/28302/bff11ea2-7012-4162-4c1f-a72e86db161e.jpeg)

###説明
説明不要なくらい見たまんまな感じで実装できる。

HTTP メソッドに対応するリクエストハンドリング用のメソッドは `get`, `post`, `put`, `delete` が用意されている。

##パラメータの取得
###クエリパラメータ
```java:
package sample.micra;

import com.noelherrick.MicraServlet;

public class MicraSampleServlet extends MicraServlet {{
    
    get("/", (req, res) -> "parameter = " + req.getParameter("p"));
    
}}
```

###ルートパラメータ
```java:
package sample.micra;

import com.noelherrick.MicraServlet;

public class MicraSampleServlet extends MicraServlet {{
    
    get("/{name}", (req, res) -> "parameter = " + req.getRouteParameter("name"));
    
}}
```

##ルーティングの条件設定
```java:
package sample.micra;

import com.noelherrick.MicraServlet;

public class MicraSampleServlet extends MicraServlet {{

    get(
        "/",
        req -> req.isParameter("name"),
        (req, res) -> "name = " + req.getParameter("name")
    );
    
    get(
        "/",
        req -> req.isParameter("id"),
        (req, res) -> "id = " + req.getParameter("id")
    );
    
}}
```

- 第２引数で渡した Lambda 式が true を返す時のみ、そのルーティングが適用される。

#Lambda Builder

https://github.com/jexenberger/lambda-builder

##説明
Groovy の Builder みたいな感じで XML を構築できるライブラリ。

テストがないのがキツイ（バグっぽい動きもする）。
けど、今までの Java じゃできなかった実装スタイルに Lambda の可能性を感じた。
（<del>Groovy 使ったほうが手っ取り早い？</del>）

##Hello World
###インストール
これも Maven リポジトリにはないっぽいので、コードを落としてきて `mvn package` でビルドする。

`target/` の直下に jar が出力されるので、クラスパスに追加する。

###build.gradle
```groovy:build.gradle
apply plugin: 'application'

repositories {
    mavenCental()
}

dependencies {
    compile fileTree(dir: 'lib', include: '*.lib')
}
```

`lib/` の下に生成した jar ファイルを置いておく。

`pom.xml` には `commons-beanutils` が依存関係に入っているけど、実装見る限り使ってないので要らないと思う。

###実装
```java:
package sample.lambdabuilder;

import java.util.Arrays;
import java.util.List;

import com.github.lambdabuilder.MarkupBuilder;
import com.github.lambdabuilder.XmlMarkupBuilder;

public class Main {
    
    public static void main(String[] args) {
        
        List<String> list = Arrays.asList("hoge", "fuga", "piyo");
        
        MarkupBuilder html = new XmlMarkupBuilder(false, "html");
        
        html.el("head", () -> {
                html.el("title", "Lambda Builder");
            })
            .el("body", () -> {
                html.el("h1", "Hello Lambda Builder!!")
                    .el("ul", () -> {
                        list.forEach(s -> {
                            html.el("li", s);
                        });
                    });
            });
        
        System.out.println(html.get());
    }
}
```

###実行結果
```html:
<html>
	<head>
		<title>Lambda Builder</title>
	</head>
	<body>
		<h1>Hello Lambda Builder!!</h1>
		<ul>
			<li>hoge</li>
			<li>fuga</li>
			<li>piyo</li>
		</ul>
	</body>
</html>
```

#underscore

|URL|最終コミット（2014/09/30 時点）|
|:--|:--|
|https://github.com/javadev/underscore-java|24日前|
|https://github.com/benjiman/underscore|7ヶ月前|
|https://github.com/nafeger/underscore.java|2年前|
|https://github.com/UnquietCode/Underscore-for-Java|2年前|
|https://github.com/alexogar/underscore.java|2年前|
|https://github.com/jdavidw13/underscore-java|2年前|
|https://github.com/ryantenney/underscore4j|3年前|
|以下略|：|

##説明
謎の激戦区。

https://github.com/javadev/underscore-java

これが最近もコミットされてて、かつテストも書かれている。
ということで、これを使ってみる。

##Hello World
###インストール
リポジトリのトップに jar が置いてあるので、それをダウンロードしてきてクラスパスに追加する。

###実装
```java:
package sample.underscore;

import java.util.Arrays;
import java.util.List;

import com.github.underscore._;

public class Main {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hoge", "fuga", "piyo");
        
        _.each(list, System.out::println);
    }
}
```

###実行結果
```text:
hoge
fuga
piyo
```

Underscore.js と違って、インデックスとかは渡してくれない。
<del>Stream API があれば必要ないか。</del>