I look forward to pre/post conditions becoming more helpful. Truss is a
good example of how things can improve. I think part of the challenge is
not making the code too messy.
Here's a proof of concept of how metadata in the pre/post/assert expression
could be used to craft nice messages:
(defn get-highlander [hs]
{:pre [^{:msg "There can be only one"} (= 1 (count ^:var hs))]}
(first hs))
And the error messages can be presented as:
user=> (get-highlander ["asdf" "ss"])
AssertionError Assert failed: There can be only one
(= 1 (count hs))
where hs is ["asdf" "ss"] user/get-highlander (NO_SOURCE_FILE:4)
This works by modifying the assert macro so it works for general asserts too
(assert (test (complex (form (with (a ^:var varible))))) "bad variable")
The modifications to assert seem quite modest but I'm unsure if this is an
approach which is considered to be the correct solution.
(declare tree-seq)
(defn pr-vars [form env]
(let [var? (fn [x] (-> x meta :var))]
(for [var (filter var? (tree-seq seq? identity form))]
`(str "\n where " '~var " is " (pr-str ~var)))))
(defmacro assert
"Evaluates expr and throws an exception if it does not evaluate to
logical tru"
{:added "1.0"}
([x]
(when *assert*
`(when-not ~x
(throw (new AssertionError (str "Assert failed: " ~(or (-> x meta :msg)
"")
"\n" (pr-str '~x)
~@(pr-vars x &env)))))))
([x message]
(when *assert*
`(when-not ~x
(throw (new AssertionError (str "Assert failed: " ~message
"\n" (pr-str '~x)
~@(pr-vars x &env))))))))
On Thursday, 31 March 2016 03:09:03 UTC+11, Niels van Klaveren wrote:
>
> Truss <https://github.com/ptaoussanis/truss>also has good support for :pre
> and :post conditions
> <https://github.com/ptaoussanis/truss#assertions-within-prepost-conditions>
>
> On Monday, July 11, 2011 at 7:40:48 PM UTC+2, frye wrote:
>>
>> Note: This message was originally posted by ' Shantanu' on the "*Re:
>> Clojure for large programs*" thread.
>>
>> I took a look at Shantanu's macros, and I like the concept a lot. But I
>> would prefer something baked into the :pre condition itself. The reason is
>> that it just removes a layer of indirection. If you dig into '
>> *clj/clojure/core.clj*', you can see that the 'fn' macro is using
>> 'assert' to test these conditions. Assert allows error messages to be
>> applied, ie:
>>
>> *user => (assert false) *
>>
>> *user => (assert false "fubar") *
>>
>>
>>
>> However, (defmacro fn ...) assumes that just the boolean condition is
>> being passed in, A). But I'd like to have the option to pass in a message
>> B).
>>
>>
>> *A) *
>>
>> *(def fubar *
>>
>> * (fn []*
>>
>> * {:pre [ (true? false) ] }*
>>
>> * (println "Hello World")))*
>>
>> *(fubar)*
>>
>>
>> *B) *
>>
>> *(def thing *
>>
>> * (fn []*
>>
>> * {:pre [ [(true? false) "A false message"] ] }*
>>
>> * (println "Hello World")))*
>>
>> *(thing)*
>>
>>
>>
>> I reworked the 'fn' macro, only for the :pre condition, as a
>> demonstration (see here <http://pastebin.com/fETV1ejJ>). The calling
>> semantics don't change that much. Is there any interest in putting this
>> into core? I'd use Shantanu's workaround otherwise, or in the interim.
>>
>> Thanks
>>
>> Tim Washington
>> [email protected]
>> 416.843.9060
>>
>>
>>
>> On Sun, Jul 3, 2011 at 11:42 AM, Shantanu Kumar <[email protected]>
>> wrote:
>>
>>>
>>>
>>> On Jul 3, 7:39 pm, Timothy Washington <[email protected]> wrote:
>>> > I'm using pre / post assertions quite a bit in a project I'm building.
>>> And I
>>> > too would love to see better or custom error messages for each
>>> assertion.
>>>
>>> That should be possible with a macro. For example, I use this:
>>>
>>> https://bitbucket.org/kumarshantanu/clj-miscutil/src/acfb97c662d9/src/main/clj/org/bituf/clj_miscutil.clj#cl-1009
>>>
>>> Maybe you need something like this(?):
>>>
>>> (defmacro verify-my-arg
>>> "Like assert, except for the following differences:
>>> 1. does not check for *assert* flag
>>> 2. throws IllegalArgumentException"
>>> [err-msg arg]
>>> `(if ~arg true
>>> (throw (IllegalArgumentException. ~err-msg))))
>>>
>>> Then use it thus:
>>>
>>> (defn foo [m]
>>> {:pre [(verify-my-arg "m must be a map" (map? m))]}
>>> (println m))
>>>
>>> Regards,
>>> Shantanu
>>>
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To post to this group, send email to [email protected]
>>> Note that posts from new members are moderated - please be patient with
>>> your first post.
>>> To unsubscribe from this group, send email to
>>> [email protected]
>>> For more options, visit this group at
>>> http://groups.google.com/group/clojure?hl=en
>>>
>>
>>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.