Commits

Anonymous committed 6868a41

add `try-while` and tests

  • Participants
  • Parent commits 164ae94

Comments (0)

Files changed (2)

File src/main/clj/org/bituf/clj_miscutil.clj

 
 (defn repeat-exec
   "Returns a lazy (infinite!, or length n if supplied) sequence of results after
-  executing f successively."
+  executing f (no-arg function) successively."
   ([f]  {:post [(seq? %)]
          :pre  [(fn? f)]}
     (let [run (fn g[] (cons (f) (lazy-seq (g))))]
     (take n (repeat-exec f))))
 
 
+(defmacro try-while
+  "Return the result after executing code body; on exception keep re-trying as
+  long as pred returns true. The predicate function accepts thrown exception
+  as argument. Unless pred throws an exception, no exception will escape the
+  code body itself."
+  [pred & body] {:pre [`(fn? ~pred)]}
+  `(first (some #(let [e# (last %)]
+                   (if e# (if (~pred e#) false
+                            (throw e#))
+                     %))
+            (repeat-exec #(maybe ~@body)))))
+
+
 (defmacro try-times
   "Execute body of code; on exception retry maximum n-1 times. Throw last
   encountered exception if none of the tries were successful."
-  [n & body] {:pre [(posnum? n)]}
+  [n & body] {:pre [`(posnum? ~n)]}
   `(let [c# (repeat-exec (dec ~n) #(maybe ~@body))
          r# (some #(if (last %) nil %) c#)]
      (first (or r# [(do ~@body)]))))

File src/test/clj/org/bituf/test_clj_miscutil.clj

     (is (= [5 5] (repeat-exec 2 (constantly 5))))
     (is (thrown? NullPointerException (repeat-exec 20
                                         (throw (NullPointerException.))))))
+  (testing "try-while"
+    (let [a (atom 0)
+          b #(do (swap! a inc)
+               (if (< @a 5) (throw (NullPointerException.))
+                 (%)))
+          f #(b (fn [] (+ 10 @a))) ; returns number
+          g #(b (fn [] false))]    ; returns logical false
+      (is (= 15 (try-while (fn [^Throwable e] (< @a 7)) (f))))
+      (is (= 5 @a))))
   (testing "try-times"
     (let [a (atom 0)
           b #(do (swap! a inc)