Language extensions for clojurescript

Author: Chris Zheng  (z@caudate.me)
Library: v0.5.1
Date: 09 October 2014
Website: http://www.github.com/purnam/purnam
Generated By: MidjeDoc

1   Installation

2   Motivation

3   Quickstart

  3.1   Native Datastructures
  3.2   Native Functions
  3.3   Native Protocols
  3.4   DSL for Testing

4   purnam.native.functions

  4.1   init
  4.2   js-lookup
  4.3   js-equals
  4.4   js-assoc
  4.5   js-dissoc
  4.6   js-empty
  4.7   js-merge
  4.8   js-merge-nil
  4.9   js-copy
  4.10   js-deep-copy
  4.11   js-replace
  4.12   js-map
  4.13   js-concat
  4.14   js-mapcat
  4.15   js-arities

5   purnam.native

  5.1   init
  5.2   seq protocol
  5.3   transient protocol
  5.4   collection protocol

6   purnam.core

  6.1   init
  6.2   obj
  6.3   arr
  6.4   getter - ?
  6.5   setter - !
  6.6   call - ?>
  6.7   call on - !>
  6.8   this
  6.9   self
  6.10   def.n
  6.11   f.n
  6.12   do.n
  6.13   raw forms

7   purnam.test

  7.1   init
  7.2   describe
  7.3   async
  7.4   fact
  7.5   facts

8   Running Tests

9   Generating Documentation

10   End Notes


Language extensions for clojurescript

Author: Chris Zheng  (z@caudate.me)
Library: v0.5.1
Date: 09 October 2014
Website: http://www.github.com/purnam/purnam
Generated By: MidjeDoc

1    Installation

Add to project.clj dependencies:

[im.chit/purnam "0.5.1"]

Looking for documentation for purnam.angular? The library has been renamed and moved to a new home at http://purnam.github.io/gyr

2    Motivation

purnam is a clojurescript library designed to provide better clojurescript/javascript interop, testing and documentation tools to the programmer. Current projects requiring interface with external javascript libraries will greatly benefit from purnam language extensions. 'Pure' clojure/clojurescript libraries will also benefit with its unit-testing and documentation workflows. The library was written to solve a number of pain points that are experienced in clojurescript development:

Better JS Interop

The first pain point was having to deal with the clojurish (.dot syntax) for javascript interop as well as a lack of functionality when working with native js objects. This made it especially hard for working with any external js library. purnam offers:

In-Browser Testing

purnam.test was written to allow clojurescript tests to work with the karma test runner. There are various advantages to using the karma test runner over existing clojurescript solutions:

Furthermore, the javascript dot.notational.style to be used for better native integration. Since version 0.4, there is much better support for error reporting and the library can now be used on its own, outside of all other purnam libraries. Currently two flavors are supported describing clojurescript tests:

Integrated Documentation

The third pain point was the lack of documentation tools for clojurescript as well as clojure. purnam is compatible with midje-doc so that the integrated testing and documentation workflow can be also used in clojurescript.

3    Quickstart

The quickest way to start is to look at some sample projects:

3.1    Native Datastructures

obj, arr and def* in the purnam.core namespace allow nested objects and arrays to be constructed. The examples below show equivalent objects in javascript and clojurescript

e.3.1  -  js object

var user = {ids: [1, 2, 3], account: {username: 'user', password: 'pass'}}

e.3.2  -  cljs object - obj

(def user (obj :ids [1 2 3] :account {:username "user" :password "pass"}))

e.3.3  -  cljs object - def*

(def* user {:ids [1 2 3] :account {:username "user" :password "pass"}})

Arrays are constructed using arr. The two examples below show equivalent arrays in javascript and clojurescript:

e.3.4  -  js array

var kids = [{name: 'Sam' age: 3}, {name: 'Bob' age: 10}]

e.3.5  -  cljs array - arr

(def kids (arr {:name "Sam" :age 3} {:name "Bob" :age 10}))

e.3.6  -  cljs array - def*

(def* kids [{:name "Sam" :age 3} {:name "Bob" :age 10}])

3.2    Native Functions

def.n and f.n allow functions to be defined using the javascript dot-notation syntax. The following are examples of the square function defined in javascript and clojurescript.

e.3.7  -  js function

square = function(x) {return x.value * x.value}

e.3.8  -  cljs function - def.n

(def.n square [x]
  (obj :value (* x.value x.value)))

e.3.9  -  cljs function - f.n

(def square 
  (f.n [x]
    (obj :value (* x.value x.value))))

As a comparison, here is the same function in clojurescript without the macro helpers.

e.3.10  -  cljs function - defn

(defn square [x]
  (let [o (js-obj)
        v (aget x "value")]
    (aset o "value" (* v v))

3.3    Native Protocols

The purnam.native namespace provide for idiomatic clojure syntax to be used:

e.3.11  -  Idiomatic Clojure Protocols

(count (obj :a 1 :b 2 :c 3)) => 3

(get (obj :a 1 :b 2 :c 3) "a") => 1

(nth (arr :0 :1 :2 :3 :4) 3) => :3

The purnam.native.functions namespace also provide additional manipulation functions like js-merge, js-merge-nil and js-deep-copy. More examples can be seen in the api).

3.4    DSL for Testing

Choose between two styles of sytax for testing clojurescript code - jasmine style or midje style (in the purnam.test namespace). Or you can mix and match both of them together.

e.3.12  -  testing - jasmine style

(describe "Addition"
  (it "should add things"
    (is (+ 1 1) 2)
    (is (+ 1 2) 3)
    (is (+ 1 3) 4)
    (is-not (+ 1 4) 0)))

e.3.13  -  testing - midje style

(fact [[{:doc "Addition should add things"}]]
  (+ 1 1) => 2
  (+ 1 2) => 3
  (+ 1 3) => 4
  (+ 1 4) => #(not= 0 %))

Although there are currently more features available when using the jasmine style syntax, using midje style syntax also allow compilation of your test files into beautiful documentation using midje-doc. The current document has been generated in this way.

4    purnam.native.functions

Clojure protocols for javascript native objects and arrays.

4.1    init

To use this package, require purnam.native.functions in your namespace

(:require [purnam.native.functions :refer [js-lookup js-equals ....]])

Utility functions for javascript native objects and arrays.

4.2    js-lookup

js-lookup is like get for native javascript. It works with keywords and strings

(js-lookup (js* "{a:1, b:2}") "a")

=> 1
(js-lookup (js* "{a:1, b:2}") :b)

=> 2

4.3    js-equals

js-equals checks for equality on native objects. The clojurescript equality = does not check for equality on native objects

(= (js* "{a:1}") (js* "{a:1}"))

=> false?

js-equals fills this gap:

(js-equals (js* "{a:1}") (js* "{a:1}"))

=> true

js-equals will also check equality for nested native objects and arrays

(js-equals (js* "{a:[{b: [{c: 1}]}]}")
           (js* "{a:[{b: [{c: 1}]}]}"))

=> true

4.4    js-assoc

js-assoc is the native mutable version of assoc, it works with both keyword and string keys

(def o (js* "{a:1}"))
(js-assoc o "b" 2)  ;; string

=> (js* "{a:1,b:2}")
(js-assoc o :c 3 "d" 4)  ;; keyword and string 

=> (js* "{a:1,b:2,c:3,d:4}")

js-assoc also works with native arrays and allows number keys

(def o (array 0))
(js-assoc o "1" 1)   ;; string

=> (array 0 1)
(js-assoc o 2 2)     ;; number

=> (array 0 1 2)

4.5    js-dissoc

js-dissoc is the native mutable version of dissoc, it works with both keyword and string keys

(def o (js* "{a:1,b:2,c:3,d:4}"))
(js-dissoc o "a" :b :c)

=> (js* "{d:4}")

4.6    js-empty

js-empty is the native mutable version of empty

(def o (js* "{a:1,b:2,c:3,d:4}"))
(js-empty o)

=> (js-obj)

4.7    js-merge

js-merge is the native mutable version of merge. It will only mutate the first object argument.

(def o1 (js* "{a:1}"))

(def o2 (js* "{b:2}"))
(js-merge o1 o2)

=> (js* "{a:1,b:2}")

If the keys are the same, it will overwrite

(def o3 (js* "{b:3}"))

(js-merge o1 o3)

=> (js* "{a:1,b:3}")

4.8    js-merge-nil

js-merge-nil is like js-merge but it will only merge the keys that are not defined

(def o1 (js* "{a:1}"))

(def o2 (js* "{a:2,b:2}"))
(js-merge-nil o1 o2)

=> (js* "{a:1,b:2}")

4.9    js-copy

js-copy creates another object with the same key/values

(def o1 (js* "{a:1,b:2}"))

(def o2 (js-copy o1))
(js-equals o1 o2)

=> true
(= o1 o2)

=> false

4.10    js-deep-copy

js-deep-copy copys everything about an object, including circular references

(def o1 (js* "function(){var a = {val:1}; a.ref = a; return a;}()"))

(def o2 (js-deep-copy o1))

Notice that we can walk o2.

(aget o2 "ref" "ref" "val")

=> 1

But o1 and o2 are not equal

(= o1 o2)

=> false?

And neither are the references

(= (aget o1 "ref") (aget o2 "ref"))

=> false?

4.11    js-replace

js-replace is like js-copy, but it uses keeps the pointer to the first object argument

(def o1 (js* "{a:1}"))

(js-replace o1 (js* "{b:2}"))


=> (js* "{b:2}")

4.12    js-map

A multi argument version of map, like clojure's map but returns a native arrays

(js-map + (js* "[1,2,3,4]") 
          (js* "[5,6,7,8]") 
          [9 10 11 12])

=> (js* "[15,18,21,24]")

4.13    js-concat

Concats multiple arrays into a single native arrays

(js-concat (js* "[1,2,3,4]") 
         (js* "[5,6,7,8]") 
         [9 10 11 12])

=> (js* "[1,2,3,4,5,6,7,8,9,10,11,12]")

4.14    js-mapcat

Like clojure's mapcat but returns a native arrays

(js-mapcat list (js* "[1,2,3,4]") 
                (js* "[5,6,7,8]") 
                [9 10 11 12])

=> (js* "[1,5,9,2,6,10,3,7,11,4,8,12]")

4.15    js-arities

Returns all arities of a function. Works with f.n and def.n

(js-arities (fn [x] x))

=> [1]

5    purnam.native

Clojure protocols for javascript native objects and arrays.

5.1    init

To use this package, require purnam.native in your namespace

(:require [purnam.native])

5.2    seq protocol

The seq can now be used on native js arrays and objects.

(seq (js* "[1, 2, 3, 4]"))

=> '(1 2 3 4)
(seq (js* "{a:1, b:2}"))

=> '(["a" 1] ["b" 2])

As well as all the built-in functionality that come with it. Although the datastructure then becomes a clojurescript lazyseq.

(map #(* 2 %) (js* "[1, 2, 3, 4]"))

=> '(2 4 6 8)
(take 2 (js* "[1, 2, 3, 4]"))

=> '(1 2)
(count (js* "[1, 2, 3, 4]"))

=> 4
(get (js* "[1, 2, 3, 4]") "1")

=> 2
(get-in (js* "{a:{b:{c:1}}}") (js* "['a', 'b', 'c']"))

=> 1

5.3    transient protocol

Transient protocol allow native js objects arrays to be manipulated using assoc!, dissoc! and persistent!

(let [o (js-obj)]
  (assoc! o :a 1)

=> (js* "{a:1}")
(let [o (js* "{a:1}")]
  (dissoc! o :a)

=> (js-obj)
(persistent! (js* "{a:1}"))

=> {:a 1}

5.4    collection protocol

Extension of clojure collection protocols allow native js objects arrays to use conj, assoc and dissoc methods.

(def o (js-obj))
  (def o1 (conj o [:a 1]))
  o => (js-obj)
  o1 => (js* "{a:1}")

It works with both arrays and objects

(conj (js* "[1]") 2 3)

=> (js* "[1,2,3]")
(conj (js* "{a:1}") [:b 2] [:c 3])

=> (js* "{a:1,b:2,c:3}")
(assoc (js* "{a:1}") :b 2 :c 3)

=> (js* "{a:1,b:2,c:3}")
(dissoc (js* "{a:1}") :a)

=> (js-obj)

6    purnam.core

(set-safe-aget true)

6.1    init

purnam.core extensions are packaged as macros. They are accessible via :use-macro declaration.

(:use-macros [purnam.core :only [? ?> ! !> f.n def.n do.n
                                obj arr def* do*n def*n f*n]])

6.2    obj

Raw js objects are constructed in clojurescript with obj:

(obj "key1" "val1" "key2" "val2")

=> (js* "{key1: 'val1', key2: 'val2'}")

Keywords can be used instead of strings for improved legibility. The previous example can also be written as:

(obj :key1 "val1" :key2 "val2")

=> (js* "{key1: 'val1', key2: 'val2'}")

Symbol are evalutated. This will produce an equivalent object to the previous examples:

(let [s1 "key1"
      s2 "key2"]
  (obj s1 "val1" s2 "val2"))

=> (js* "{key1: 'val1', key2: 'val2'}")

Note that the symbols have to represent strings to get the same output as previous. The following WILL NOT construct the equivalent object as before:

(let [s1 :key1
      s2 :key2]
  (obj s1 "val1" s2 "val2"))

=> #(not (= % (js* "{key1: 'val1', key2: 'val2'}")))

The obj form can be used to set up nested js objects and arrays primitives. Using [] with the form will create a new js array, {} will create a new js object.

(obj :data [{:id 1 :name "one"}
            {:id 2 :name "two"}])

=> (js* "{data: [{id:1,name:'one'},

The nesting notation alleviates the use of the clj->js transform for constructing large javascipt variables. In this way, deeply nested javascript object structures can be created in clojurescript in the same way clojure maps and arrays are created.

(obj :name "l1" :data [1 2 3]
     :next {:name "l2" :data [4 5 6]
            :next {:name "l3" :data [7 8 9]}})

=> (js* "{name: 'l1',
          data: [1,2,3],
          next: {name: 'l2',
                 data: [4,5,6],
                 next: {name: 'l3',
                        data: [7,8,9]}}}")

6.3    arr

arr constructs a javascript array primitive, the same way as array

(arr 1 2 3 4 5)

=> (js* "[1,2,3,4,5]")

arr supports nesting of native objects and arrays much like obj

(arr {:data [1 2 3 4 5]}
     {:data [6 7 8 9 10]})

=> (js* "[{data: [1,2,3,4,5]},
            {data: [6,7,8,9,10]}]")

6.4    getter - ?

? provides javascript-like dot notation access for objects

(let [o (obj :a 1 :b 2 :c 3)]
  (+ (? o.a) (? o.b) (? o.c)))

=> 6

Pipe notation object.|key| provides symbol lookup

(let [o (obj :a 1 :b 2 :c 3)
      k "a"]
  (- (? o.b) (? o.|k|)))

=> 1

? also works on javascript arrays

(let [o (arr [1 2 3] [4 5 6] [7 8 9])]
   (- (? o.2.2) (? o.0.0)))

=> 8

If any of the keys are missing, ? will not throw an object undefined exception but will return nil.

(let [o (obj)]
  (? o.any.nested.syntax))

=> nil?

6.5    setter - !

The ! form provides setting using dot notation:

(let [o (obj)]
  (! o.a 6)  
  (? o.a))

=> 6

Pipe notation object.|key| also works

(let [o (obj)
      k "a"]
  (! o.|k| 6)
  (? o.a))

=> 6

If there is no value or the value is nil, ! will delete the key from the object:

(let [o (obj :a 1)]
  (! o.a)

=> (obj)

If the hierachy of nested objects does not exist, ! will create it

(let [o (obj)]
  (! o.a.b.c 10)
  (? o.a.b.c))

=> 10

If one of the keys in the object accessor is not an object, ! WILL NOT create nested structures

(let [o (obj :a 1)]
  (! o.a.b.c 10)
  [(? o.a.b.c) (? o.a)])

=> [nil 1]

6.6    call - ?>

?> allows function calls with dot-notation syntax.

(let [o1 (obj :a 1)
      o2 (obj :a 3)]
  (?> + o1.a o2.a))

=> 4

Inner forms within ?> are automatically interpreted using dot-notation. There is no need to write ?.

(?> .map (arr {:a 1} {:a 2} {:a 3})
         (fn [x] (inc x.a))) ;; no need to write (inc (? x.a))

=> (arr 2 3 4)

6.7    call on - !>

The !> form allows for writing dot-notation function calls.

(let [a (arr)]
  (!> a.push 1)
  (!> a.push 2)

=> (arr 1 2)

We can also use pipe notation to dynamically invoke our function.

(let [a (arr)
      k "push"]
  (!> a.|k| 1)
  (!> a.|k| 2)

=> (arr 1 2)

6.8    this

The rational for adding this back into our language is that when a piece of a program really needs to work with existing javascript libraries (and it usually does), then clojurescript should give allow the flexibility to do that without adding additional noise to the code. Use with care!

(let [o1 (obj :a 10 
              :func (fn [] this.a))
      o2 (obj :a 20
              :func o1.func)]
  [(!> o1.func) (!> o2.func)])

=> [10 20]

When this is nested, it works within the scope of the nested object

(let [o (obj :a 10
             :func (fn [] this.a)
             :b {:a 20
                 :func (fn [] this.a)})]
  [(!> o.func) (!> o.b.func)])

=> [10 20]

6.9    self

A new existential construct has been added, it be use only within the obj form. It is used to refer to the object itself and does not change contexts the way this does. It provides a somewhat safer self reference which does not change when the context is changed.

self is similar to this. Note that the two keywords both refer to the object itself.

(let [o (obj :a 1
             :thisfn (fn [] this.a)
             :selffn (fn [] self.a))]
    [(!> o.thisfn) (!> o.selffn)])

=> [1 1]

We can quickly see the difference by creating another object. o1 has been initiated with functions defined o. If we invoke the o1 functions, it can be seen that the context for o.thisfn has changed and so it returns o1.a (2). While o1.selffn returns the value o.a (1)

(let [o (obj :a 1
             :thisfn (fn [] this.a)
             :selffn (fn [] self.a))
      o1 (obj :a 2
             :thisfn o.thisfn
             :selffn o.selffn)]
  [(!> o1.thisfn) (!> o1.selffn)])

=> [2 1]

A useful property of obj and self can be seen in the next example. Even though both have the same structure, self in a1 refers to a1 whereas self in a2 refers to a2.b. This was due to the fact that in a1, a hashmap was used to construct :b as opposed to the obj form in a2.

(let [a1 (obj :a 1
              :b {:a 2         ;; Note {} is used
                  :func (fn [] self.a)})
      a2 (obj :a 1
              :b (obj :a 2   ;; Note obj is used
                      :func (fn [] self.a)))]
    [(!> a1.b.func) (!> a2.b.func)])

=> [1 2]

6.10    def.n

def.n allow construction of functions with the javascript dot-notation. Within the forms, there is no need to add ?, ?> and !> forms:

? getters are automatic

(? a.b) => a.b

?> call syntax is automatically applied

(?> + a.b c.d) => (+ a.b c.d)

!> syntax is also automatically applied:

(!> a.b c.d) => (a.b c.d)

The defn function:

(defn dostuff0 [a b c]
  (!> b.func 10 10)
  (?> + a.val b.val)
  (inc (? c.val)))

Can be written more succinctly using def.n:

(def.n dostuff1 [a b c]
  (b.func 10 10)
  (+ a.val b.val)
  (inc c.val))

6.11    f.n

f.n is the equivalent dot-notation counterpart for fn

(def dostuff2 
  (f.n [a b c]
    (b.func 10 10)
    (+ a.val b.val)
    (inc c.val)))

6.12    do.n

The do.n block is like do but allows dot-notation syntax:

  (let [o (obj)]
    (! o.val.a 1)
    (! o.val.b 2)
    (+ o.val.a o.val.b)))

=> 3

6.13    raw forms

For those that want to write clojurescript with {} interpreted as js objects and [] interpreted as arrays, then the raw js forms are very handy. def*, def*n, f*n and do*n allow this. The same function raw-fn can be defined the following four ways:

(def raw-fn (f*n [o] (! o.val [1 2 3 4 5])))

(def* raw-fn (fn [o] (! o.val [1 2 3 4 5])))

(def*n raw-fn [o] (! o.val [1 2 3 4 5]))

(do*n (def raw-fn (fn [o] (! o.val [1 2 3 4 5]) o)))


(raw-fn (obj))

=> (obj :val [1 2 3 4 5])

Within the raw js form, self refers to the top level object.

(def* o (obj :a 10
             :b {:a 20
                 :func (fn [] self.a)}))

(!> o.b.func)

=> 10

The raw js forms will only recognise the cljs.core vector binding constructs: let, loop, for, doseq, if-let and when-let. Any custom macros within a raw form will run into problems.

(set-safe-aget false)

7    purnam.test

7.1    init

All tests require the following within the namespace declaration.

(:require [purnam.test])
(:use-macros [purnam.test :only [describe it is is-not]])

PLEASE NOTE: (:require [purnam.test]) must be placed inside your namespace. This configures jasmine with the correct checker so that tests can be run. There will be random errors outputted without it when karma is run.

7.2    describe

describe is the top-level form for testing. Its usage is in combination with the setup clause it and the checkers is and is-not. :globals sets up bindings for variables that can be manipulated but cannot be rebounded. :vars are allowed to be rebounded.

e.7.1  -  describe purnam example

   {:doc "an example test description"
    :globals [ka "a"
              kb "b"]
    :vars [o (js* "{a:1,b:2,c:3}")
           y (js* "[[1, 2, 3],
                    [4, 5, 6],
                    [7, 8, 9]]")]}

   (it "dot notation for native objects"
       (is 1 o.a)
       (is 6 (+ o.a o.b o.c)))

   (it "support for both native and cljs comparisons"
       (is [1 2 3 4] [1 2 3 4]))

   (it "support for function comparison"
       (is 2 even?)
       (is-not 2 odd?)
       (is 3 (comp not even?)))

   (it "globals"
       (is o.|ka| 1)
       (is 3 (+ o.|ka| o.|kb|))))

7.3    async

An example of testing async functionality can be seen

e.7.2  -  async macros

(describe {:doc  "Testing Async macros"
           :vars [flag (atom false) 
                  value (atom 0)]}
  (it "Should support async execution of test preparation and exepectations"
    (runs (js/setTimeout (fn [] (reset! flag true)) 500))
    (waits-for "Flag should be true" 750 (swap! value inc) @flag)
    (runs (is @flag true)
          (is (> @value 0) true))))

7.4    fact

fact is the default form for testing. It can currently only use the => checker and is a much lighter version of midje. However, it is enough for all but the most common cases. The describe example is rewritten below:

e.7.3  -  fact form example

(fact [[{:doc "an example test description"
         :globals [ka "a"
                   kb "b"]
         :vars [o (js* "{a:1,b:2,c:3}")
                y (js* "[[1, 2, 3],
                         [4, 5, 6],
                         [7, 8, 9]]")]}]]

 "dot notation for native objects"
 o.a => 1
 (+ o.a o.b o.c) => 6

 "support for both native and cljs comparisons"
 o => (js* "{a:1,b:2,c:3}")
 [1 2 3 4] => [1 2 3 4]
 "support for function comparison"
  2 => even?
  3 => (comp not even?)
  o.|ka| => 1
  (+ o.|ka| o.|kb|) => 3
  "vars are allowed to be rebound"              
  (- y.2.2 y.0.0) => 8

7.5    facts

facts and fact are interchangeable. The difference is how they are rendered in a document. See lein-midje-doc for more details.

e.7.4  -  facts form example

(facts [[{:doc "Basic Hashmaps"
          :globals [o {:a 1 :b 2 :c 3}]}]]
  (o :a)       => 1 
  (o :a)       => #(not= 0 %)
  (get o :b)   => 2
  (:c o)       => 3
  (select-keys o [:a :b]) => {:a 1 :b 2})

8    Running Tests

To run tests, the karma test library is required. It can be installed using npm. There are two files that needs to be updated:

In project.clj, add your clojurescript builds. Usually the test code is built to a seperate file than the application code. In the following case, the tests are compiled to target/example-test.js.

e.8.1  -  project.clj - cljsbuild

:cljsbuild {:builds [{:source-paths ["src"]
                      :compiler {:output-to "target/example.js"
                                 :optimizations :whitespace
                                 :pretty-print true}}
                     {:source-paths ["src", "test/cljs"]
                      :compiler {:output-to "target/example-test.js"
                                 :optimizations :whitespace
                                 :pretty-print true}}]}

A karma.conf.js file is required at the root level of your project. It is created by running karma init in the root project directory and following a bunch of instructions:


Make sure that autoWatch is set to true and that the the compiled output from cljsbuild is included as one of the files.

e.8.2  -  karma.conf.js

  files: [
  autoWatch: true,

Run in one window: lein cljsbuild auto.

Run in another window: karma start.

Note that you will have to restart karma if the *.js file was not found before the test runner starts. The following video shows the entire process in detail:


9    Generating Documentation

If the midje flavor testing is used, MidjeDoc can be used to auto generate documentation from test cases. The following should be added to project.clj:

e.9.1  -  project.clj - documentation

:profiles {:dev {:plugins [...
                           [lein-midje-doc "0.0.18"]
                           ... ]}}
:documentation {:files {"index"
                        {:input "test/cljs/midje_doc/example_guide.cljs"
                         :title "example"
                         :sub-title "this is an example"
                         :author "Your Name"
                         :email  "example@email.com"
                         :tracking "UA-31320512-2"}}}

Running in a third window: lein midje-doc will watch files for changes and generate a pretty viewable output to index.html on any change. A demonstration of how this works can be seen here:


10    End Notes

For any feedback, requests and comments, please feel free to lodge an issue on github or contact me directly.