良いコ-ドへの道―普通のプログラマのためのステップアップガイド

第5回 メタプログラミング―Excelを使ったDSLを作ろう―その1 メタプログラミングとは?

この記事を読むのに必要な時間:およそ 3 分

内部DSL

次は内部DSLの例を見てみましょう。以下はRuby on Railsのルーティング処理です。

ActionController::Routing::Routes.draw do |map|
  map.connect '/todo/:id',
    :controller => "todo", :action=> "show"
end

一見,設定ファイルや独自言語のようにも見えますが,通常のRuby構文のみで表現されています。このようにホストとなる言語のみで実現するDSLを「内部DSL」⁠または言語内DSL)と言います。Rubyではメソッド呼び出しの括弧が省略可能だったり,do~endでブロックが使えたりなど内部DSLを簡単に実現できる環境がそろっています。内部DSLではホスト言語の構文のみで実現するので,新たに独自の構文を覚える必要はありません(フレームワークの作法やAPIは覚える必要があります⁠⁠。また,言語のパワーをフル活用できるので,たとえば繰り返しや分岐などの制御構造と組み合わせて使用できるといったメリットもあります。

Javaのように構文の自由度があまり高くない言語では,Rubyのような内部DSLを行うことは難しい部分があります。限定的ながらJavaで内部DSLを実現する方法としてアノテーションが挙げられます。以下はWebアプリケーションフレームワークCubbyのアクションメソッドに対するアノテーションです。

@Accept(RequestMethod.GET)
@Path("/todo/{id}")
public ActionResult show() {
  ...
}

これは「/todo/{id}というパスでGETアクセスの場合,showメソッドが実行される」という意味になります。設定のようでもありますが,フレームワークの挙動を変えるので内部DSLであるとも言えます。

ただ,アノテーションは利用できる個所に制限がありますし,複雑なアノテーションは可読性が落ちてしまうので,上記の例のようにフレームワークにメタ的な情報を渡したり,フレームワークに対する目印を付けたりといったシンプルな利用形態が多いです。またJavaでも「流れるようなインタフェース」注1を利用することでもう少し言語っぽい内部DSLを実現できますコラム参照⁠。

注1)
Martin Fowler's Bliki流れるようなインターフェース

COLUMN 流れるようなインタフェースとstaticインポートによる内部DSL

S2JDBCEasyMockなどのフレームワークでは,⁠流れるようなインタフェース」と呼ばれるメソッドチェインを利用した可読性の高いAPIを提供しています。

以下はS2JDBCのコードです。

List<Employee> results = jdbcManager.from(Employee.class)
    .join("department")
    .where("id in (? , ?)", 11, 22)
    .orderBy("name")
    .getResultList();

また,以下はEasyMockのコードです。

expect(mock.voteForRemoval("Document"))
    .andReturn((byte) 42).times(3)
    .andThrow(new RuntimeException(), 4)
    .andReturn((byte) -42)

上記のコードを薄目で見て,括弧とドットがないものとして考えてみてください。まるで独自のミニ言語(=DSL)のように見えませんか? このように,流れるようなインタフェースを用いると,Javaなど静的言語では難しい内部DSLを実現できるようになります。通常のメソッド呼び出しのみで実現できるため,副次的な効果としてIDEのコードアシスト機能を使ってさくさくコーディングができるというメリットもあります。

ただし,流れるようなインタフェースを使いやすく作るには,APIのセンスが必要で設計にも時間がかかります。慎重に検討して,ポイントを押さえて導入するのがよいでしょう。

また,流れるようなインタフェースと同様,Java 5から導入されたstaticインポートも内部DSLっぽい記述を実現する際によく活用されます。先ほどのEasyMockのexpectメソッドがstaticインポートされたメソッドです。

著者プロフィール

縣俊貴(あがたとしたか)

学生時代にMSXで制限された環境でのプログラミングの楽しさを学ぶ。以来,オープンソースのWiki実装「MobWiki」の開発や受託開発などを経て,現在はプロジェクト管理ツール「Backlog」,ドローツール「Cacoo」など,コラボレーション型のWebサービスの企画と製品開発を行う。また,Webアプリケーションフレームワーク「Cubby」のコミッタを務める。福岡在住。株式会社ヌーラボ所属。

ブログ :http://d.hatena.ne.jp/agt

Twitter:@agata