Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confused about phrasing a coll-of #22

Open
marco-m opened this issue Jul 17, 2018 · 3 comments
Open

Confused about phrasing a coll-of #22

marco-m opened this issue Jul 17, 2018 · 3 comments

Comments

@marco-m
Copy link

marco-m commented Jul 17, 2018

Hello, I am missing how to phrase a coll-of. Consider the following:

(ns grape.phrase-test
  (:require [clojure.test :refer [deftest is are testing]]
            [clojure.spec.alpha :as s]
            [phrase.alpha :as phrase]))

(s/def ::just-int int?)

(phrase/defphraser int? [_ _] "Expected an integer (1)")

; this passes
(deftest simplest-possible-spec-for-phrase
  (is (= "val: 1.0 fails spec: :grape.phrase-test/just-int predicate: int?\n"
         (s/explain-str ::just-int 1.0)))
  (is (= "Expected an integer (1)"
         (phrase/phrase-first {} ::just-int 1.0))))

(s/def ::coll-of-ints (s/coll-of int?))

(phrase/defphraser coll? [_ _] "Expected a collection (2)")

(deftest coll-of-ints-fail-pred-int
  ; this passes
  (is (= "In: [0] val: :a fails spec: :grape.phrase-test/coll-of-ints predicate: int?\n"
         (s/explain-str ::coll-of-ints [:a])))
  ; this fails with `nil`
  (is (= "Expected an integer (1)" (phrase/phrase-first {} ::coll-of-ints [:a]))))

; this passes
(deftest coll-of-ints-fail-pred-coll
  (is (= "val: :a fails spec: :grape.phrase-test/coll-of-ints predicate: coll?\n"
         (s/explain-str ::coll-of-ints :a)))
  (is (= "Expected a collection (2)" (phrase/phrase-first {} ::coll-of-ints :a))))

Tests simplest-possible-spec-for-phrase and coll-of-ints-fail-pred-coll pass as expected. On the other hand, test coll-of-ints-fail-pred-int fails, phrase-first returns nil instead of "Expected an integer (1)". What am I missing ?

@alexanderkiel
Copy link
Owner

In such situations, it's always a good idea to define a default phrase which simply returns the problem:

(defphraser :default
  [_ problem]
  problem)

with that, (phrase/phrase-first {} ::coll-of-ints [:a]) returns:

{:path [],
 :pred int?,
 :val :a,
 :via [:grape/coll-of-ints],
 :in [0],
 :phrase.alpha/mappings {},
 :phrase.alpha/via ()}

here you can see that the :pred is only int? without a namespace. Your phraser on the other hand is registered with the predicate clojure.core/int?. Thats not the same.

Here we have a spec bug. Spec should use clojure.core/int? as predicted and not simply int?. They used to use simple symbols of press everywhere in the past. I thing they just forgot to add the namespace here.

A workaround is to use a registered spec like your ::just-int in s/coll-of like so:

(s/def ::coll-of-ints (s/coll-of ::just-int))

I'll look for an existing or open an issue in the Clojure JIRA. This issue stays open until upstream is fixed.

@alexanderkiel
Copy link
Owner

The following upstream issue applies: https://dev.clojure.org/jira/browse/CLJ-2168

@marco-m
Copy link
Author

marco-m commented Jul 18, 2018

Thanks @alexanderkiel, I appreciate your detailed explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants