react - clojurescript tutorial
¿Cómo puedo obtener Clojure: pre &: post para informar su valor fallido? (3)
¿Algo como abajo donde la especificación del clojure está explicando el problema? Esto arrojará un error de aserción que puede detectar.
(defn string-to-string [s1]
{:pre [ (or (s/valid? ::ur-spec-or-predicate s1)
(s/explain ::ur-spec-or-predicate s1)]}
s1)
(defn string-to-string [s1]
{:pre [(string? s1)]
:post [(string? %)]}
s1)
Me gusta: condiciones previas y posteriores, me permiten averiguar cuándo he puesto "clavijas cuadradas en agujeros redondos" más rápidamente. Tal vez sea incorrecto, pero me gusta usarlos como una especie de corrector tipo mans pobre. Esto no es filosofía, sin embargo, esta es una pregunta simple.
Parece en el código anterior que debería poder determinar fácilmente que s1
es un argumento de función en la condición :pre
. De manera similar, %
en la condición :post
es siempre el valor de retorno de la función.
Lo que me gustaría es imprimir el valor de s1
o %
cuando cualquiera de estas condiciones respectivas falla dentro de AssertionError. Así que consigo algo como
(string-to-string 23)
AssertionError Assert failed: (string? s1)
(pr-str s1) => 23
Con AssertionError que contiene una sola línea para cada variable que se identificó como proveniente de la lista de argumentos de la función y que se hizo referencia en la prueba que falla. También me gustaría algo similar cuando el valor de retorno de la función falla la condición de :post
.
Esto haría que fuera trivial detectar rápidamente cómo usé mal una función al intentar diagnosticar desde AssertionError. Al menos me dejaría saber si el valor es nil
o un valor real (que es el error más común que cometo).
Tengo algunas ideas de que esto se podría hacer con una macro, pero me preguntaba si había alguna forma segura y global para redefinir básicamente lo que (defn
y (fn
y amigos hacen para que :pre
y :post
también impriman el valor). (s) que llevan a que la prueba falle.
@octopusgrabbus sugirió esto al proponer (try ... (catch ...))
, y mencionó que podría ser demasiado ruidoso, y aún está envuelto en una afirmación. Una variante más simple y menos ruidosa de esto sería una sintaxis simple (or (condition-here) (throw-exception-with-custom-message))
, como esta:
(defn string-to-string [s1]
{:pre [(or (string? s1)
(throw (Exception. (format "Pre-condition failed; %s is not a string." s1))))]
:post [(or (string? %)
(throw (Exception. (format "Post-condition failed; %s is not a string." %))))]}
s1)
Básicamente, esto le permite utilizar condiciones previas y posteriores con mensajes de error personalizados: las condiciones previas y posteriores aún se verifican como normalmente lo harían, pero su excepción personalizada se evalúa (y, por lo tanto, se lanza) antes de que pueda suceder el error de afirmación.
Podrías envolver tu predicado con la macro is
de clojure.test
(defn string-to-string [s1]
{:pre [(is (string? s1))]
:post [(is (string? %))]}
s1)
Entonces obtienes:
(string-to-string 10)
;FAIL in clojure.lang.PersistentList$EmptyList@1 (scratch.clj:5)
;expected: (string? s1)
;actual: (not (string? 10))