2017-12-12 2 views
1

私は受信データの内容を検証する仕様定義を持っています。データはフィールドのマップなので、spec/keysを使用して検証します。例:clojure spec/keysの再利用構造定義コード

(def person-data {:name "Jon Doe", :age 30}) 
(s/def ::name string?) 
(s/def ::age pos-int?) 
(s/def ::person-info (s/keys :req-un [::name ::age]) 
... 
;validate data via spec and make sure no additional keys are included 
(s/valid? ::person-spec some-input) 

ただし、受信データに必要なキーのみが含まれていることを確認する必要があります。 。(この場合は:name:ageキーだけそのために、私は何かの操作を行います。でフィルタリングを受けるだけでこれらのキーを確保し、

(def permitted-keys [:age :name]) 
(select-keys some-input permitted-keys) 

は、私は私のスペック間のいくつかのコードを再利用することができます方法はありますマップ構造( s/keys)の定義と私は許可されたキーをフィルタリングするために取るこの追加のステップ( permitted-keys)?おそらく

s/keys定義からキーのリストを抽出することのいずれかによって、またはにキーの既存のベクトルを渡すこと10?

+0

[このマクロ](https://github.com/gfredericks/schpec/blob/master/src/com/gfredericks/schpec.clj#L13-L35)を参照してください。 –

答えて

1

、それはすべての拠点をカバーし、発電機を提供するので、私はthis macroを見てお勧めしますが、ここにあなたのマップを想定している別テイクのみ使用unnamespacedキーです:

(defmacro keys-strict 
    [& args] 
    (let [{:keys [req opt req-un opt-un]} args 
     ks (into #{} (->> (concat req opt req-un opt-un) 
          (map #(keyword (name %)))))] ;; strip namespaces from keywords 
    `(s/and (s/keys [email protected]) (s/map-of ~ks any?)))) 

再利用するためのここでの唯一のトリックはキーの真理の源は、キースペックは名前空間になりますが、マップキーは同じではありません。あなたはマクロなしで同じことをすることができます。あなたは s/keysの仕様で、s/map-ofの仕様または許可されたキーを制限する他の仕様です。

マップ構造(s/keys)の仕様定義と許可されたキー(allowed-keys)をフィルタリングするためのこの追加手順の間でコードを再利用する方法はありますか?

はい、これはs/keysコールにスプライシングargsことにより、上記実施例で扱う、このより完全なマクロhereに同様に行われます。

注:受け入れるキーを本当に制限する必要がある場合がありますが、後で拡張できるようにマップ仕様を定義することをお勧めします。

+0

これは間違いなく厳密なマップを指定するのに役立ちます。また、あなたは明示的にそれを述べていませんでしたが、マクロ定義の '〜@ args'スプライシングの使用で、私の質問の一部に"どのようにs/keys定義にキーの既存のベクトルを渡すことができますか "これはあなたの答えの一部として示す価値があります。 –

関連する問題