Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return successively different values for a symbol `with-redefs` (Clojure)

I am hoping to use with-redefs to mock user input from STDIN.

First, I am testing incorrect input, which should re-ask the user for input. Then, the correct input should be given.

Is there a way to use with-redefs to bind successively different values to a given symbol?

I'm trying to get this functionality:

(with-redefs [read-line (fn [] "HI")
              read-line (fn [] "OK")]
  (do (println (read-line)) ;; -> "HI"
      (println (read-line)))) ;; -> "OK"
like image 705
Ryan Asensio Avatar asked Jan 22 '18 03:01

Ryan Asensio


1 Answers

Not specifically, but you could always 'let-over-lambda' with some state!

(let [a (atom ["a" "b"])]
  (defn f []
    (let [r (first @a)]
      (swap! a rest)
      r)))

(f) ;; "a"
(f) ;; "b"
(f) ;; nil

In your particular case, it would make sense to have a function that generates the 'stateful' function, So a full example would be:

(defn maker [l]
  (let [a (atom l)]
    (fn []
      (let [r (first @a)]
        (swap! a rest)
        r))))

(with-redefs [read-line (maker ["HI" "OK"])]
  (do (println (read-line)) ;; -> "HI"
      (println (read-line)))) ;; -> "OK"
like image 53
Shlomi Avatar answered Nov 02 '22 22:11

Shlomi