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 
>> twas...@gmail.com 
>> 416.843.9060 
>>
>>
>>
>> On Sun, Jul 3, 2011 at 11:42 AM, Shantanu Kumar <kumar.s...@gmail.com> 
>> wrote:
>>
>>>
>>>
>>> On Jul 3, 7:39 pm, Timothy Washington <twash...@gmail.com> 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 clo...@googlegroups.com
>>> Note that posts from new members are moderated - please be patient with 
>>> your first post.
>>> To unsubscribe from this group, send email to
>>> clojure+u...@googlegroups.com
>>> 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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
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 clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to