Clojureに新しいコアライブラリ、clojure.spec
が加わった。 Clojureの作者、Rich Hickeyによると、 このライブラリは、データおよび関数の仕様記述とテスティングに関する、標準的で統合されたシステムの提供を目的としている。 このライブラリは、Clojureコードの自動的な検証だけでなく、生成的テスティング、エラー報告、デストラクチャリング、その他様々なタスクに利用することができる。
clojure.spec
は、仕様の記法を改善する。 仕様記述には、述語(integer?
や#(< 42 % 66)
など)の論理結合が使用される。 clojure.spec
は、spec/and
やspec/or
といった、論理演算子を提供する。 Hickey氏によれば、clojure.spec
は、コントラクトシステム(contract systems)として知られる成果を元に開発されている。 コントラクトシステムは、RDFやRacket、その他にみられる。
たとえば、あるmap
は、:req
と:opt
を引数として、keys
を呼ぶものとして記述できる。
(spec/keys :req [::x ::y (or ::secret (and ::user ::pwd))] :opt [::z])
注目すべきは、このmap
の仕様が、与えられたキーワードに対応する値の種類が何かを指定する方法を提供しないことだ。 直接指定する代わりに、clojure.spec
は、キーワード自身に紐付く名前空間キーワードに関連付けられた値の仕様を推奨- 時には強制- する。
(spec/def ::x integer?)
(spec/def ::y integer?)
(spec/def ::z integer?)
このような値の仕様記述は、同一のキーワードを使用するどのようなmap
に対しても適用される。
clojure.spec
においては、シーケンスは、正規表現として仕様記述できる。 述語がどのようにシーケンスと一致するかを記述した正規表現として記述できるのだ。 関数は、3つの分離した仕様として記述できる。
clojure.spec
を使用したClojureの仕様記述に関する詳細は、ここを参照してほしい。
仕様を一度書けば、値に対してconform
を適用することで、検証できるようになる。 もし、conform
が:clojure.spec/invalid
を返した場合は、explain
により、原因を探ることができる。 instrument
を使うと、関数を一つにまとめあげる。これにより、関数の持つ3つの仕様をテストできる。 テストのために、run-tests
を利用できる。 これは、1つの名前空間に対して生成的テストスイートを実行する。 あるいは、gen
により、1つの仕様のためのジェネレータを構築できる。 このジェネレータは、test.check
互換である。
clojure.spec
は、Clojureに仕様記述を取り込む初の試み、というわけではない。 これまでにも、開発者たちは、SchemaやHerbertを使用してきた。 Clojureの動作を保証するための別のアプローチとしては、clojure.typed
もある。 clojure.typed
は、コンパイル時検証のコンセプトを実現するための、漸進的型付け(gradual typing)ライブラリである。
clojure.spec
を利用可能なClojureのバージョンは、1.9.0/alpha1以降である。 project.clj
に次の記述を追加することにより、利用できるようになる。[org.clojure/clojure "1.9.0-alpha1"]