2017-10-13 3 views
2

Ich habe eine Karte von clojure.specs, die ich verwenden möchte meine Anfragen im laufenden Betrieb wie folgt zu überprüfen:Register clojure.specs aus einer Karte

{::num-id int? 
:project-spec/id ::num-id 
:project-spec/name (s/and string? #((< (count %) 24))) 
:project-spec/project (s/keys :req-un [:project-spec/id :project-spec/name])} 

ich eine dieser Angaben im laufenden Betrieb verwenden kann, um zu validieren Verwendung s/valid?, mit Ausnahme der project-spec/project eins. Dieser erfordert, dass alle anderen im globalen Spezifikationsregister registriert werden, damit sie ordnungsgemäß funktionieren. Wenn ich versuche, spec mit einfachen doseq Funktion zu registrieren, wenn fehlschlägt, da ich lokale Variablen an s/def Makros überlasse und Variablen vor dem Erweitern der Makros auf den Wert nicht auflöst.

(doseq [[name spec] spec-map] 
    (s/def name spec)) 

Ich habe versucht, Makros zu erstellen Variablen eval, bevor sie auf s/def Makros, aber dass man nicht mit CompilerException java.lang.UnsupportedOperationException: Can't eval locals vorbei.

(defmacro reg-spec 
    [name spec] 
    `(s/def ~(eval name) ~(eval spec))) 

(doseq [[name spec] spec-map] 
    (reg-spec name spec)) 

Das letzte, was ich versuchte, ist Variablen eval, wenn zu s/def vorbei, aber das nicht spec Validierung.

(s/def (eval spec-name) (eval spec-spec)) 
CompilerException java.lang.AssertionError: Assert failed: k must be 
namespaced keyword or resolvable symbol (c/and (ident? k) (namespace k)) 

Gibt es eine Möglichkeit zu erreichen, was ich tun möchte? Oder verstehe ich etwas Offensichtliches falsch? Jede Hilfe wird geschätzt!

Antwort

3

Gibt es einen Grund, warum Sie den Spezifikationen keinen Namen über s/def geben möchten? Ein wichtiger Aspekt der Spezifikation sind starke/Namespaced-Namen. Ihr Beispiel gibt ihnen in gewissem Sinne Namen, aber nur als Schlüssel in dieser Karte. Ich würde s/def sie alle. Im obigen Beispiel habe ich ein paar Fehler behoben. Ihre Kartenschlüssel sind Namespaced, daher sollte s/keys:req statt :req-un verwenden.

Sie könnten Ihre Karte der Spezifikationen immer noch erstellen, wenn Sie wollten, aber die Schlüssel/Werte wären identisch.

(s/conform :project-spec/project 
      {:project-spec/id 1, :project-spec/name "123"}) 
;;=> {:project-spec/id 1, :project-spec/name "123"} 
+0

Das Ziel, das ich bin versucht zu erreichen Spezifikationen einer Anwendung sowohl in ClojureScript und Clojure Teil wieder zu verwenden, und ich möchte den Zugriff auf die in der Laufzeit haben, so dass ich und Validierung wurden, entsprechen. Ich möchte sie auch für Funktionen wiederverwenden, die mit diesen Daten arbeiten. Sie als Karte zu haben, macht das praktisch, aber ich habe Probleme, sie aus der Karte in die globale Registrierung einzutragen. –

+0

Auch wenn Sie "req-un" -Schlüssel setzen, die nicht namespaced sind, müssen Sie dennoch namespaced Schlüssel dort zur Verfügung stellen, also kann spec die Werte entsprechend Schlüsseln validieren. –

+3

@SergeyShvets überprüfen Sie [diesen Artikel] (http://blog.cognitect.com/blog/2017/3/24/3xeif9bxaom78qyzwssgwz1leuorh4#sharing-specs-across-the-front-and-back-end). Ich denke, es beschreibt genau, was Sie für die Wiederverwendung von Spezifikationen in CLJ/CLJS versuchen. Außerdem bin ich mir nicht sicher, ob das Speichern der Spezifikationen in einer Karte Vorteile hat, statt sie nur in einem Namensraum zu definieren. –

Verwandte Themen