Clojure table layout
Clojure
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/doric
test/doric/test
.gitignore
README.md
project.clj

README.md

Doric

Doric is a library for rendering pretty emacs-style tables from Clojure data. Data is passed into Doric as nested collections, and comes out as a string suitable for printing.

Add this to your project.clj :dependencies list:

[doric "0.9.0"]

Usage

In most cases, you'll just want to use/require the table function.

> (use '[doric.core :only [table]])
nil

But you can access other things if you'd like, for instance if you want to use the other formats.

> (use '[doric.core :only [table csv html org raw]])
nil

Rows are maps, columns are entries in the maps. Column titles are driven from the keys, by default, :like-this becomes Like This. Since we can't know the original order of the keys in your maps, you'll probably want to provide a columns argument that specifies the order of your keys (more on this later).

> (println (table [:a :b] [{:a 1 :b 2}]))
|---+---|
| A | B |
|---+---|
| 1 | 2 |
|---+---|
nil

The default formatting is emacs org-mode tables, which are awesome.

> (println (table [:a :b :c] [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
|---+---+---|
| A | B | C |
|---+---+---|
| 1 | 2 | 3 |
| 4 | 5 | 6 |
|---+---+---|
nil

But you can also have raw, csv, and html tables pretty easily:

> (println (table {:format raw} [:a :b :c] [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
A B C
1 2 3
4 5 6
nil

> (println (table {:format csv} [:a :b :c] [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
A,B,C
1,2,3
4,5,6
nil

> (println (table {:format html} [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
;; omg lots of <tr>s and <td>s here

You can also use a custom table format by specifying a namespace that contains the functions th, td, and render.

> (println (table {:format 'my.sweet.ns} [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
;; the sky's the limit, buddy

Individual columns are optional, each column automatically sizes itself to hold the data.

> (println (table [:lang :strength :safety]
                  [{:lang "Clojure" :strength "strong" :safety "safe"}
                   {:lang "Java" :strength "strong" :safety "safe"}
                   {:lang "JavaScript" :strength "weak"}]))
|------------+----------+--------|
|    Lang    | Strength | Safety |
|------------+----------+--------|
| Clojure    | strong   | safe   |
| Java       | strong   | safe   |
| JavaScript | weak     |        |
|------------+----------+--------|
nil

Or, you can substitute (per column) a map for a keyword, and change lots of things about the way the data is displayed.

> (println (table [{:name :lang :title "Language" :align :center :width 12}
                   {:name :safety :width 12 :align :left}
                   {:name :strength :width 12 :align :left}]
                  [{:lang "Clojure" :strength "strong" :safety "safe"}
                   {:lang "Java" :strength "strong" :safety "safe"}
                   {:lang "JavaScript" :strength "weak"}]))
|--------------+--------------+--------------|
|   Language   | Safety       | Strength     |
|--------------+--------------+--------------|
|    Clojure   | safe         | strong       |
|     Java     | safe         | strong       |
|  JavaScript  |              | weak         |
|--------------+--------------+--------------|
nil

Which probably seems like a lot of syntax, but consider that in actual use it would probably look more like this, which isn't nearly as bad:

> (println (table [{:name :lang :title "Language" :align :center :width 12}
                   {:name :safety :width 12 :align :left}
                   {:name :strength :width 12 :align :left}]
                  (select-languages-from-db)))
;; assuming select-languages-from-db is some useful function
|--------------+--------------+--------------|
|   Language   | Safety       | Strength     |
|--------------+--------------+--------------|
|    Clojure   | safe         | strong       |
|     Java     | safe         | strong       |
|  JavaScript  |              | weak         |
|--------------+--------------+--------------|
nil

Each column can also take a format function to alter the way the cells are displayed. For example, there's an included bar function for creating text bar charts:

> (use '[doric.core :only [bar]])
nil
> (println (table {:format raw} [:a :b {:name :c :format bar}]
                                [{:a 1 :b 2 :c 3}{:a 4 :b 5 :c 6}]))
A B    C  
1 2 ###   
4 5 ######
nil

Column level options include:

  • :align - :left, :right, :center, defaults to :left
  • :title - a string, defaults to your column name, title-cased
  • :title-align - like align, and defaults to the same as :align
  • :format - a function to call on the values in the column, pre-output
  • :when - a boolean, allows you to turn columns on and off
  • :width - how wide to make the column, defaults to wide enough
  • :ellipsis - a boolean, whether or not to ... truncated values, defaults to false

License

Copyright (C) 2014 Joe Gallo and Dan Larkin

Distributed under the Eclipse Public License, the same as Clojure.