2016-12-20 2 views
3

Ich möchte eine Spezifikation schreiben mit keys/keys* aber in der Lage, die Wert-Spezifikationen, die nicht unterstützt by design inline, und ich bekomme die Begründung dahinter. Aber manchmal tun wollen (oder einfach, durch Legacy oder 3rd-Party) Kopplung zwischen Schlüssel und Werte, wenn es einen bestimmten Kontext für die Karte.Schlüssel */Schlüssel mit inlined Wert specs

Ich bin immer noch neu in der Spezifikation und dies ist nur mein erstes Mal mit einem bestehenden Projekt zu integrieren und es gibt mir ständig Probleme, weil es viel zu viel angenommen, vor allem aus dem oben genannten Grund. Z.B. Stellen Sie sich eine Karte vor, die einen Zeitraum beschreibt und einen until Schlüssel für ein Datum hat, und in derselben ns gibt es eine Karte für die Listenverarbeitung, und es gibt eine until, die eine Prädikatfunktion übernimmt. Ich muss jetzt mit dem manuellen Schreiben voll Namespaced-Schlüssel für Namespaces, die nicht einmal vorhanden sind (alias ing ist niedlich, aber es müsste ständig über mehrere Namespaces/Dateien dupliziert werden) schreiben. Abgesehen davon, dass ich irritierend bin, habe ich das Gefühl, dass es auch fehleranfällig ist.

Und ein anderer Ort, wo keys/keys* davon ausgeht, ist, wenn ich auch Schlüsselwörter als meine Schlüssel will. Ich schreibe jetzt ein DSL für Nicht-Programmierer, aber technische Benutzer, und unterm Strich möchte ich eine Karte mit Symbolen als Schlüssel spezifizieren. Das scheint überhaupt nicht unterstützt zu werden.

Gibt es etwas, das ich nicht bekomme? oder fehlt der spezifikation wirklich die wesentliche funktionalität?

Antwort

4

Sie können eine Karte mit Symbolen als Schlüssel entweder mit spec Karte-of:

(s/def ::sm (s/map-of symbol? any?)) 

oder durch spec'ing die Karte als eine Sammlung von Einträgen:

(s/def ::sm (s/every (s/tuple symbol? any?) :kind map? :into {})) 

Letzteres i Es ist besonders interessant, da man anstelle eines einzelnen Tupels s/oder viele verschiedene Arten von Tupeln verwenden kann, um interessantere Karten zu beschreiben. Sie können auch diese Symbole zu anderen bestehenden Spezifikationen auf diese Weise verbinden:

(s/def ::attr1 int?) 
(s/def ::attr2 boolean?) 
(s/def ::sm (s/every (s/or :foo (s/tuple #{'foo} ::attr1) 
          :bar (s/tuple #{'bar} ::attr2)) 
       :kind map? :into {})) 
(s/valid? ::sm {'foo 10 'bar true}) ;; => true 
+0

Danke Alex, ich werde es ausprobieren. Ich gehe davon aus, dass es keine Pläne für diese Funktionalität gibt, oder? (Ich meine etwas, um den letzten Code prägnant zu machen, vielleicht ähnlich wie "Schlüssel"). – MasterMastic

+0

Keine Pläne, jetzt mehr in diesem Bereich hinzuzufügen (aber wer weiß es schließlich) –

1

Ich muss jetzt zu Chaos mit manuell vollständig Namensraum Schlüssel für Namespaces zu schreiben, die nicht einmal existieren

Ich habe auch diesen Ansatz unter Verwendung von, und ich denke, ich mag es eigentlich mehr Dann stelle ich sicher, dass die Namespaces Ihrer Keywords immer echten Clojure NS-Formularen entsprechen. Ich benutze Stichworte wie :business-domain-concept/a-name anstatt :my-project.util.lists/a-name.

Sie können Schlüsselwörter mit beliebigen Namespaces erstellen, die keinem Clojure NS zugeordnet sind. In Ihrer until Situation könnten Sie beispielsweise eine :date/until Spezifikation definieren, die Daten beschreibt, und eine (vielleicht gibt es einen besseren Namen für diese) :list/until Spezifikation, die Ihr Listenverarbeitungsfeld beschreibt.

Es klingt, als ob Sie bereits wissen, dass dieser willkürliche Schlüsselwort-Namespace-Ansatz - insbesondere kaufe ich, dass es sich fehleranfällig anfühlt, da Sie diese Sachen von Hand eingeben und die Spezifikation nicht scheint Drossel, wenn Sie Ihre s/keys a :fate/until aus Versehen füttern. FWIW, ich glaube, Sie haben gerade den Schmerz, den Namespace-Schlüsselwörter speziell lösen sollen: Sie befinden sich in einer Clojure-Datei, Sie haben zwei Maps mit Schlüsseln mit dem Namen until, und sie bedeuten zwei völlig verschiedene Dinge.

Ich schreibe eine DSL für Nicht-Programmierer, aber technisch versierten Benutzer gerade jetzt, und Endergebnis ist, dass ich eine Karte mit Symbolen als Schlüssel spec will.

Ich denke, dass map-of ist, was Sie wollen hier:

user=> (s/def ::valid-symbols #{'foo 'bar 'baz}) 
:user/valid-symbols 
user=> (s/def ::symbol-map (s/map-of ::valid-symbols int?)) 
:user/symbol-map 
user=> (s/valid? ::symbol-map {'foo 1 'bar 3}) 
true 
user=> (s/valid? ::symbol-map {'foo 1 'quux 3}) 
false 
+0

Ich dachte daran, mit ': Domain/name' als gut, aber Namen Klirren leicht passieren könnte (zB wenn alle sind Sachen def wie': Zeit/bis "). 'map-of' ist nicht geeignet, da ich einen Schlüssel mit einer Spezifikation vergleichen muss. – MasterMastic

+0

Guter Punkt - vielleicht ': my-app.domain/name', dann? –