Testing map with timestamp value in Clojure - unit-testing

I am testing a function in Clojure which takes a map as input and outputs a map to which the field :timestamp (current-timestamp) is added.
I have problems testing for equality as I cannot predict which timestamp will be added by the function.
(is (= output (convert-map input)))
I thought about dissoc-ing the :timestamp from the output of the function but that seems convoluted, so I wonder if there is a better solution.

You could use the fn with-redefs, and make the fn you're using to get the timestamp always return the same timestamp when testing.
(with-redefs [timestamp-fn (constantly "2019-07-28T12:00:00Z")]
(your-fn params))
You can read about it here: https://clojuredocs.org/clojure.core/with-redefs

Clojure's metadata feature was designed with this in mind. It provides a way to store information about some data that is independent of the data itself.
user> (defn convert-map [input]
(with-meta input {:timestamp (clj-time.core/now)}))
#'user/convert-map
user> (convert-map {:a 1 :b 1})
{:a 1, :b 1}
user> (def input {:a 1 :b 1})
#'user/input
user> (def output (convert-map {:a 1 :b 1}))
#'user/output
user> (:timestamp (meta output))
#object[org.joda.time.DateTime 0x29eb7744 "2019-07-25T15:36:16.609Z"]
user> (= input output)
true
This preserves all equality concepts. It is very useful to keep in mind that the metadata is attached to a particular data so if you do something that copies the contents from input into some other data structure then this metadata would not come along as in this example:
user> (meta (merge output {:c 0}))
{:timestamp
#object[org.joda.time.DateTime 0x29eb7744 "2019-07-25T15:36:16.609Z"]}
user> (meta (merge {:c 0} output))
nil

Either remove the timestamp, or provide a way of making (current-timestamp) produce a known value rather than clock time.

Related

What is the simplest way to find out if a set contains maps with given key values in Clojure?

I really like using contains? because it's so terse and readable. I want to see if a set contains maps that have the same key and value pairs of an example that also had other key value pairs. I'm pretty sure contains? won't work here. Is there an alternative? Maybe I'll have to write one (I'm finally getting into the mindset!). For example, if I had
(def some-set #{{:foo "bar" :beep "boop"}{:foo "bar"} {:foo "bar" :hi "there"}})
what would be a quick way to know if it had any maps that matched {:foo "bar" :one "two"} on :foo "bar"?
Edited: Remembering that a map is a collection of key-value vectors, here is an implementation for the predicate submap?:
(defn submap?
"Returns true if subm is a submap of m, false otherwise."
[subm m]
(every? (fn [[k v]] (= (get m k ::not-found) v)) subm))
This predicate can be used to filter any collection:
(filter #(submap? {:a 1 :b 2} %) [{:a 1} {:a 1 :b 2 :c 3}])
=> ({:a 1, :b 2, :c 3})
Original answer
This solution works but is slower than my updated answer, due to the construction of (set m) for large m
(defn submap?
"Returns true if subm is a submap of m, false otherwise."
[subm m]
(let [kvs (set m)]
(every? kvs subm)))
A generic way would be to write a predicate, that checks if a map
contains another map. This can be done using select-keys to only get
a map with certain keys; using the keys from the map to compare and
then just comparing the result will give you that.
(def maps #{{:foo "bar" :beep "boop"} {:foo "bar"} {:foo "bar" :hi "there"} {:foo "baz"}})
(defn submap?
[submap m]
(= (select-keys m (keys submap)) submap))
(println
(filter (partial submap? {:foo "bar"}) maps))
; → ({:foo bar, :beep boop} {:foo bar, :hi there} {:foo bar})
Yet this is just a simple sequential search. This does not (and AFAIR
there is nothing in core to help) utilize your maps being in a set.
Also note, that the order of the result is undefined since the order of
sets is too.
You can find many predicates of this nature and related helper functions in the Tupelo library, in particular:
submap?
submatch?
wild-match?
wild-submatch?
These are especially helpful in writing unit tests. For example, you may only care about certain fields like :body when testing a webserver response, and you want to ignore other fields like the IP address or a timestamp.
The unit tests show the code in action.

Update multiple elements of a Clojure atom within a single swap statement?

I have an atom that has two parts to it.
(def thing (atom {:queue '() :map {}}))
I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.
Queue individually:
(swap! thing update-in [:queue] (list 1))
(From this question: How to append to a nested list in a Clojure atom?)
Map individually:
(swap! thing assoc-in [:map 1] (:key :value))
(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)
How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)
You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.
(defn take-from-queue [{q :queue, m :map}]
{:queue (rest q), :map (assoc m :new-task (first q))})
(swap! thing take-from-queue)
Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.
Say you have a hash-map atom:
(def m1 (atom {:a "A" :b "B"}))
To change :a and :b at the same time, changing their values to values that are different, say the numbers 1 and 2, use this function:
(defn my-swap! [params]
(swap! m1 (fn [old new] new) params))
, like so:
(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}
And the same effect could be achieved with the following function and execution:
(defn my-multi-swap! [params1 params2]
(swap! m1 (fn [old new1 new2] new2) params1 params2))
(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}
Normally reset! is used if you want to ignore the old value. Here we use it:
(defn my-merge-swap! [params]
(swap! m1 (fn [old new] (merge old new)) params))
(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}
The first parameter to the swap! function is the existing value of the atom, and you must pass in one or more extra parameters, which you can use to give the atom its new value.

Saving+reading sorted maps to a file in Clojure

I'm saving a nested map of data to disk via spit. I want some of the maps inside my map to be sorted, and to stay sorted when I slurp the map back into my program. Sorted maps don't have a unique literal representation, so when I spit the map-of-maps onto disk, the sorted maps and the unsorted maps are represented the same, and #(read-string (slurp %))ing the data makes every map the usual unsorted type. Here's a toy example illustrating the problem:
(def sorted-thing (sorted-map :c 3 :e 5 :a 1))
;= #'user/sorted-thing
(spit "disk" sorted-thing)
;= nil
(def read-thing (read-string (slurp "disk")))
;= #'user/read-thing
(assoc sorted-thing :b 2)
;= {:a 1, :b 2, :c 3, :e 5}
(assoc read-thing :b 2)
;= {:b 2, :a 1, :c 3, :e 5}
Is there some way to read the maps in as sorted in the first place, rather than converting them to sorted maps after reading? Or is this a sign that I should be using some kind of real database?
The *print-dup* dynamically rebindable Var is meant to support this use case:
(binding [*print-dup* true]
(prn (sorted-map :foo 1)))
; #=(clojure.lang.PersistentTreeMap/create {:foo 1})
The commented out line is what gets printed.
It so happens that it also affects str when applied to Clojure data structures, and therefore also spit, so if you do
(binding [*print-dup* true]
(spit "foo.txt" (sorted-map :foo 1)))
the map representation written to foo.txt will be the one displayed above.
Admittedly, I'm not 100% sure whether this is documented somewhere; if you feel uneasy about this, you could always spit the result of using pr-str with *print-dup* bound to true:
(binding [*print-dup* true]
(pr-str (sorted-map :foo 1)))
;= "#=(clojure.lang.PersistentTreeMap/create {:foo 1})"
(This time the last line is the value returned rather than printed output.)
Clearly you'll have to have *read-eval* bound to true to be able to read back these literals. That's fine though, it's exactly the purpose it's meant to serve (reading code from trusted sources).
I don't think its necessarily a sign that you should be using a database, but I do think its a sign that you shouldn't be using spit. When you write your sorted maps to disk, don't use the map literal syntax. If you write it out in the following format, read-string will work:
(def sorted-thing (eval (read-string "(sorted-map :c 3 :e 5 :a 1)")))
(assoc sorted-thing :b 2)
;= {:a 1, :b 2, :c 3, :e 5}

What is the idiomatic way to obtain a sequence of columns from an incanter dataset?

What's the best way to get a sequence of columns (as vectors or whatever) from an Incanter data set?
I thought of:
(to-vect (trans (to-matrix my-dataset)))
But Ideally, I'd like a lazy sequence. Is there a better way?
Use the $ macro.
=> (def data (to-dataset [{:a 1 :b 2} {:a 3 :b 4}]))
=> ($ :a data) ;; :a column
=> ($ 0 :all data) ;; first row
=> (type ($ :a data))
clojure.lang.LazySeq
Looking at the source code for to-vect it makes use of map to build up the result, which is already providing one degree of lazyness. Unfortunately, it looks like the whole data set is first converted toArray, probably just giving away all the benefits of map lazyness.
If you want more, you probably have to dive into the gory details of the Java object effectively holding the matrix version of the data set and write your own version of to-vect.
You could use the internal structure of the dataset.
user=> (use 'incanter.core)
nil
user=> (def d (to-dataset [{:a 1 :b 2} {:a 3 :b 4}]))
#'user/d
user=> (:column-names d)
[:a :b]
user=> (:rows d)
[{:a 1, :b 2} {:a 3, :b 4}]
user=> (defn columns-of
[dataset]
(for [column (:column-names dataset)]
(map #(get % column) (:rows dataset))))
#'user/columns-of
user=> (columns-of d)
((1 3) (2 4))
Although I'm not sure in how far the internal structure is public API. You should probably check that with the incanter guys.

How can I format a map over several lines with pprint?

pprint's docs are kind of a brick wall. If you pprint a map, it comes out on one line like so: {:a "b", :b "c", :d "e"}. Instead, I'd like to be pprinted like this, optionally with commas:
{:a "b"
:b "c"
:d "e"}
How would one do that with pprint?
You can set the *print-right-margin* binding:
Clojure=> (binding [*print-right-margin* 7] (pprint {:a 1 :b 2 :c 3}))
{:a 1,
:b 2,
:c 3}
Not exactly what you're looking for, but it might be enough?
BTW, the best way to figure this out —or at least the approach I took— is to use
Clojure=> (use 'clojure.contrib.repl-utils)
Clojure=> (source pprint)
(defn pprint
"Pretty print object to the optional output writer. If the writer is not provided,
print the object to the currently bound value of *out*."
([object] (pprint object *out*))
([object writer]
(with-pretty-writer writer
(binding [*print-pretty* true]
(write-out object))
(if (not (= 0 (.getColumn #^PrettyWriter *out*)))
(.write *out* (int \newline))))))
nil
Hmmrmmm.. what does with-pretty-writer do to *out*?
Clojure=> (source clojure.contrib.pprint/with-pretty-writer)
(defmacro #^{:private true} with-pretty-writer [base-writer & body]
`(let [new-writer# (not (pretty-writer? ~base-writer))]
(binding [*out* (if new-writer#
(make-pretty-writer ~base-writer *print-right-margin* *print-miser-width*)
~base-writer)]
~#body
(if new-writer# (.flush *out*)))))
nil
Okay, so *print-right-margin* sounds promising...
Clojure=> (source clojure.contrib.pprint/make-pretty-writer)
(defn- make-pretty-writer
"Wrap base-writer in a PrettyWriter with the specified right-margin and miser-width"
[base-writer right-margin miser-width]
(PrettyWriter. base-writer right-margin miser-width))
nil
Also, this is pretty informative:
Clojure=> (doc *print-right-margin*)
-------------------------
clojure.contrib.pprint/*print-right-margin*
nil
Pretty printing will try to avoid anything going beyond this column.
Set it to nil to have pprint let the line be arbitrarily long. This will ignore all
non-mandatory newlines.
nil
Anyway —and perhaps you already knew even this— if you really want to customize the way that pprint works, you can proxy clojure.contrib.pprint.PrettyWriter and pass that down by binding it to *out*. The PrettyWriter class is pretty large and intimidating, so I'm not sure if this was what you originally meant by your "brick wall" comment.
I don't think you can do that, you'll probably need to write your own, something like:
(defn pprint-map [m]
(print "{")
(doall (for [[k v] m] (println k v)))
(print "}"))