Python doctests associate simple tests with the source code (in Python they are in the function documentation). More info and examples here.
Is there anything similar for Clojure?
I am aware of unit tests with clojure.test, but looking for something more closely integrated with the source (typically unit tests are in different files; here I want to have the test "inside" the defn).
Searching around I found this, but it seems very un-lispy (the tests are in actual text, like Python - surely a macro that extends defn would be preferable?).
Or perhaps there is some other way to solve the general problem, which is that I have some tests (generally simple things that demonstrate basic properties of the function) that would be better included with the documentation (I am using marginalia) than in separate unit test files.
update Here's an example: I have a function that calculates the (manhattan) distance (in pixels) from a rectangle of pixels to the centre of the image. That sounds simple, but is complicated by things like the difference in meaning of "centre" for images with odd or even numbers of pixels on sides, or which part of the block you measure from. So I had to write some tests just to get the code straight. And now I look at the docs and really it would be best if the docs included those tests because they explain better than words what the function does...
and the test flag in metadata, http://clojure.org/special_forms
(defn
^{:doc "mymax [xs+] gets the maximum value in xs using > "
:test (fn []
(assert (= 42 (mymax 2 42 5 4))))
:user/comment "this is the best fn ever!"}
mymax
([x] x)
([x y] (if (> x y) x y))
([x y & more]
(reduce mymax (mymax x y) more)))
user=> (test #'mymax)
:ok
user=> (doc test)
-------------------------
clojure.core/test
([v])
test [v] finds fn at key :test in var metadata and calls it,
presuming failure will throw exception
nil
How about :pre and :post expressions?
http://blog.fogus.me/2009/12/21/clojures-pre-and-post/
Related
I'm building a ClojureScript app and I'm having trouble with using reagent to fill a table with data. The two issues I'm having are TONS of warnings of the form
Every element in a seq should have a unique :key
And also, as soon as I call the function that does the rendering, it renders correctly, then my entire page freezes and reloading the page is the only way to fix it. These are my two functions:
(defn foo
[]
[:table
(for [i (range 10)]
[:tr (for [j (range 3)]
[:td (str "Row " i ", Col " j)])])])
And when I call the following, I get the warnings and the page freezes, though it does render correctly:
(reagent/render [foo] (dom/getElement "results"))
Am I approaching the process of filling in data the wrong way? Is there an easier way?
The warning you are getting is due to reagent requiring a unique key value for dynamic elements created along these lines. There are a couple of ways you can fix this. The other thing you need to watch out for is possible issues with using for because it generates lazy sequences. While this is working for you in this context, it can create subtle issues with re-rendering.
My advice would be to create a function to render the td element and prefix the rendering with
^{:key (str i j)} [:td (str "Row " i ", Col " j)]
The (str i j) will create a unique key for each td element. The other thing I find useful is to use into i.e.
(into [:tr]
(for [j (range 3)]
^{:key (str i j)} [:td ....])))
I've been developing my own app using reagent. It isn't great code and it still needs a lot of re-factoring, but I have done tables like this as well as paginated tables and a few other reagent components, such as tabs, sidebar menus etc. It can be found at my github arcis project It should give you some ideas if nothing else
There is also some good documentation regarding reagent and how it does rendering and some of the subtle 'gotchas' at re-frame wiki
I am trying to 'purify' some of my Clojure functions. I would like to get to a point where all my side-effecting code is explicitly declared in one function. It's easy to get some data at the start and to write it to a db at the end and just have a pure function transforming in between. However, the usual situation is that the transformation function requires another DB read somewhere in the middle of the logic:
(defn transform-users
[users]
(let [ids (map :id users)
profiles (db/read :profiles ids)]
(profiles->something profiles)))
(->> (db/read :users)
(transform-users)
(db/write :something)
Obviously this is a very simple example but the point is, how do I get the side-effecting db/read function out of there, how can I make transform-users pure (and as a benefit, easily testable)?
One thing you could do here would be a dependency-injection-like approach of supplying the (potentially) side-effectful function as an optional parameter, e.g.:
(defn transform-users
[users & {:keys [ids->profiles]
:or {ids->profiles #(db/read :profiles %)}]
(let [ids (map :id users)
profiles (ids->profiles ids)]
(profiles->something profiles)))
This should be easily testable since you can mock the injected functions without a lot of effort. And as a bonus, by supplying the default value, you're documenting what you're expecting and making the function convenient to call.
Why couple the reading of the profiles with transforming profiles?
(->> (db/read :users)
(map :id)
(db/read :profiles)
(profile->something)
(db/write :something)
(This also exposes the fact that you are doing two round trips to the db. Where is db/read :user-profiles ?)
(->> (db/read :user-profiles)
(profile->something)
(db/write :something)
or perhaps:
(->> (read-profiles-from-users)
(profile->something)
(db/write :something)
I am new to Clojure and am just trying to build some sample apps to get used to the syntax. I noticed the following order dependency behaviour.
I created a project called timex to calculate the time in weeks between two dates. I am using the clj-time functions for the date difference calculations.
If my core.clj looks as follows:
(ns timex.core
(:gen-class))
(defn -main
"Calculate weeks between dates."
[& args]
dp
)
(require '[clj-time.core :as t])
(def d2 (t/date-time 1989 01 07))
(def dw (t/in-weeks (t/interval d2 (t/now))))
(def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))
**
If I run lein repl I get the following error:
#CompilerException java.lang.RuntimeException: Unable to resolve symbol: dp in this context, compiling:(timex/core.clj:4:1)
But if I re-order the lines in the file and put the def's and the require statement before the main as such
(ns timex.core
(:gen-class))
(require '[clj-time.core :as t])
(def d2 (t/date-time 1989 01 07))
(def dw (t/in-weeks (t/interval d2 (t/now))))
(def dp (str "The number of weeks between Jan 7, 1989 and now is " dw "!"))
(defn -main
"Calculate weeks between dates."
[& args]
dp
)
**
Then when I run lein repl and the invoke the (-main) function, I get:
timex.core=> (-main)
"The number of weeks between Jan 7, 1989 and now is 1341!"
Is this apparent order-dependency normal or am I doing something wrong? If the latter, then I would appreciate any advice or documentation I should review. Thanks.
The unit of compilation in Clojure is the s-expression as opposed to a whole file like many other languages. When you load a file that file file is evaluated from top to bottom in a single pass. vars (what is created by calls to def) must be created above where they are used, or you can use declare if you need mutual recursion though this is rare.
It's worth spending some time getting used to the difference between compiling a file in the traditional sense, and loading a file in the lisp sense because it is fundamental to the macro system and many other aspects of the language. When you require a file from a namespace, or call load-file from the repl the clojure compiler is invoked and repeatedly reads, macro-expands, then evaluates each from in the file starting at the top. The first line tels it what namespace to define things in which is why the ns expression comes first. Then further forms define things in that namespace. If you then load the file again it does nothing more than read the file from the top all over again. It does not clear the namespace or any other magic, so if you evaluate the file, then change the order and evaluate it again it can continue to work because the required functions are already defined in the namespace (as stored in memeory) when the second pass is run. When getting used to this it helps to run lein check often to make sure things are well ordered.
PS: the vast majority of the time the call to require goes in the ns form at the top of the file.
Having a collection of files/directories I'd like to create a collection of all leaves files.
I'd like the resulting collection extend the clojure.core.protocols/CollReduce protocol.
Do I need to extend the protocol or are there helper functions for that?
In other words. Do reducers only help in parallel reduction or can I use them to effectively generate reducible collections in parallel as well?
To illustrate the problem let me show the implementation which could work, granted that the file hierarchy is no deeper than two levels (e.g our collection can contain files and directories, but the directories can contain only files)
(ns user
[import [java.io File]])
(defn expand [reduction-function]
(fn [result input]
(if (.isFile input)
(reduction-function result input)
; if not a file we assume it's a directory
(reduce reduction-function result (.listFiles input)))))
(defn process [xfn c]
(lazy-seq (when-let [s (seq c)]
(concat ((xfn #(concat %1 (list %2))) '() (first s))
(process xfn (rest s))))))
(def f (File. "C:\\WORK"))
(process expand [f]) ; => produces list of files
Now, it would be nice to have the expand defined in recursion-like style (or rather as a cascade of transformations), so it works for all levels, but executed in parallel fashion. As with reducers we can define early termination in reduction, I'd like to have ability to define generation (collection expansion) which stops when certain criteria is met (reaching file in directory hierarchy tree, as in file example)
I am working through the first edition of this book and while I enjoy it, some of the examples given seem out-dated. I would give up and find another book to learn from, but I am really interested in what the author is talking about and want to make the examples work for myself, so I am trying to update them as I go along.
The following code is a map/reduce approach to analyzing text that depends on clojure.contrib. I have tried changing the .split function to re-seq with #"\w+", used line-seq instead of read-lines, and changed the .toLowerCase to string/lower-case. I tried to follow my problems to the source code and read the docs thoroughly to learn that the read-lines function closes after you consume the entire sequence and that line-seq returns a lazy sequence of strings, implementing java.io.BufferedReader. The most helpful thing for my problem was post about how to read files after clojure 1.3. Even still, I can't get it to work.
So here's my question: What dependencies and/or functions do I need to change in the following code to make it contemporary, reliable, idiomatic Clojure?
First namespace:
(ns chapter-data.word-count-1
(:use clojure.contrib.io
clojure.contrib.seq-utils))
(defn parse-line [line]
(let [tokens (.split (.toLowerCase line) " ")]
(map #(vector % 1) tokens)))
(defn combine [mapped]
(->> (apply concat mapped)
(group-by first)
(map (fn [[k v]]
{k (map second v)}))
(apply merge-with conj)))
(defn map-reduce [mapper reducer args-seq]
(->> (map mapper args-seq)
(combine)
(reducer)))
(defn sum [[k v]]
{k (apply + v)})
(defn reduce-parsed-lines [collected-values]
(apply merge (map sum collected-values)))
(defn word-frequency [filename]
(map-reduce parse-line reduce-parsed-lines (read-lines filename)))
Second namespace:
(ns chapter-data.average-line-length
(:use rabbit-x.data-anal
clojure.contrib.io))
(def IGNORE "_")
(defn parse-line [line]
(let [tokens (.split (.toLowerCase line) " ")]
[[IGNORE (count tokens)]]))
(defn average [numbers]
(/ (apply + numbers)
(count numbers)))
(defn reducer [combined]
(average (val (first combined))))
(defn average-line-length [filename]
(map-reduce parse-line reducer (read-lines filename)))
But when I compile and run it in light table I get a bevy of errors:
1) In the word-count-1 namespace I get this when I try to reload the ns function after editing:
java.lang.IllegalStateException: spit already refers to: #'clojure.contrib.io/spit in namespace: chapter-data.word-count-1
2) In the average-line-length namespace I get similar name collision errors under the same circumstances:
clojure.lang.Compiler$CompilerException: java.lang.IllegalStateException: parse-line already refers to: #'chapter-data.word-count-1/parse-line in namespace: chapter-data.average-line-length, compiling:(/Users/.../average-line-length.clj:7:1)
3) Oddly, when I quit and restart light table, copy and paste the code directly into the files (replacing what's there) and call instances of their top level functions the word-count-1 namespace runs fine, giving me the number of occurrences of certain words in the test.txt file but the average-line-length name-space gives me this:
"Warning: *default-encoding* not declared dynamic and thus is not dynamically rebindable, but its name suggests otherwise. Please either indicate ^:dynamic *default-encoding* or change the name. (clojure/contrib/io.clj:73)...
4) At this point when I call the word-frequency functions of the first namespace it returns nil instead of the number of word occurrences and when I call the average-line-length function of the second namespace it returns
java.lang.NullPointerException: null
core.clj:1502 clojure.core/val
As far as I can tell, clojure.contrib.io and clojure.contrib.seq-utils are no longer updated, and in fact they may be conflicting with clojure.core functions like spit. I would recommend taking out those dependencies and seeing if you can do this using only core functions. spit should just work -- the error that you're getting is caused by useing clojure.contrib.io, which contains its own spit function, which looks to be roughly equivalent; perhaps the current version in clojure.core is a "new and improved" version of clojure.contrib.io/spit.
Your problem with the parse-line function looks to be caused by the fact that you've defined two functions with the same name, in two different namespaces. The namespaces don't depend on one another, but you can still run into a conflict if you load both namespaces in a REPL. If you only need to use one at a time, try using one of them, and then when you want to use the other one, make sure you do a (remove-ns name-of-first-ns) first to free up the vars so there is no conflict. Alternatively, you could make parse-line a private function in each namespace, by changing (defn parse-line ... to (defn- parse-line ....
EDIT: If you still need any functions that were in clojure.contrib.io or clojure.contrib.seq-utils that aren't available in core or elsewhere, you can always copy the source over into your namespace. See clojure.contrib.io and clojure.contrib.seq-utils on github.