Ruby関連のツールではRubyで書かれたDSLがよく使われます。先ほど説明した
RakefileもRubyを使ったDSL
です。しかし、そもそもDSLとは何でしょうか? そして、なぜRubyで書かれたDSLがよく登場するのでしょうか?
人間と機械に読みやすい言語 DSL
DSLとは"Domain Specific Language"の略
で、「ドメイン固有言語」(または「ドメイン特化言語」)
と訳されます。これを筆者の言葉でもう少し噛み砕いて説明するなら、「何か特別な目的を実現するために定義された、人間(=非技術者)にとって読みやすく、機械にとっても処理しやすいテキストフィルの記述ルール
」になります。
P424
DSL(Domain Specific Language)は、ドメイン固有言語と訳されてます。DSLは、Java、C#などの汎用言語とは違い、
ある特定の種類の問題に特化したコンピュータ言語
です。
構造化
classやdefのようなキーワードや、丸括弧やセミコロンのような
記号類など、余計な情報が多すぎて元のRakefileにあったシンプルさや文書っぽさは失われ
ていますね。
Rubyではメソッド呼び出しのため丸括弧(())が省略できます
。また命令の区切りは改行になるのでいちいちセミコロン(;)をつける必要もありません。また、トップレベルに命令を羅列できる
ので、main関数やmainクラスでプログラム全体を囲む必要もありません。ブロックも情報を構造化(入れ子)にする用途に使うと便利です。
Rubyにはこうした特徴があるため、
Rubyのプログラムをあたかも設定ファイルやテキストドキュメント
のように使うことができます。そして、「人間が読みやすいテキスト」がそのまま「Rubyのプログラム」になっている
ため、ツールやライブラリを作る開発者にとっても非常に都合が良いのです。
Rubyを使っているとDSL、つまり「
設定ファイルのようなRubyプログラム
」や「ドキュメントのようなRubyプログラム
」がいろいろなところに登場します。この後で説明されるBundlerのGemファイルも
そうですし、テスティングフレームワークのRspecも
そうです。Railsや各種gemで使われる設定ファイルも
「一見すると設定用のテキストファイルっぽいが、実はRubyプログラムそのもの」であるケースがよくあります。
-
設定ファイルのようなRubyプログラム
」や「ドキュメントのようなRubyプログラム
とはどんなコードだろうか?
このようにRubyはDSLを通じて、人間と機械のスムーズな橋渡しを担ってくれているのです。
DSLの必要性
Ruby on Railsの登場以降、メタプログラミングという言葉を良く聞くようになりました。
メタプログラミングというと、マクロ、コードの自動生成、テンプレート
を上げることができます。DSLは、メタプログラミングで使われます。メタプログラミングは、一般的なプログラムとはまったく違った方法をとっているので、その概念、仕組みを知る必要があります。
メタプログラミングとは、ロジックを直接コーディングするのではなく、
あるパターンをもったロジックを生成する高位ロジックを定義
する方法のこと。主に対象言語に埋め込まれたマクロ言語によって行われる。
(2)メタプログラミング:
一般的なプログラムでは実現することができなかった次の2つの点を実現することができます。
a.プログラムの再利用
b.データを自然な形で扱えるようにする
つまり、DSLを作ることで「プログラムを生成するプログラムを書く」ことが容易に解決できます。まず、プログラムを生成する仕様を決めます。クラス名は、ファイル名から取得します。要素名(フィールド)は、1行目に記述されている列名から取得します。この
プログラムを動的に生成
します。動的に生成されたプログラムにアクセスすることで、CSVファイルから取得したデータにアクセスすることが可能になります。しかし、
このプログラムは、CSVファイルからデータを取得し、提供することのみを解決してくれます。これが、“DSL(ドメイン固有言語)”と言われる所以
です。この例のDSLは、一般的に内部DSLもしくは組み込みDSLと言われてます(後述「内部DSLと外部DSL」を参照)。この例を作る際に参考にしたのが、Ruby on RailsのActiveRecordです。
DSLの種類
内部DSL
言語自身で強力なDSLを記述する事のできるLispは、「プログラム可能なプログラミング言語」と言われてます。この手法をとっているDSLは、内部DSLもしくは、組み込みDSLと言われてます。
RubyはLispの血統であることから、Ruby、Ruby on Railsを使って書かれたコードの中には、多くの内部DSLが含まれてい ます。以下のサンプルコードは、内部DSLを使って書かれてます。ここで重要なのは、Rubyのシンタックスを違反することなく書かれている、ということです。このことにより、ホスト言語のパワーと既存のツールのすべてを利用することができます。
外部DSL
ホスト言語とは異なる言語(XML、Makefileのような独自形式)で作成されたDSLは、外部DSLと呼ばれてます。UNIX伝統のリトル言語がそれに相当します。外部DSLの最大のメリットは、DSL設計者が自由にフォーマットを決められるということです。しかし、この方法を採用すると、フォーマットをパースする処理を書かねばなりません。
また、この手法を使ったDSLは、GUIツールを提供していることが多いのも大きな特徴です。Eclipseには、外部DSLをサポートする多くのプラグイン(Seasar2、Spring、Hibernate、JBoss Rules など)が既に存在してます。
感想
DSLでメタプログラミングができてあるパターンをもったロジックを生成する
を実現させることができる