Skip to content

Commit e90bfdc

Browse files
authored
basilisp.pprint/print-table function (#983)
Peeling away parts of #513
1 parent ddc65d6 commit e90bfdc

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
## [Unreleased]
88
### Added
99
* Added the `CollReduce` and `KVReduce` protocols in `basilisp.core.protocols` and implemented `reduce` in terms of those protocols (#927)
10+
* Added `basilisp.pprint/print-table` function (#983)
1011

1112
### Changed
1213
* Improved on the nREPL server exception messages by matching that of the REPL user friendly format (#968)

docs/differencesfromclojure.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ Basilisp includes ports of some of the standard libraries from Clojure which sho
223223
* :lpy:ns:`basilisp.io` is a port of ``clojure.java.io``
224224
* :lpy:ns:`basilisp.set` is a port of ``clojure.set``
225225
* :lpy:ns:`basilisp.shell` is a port of ``clojure.java.shell``
226+
* :lpy:ns:`basilisp.stacktrace` is a port of ``clojure.stacktrace``
226227
* :lpy:ns:`basilisp.string` is a port of ``clojure.string``
227228
* :lpy:ns:`basilisp.test` is a port of ``clojure.test``
228229
* :lpy:ns:`basilisp.walk` is a port of ``clojure.walk``

src/basilisp/lang/compiler/generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3049,7 +3049,7 @@ def _local_sym_to_py_ast(
30493049
assert node.op == NodeOp.LOCAL
30503050

30513051
sym_entry = ctx.symbol_table.find_symbol(sym.symbol(node.name))
3052-
assert sym_entry is not None
3052+
assert sym_entry is not None, f"Expected symbol {sym.symbol(node.name)}"
30533053

30543054
if node.local == LocalType.FIELD:
30553055
this_entry = ctx.symbol_table.find_symbol(ctx.current_this)

src/basilisp/pprint.lpy

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
(ns basilisp.pprint
2+
(:require [basilisp.string :as str]))
3+
4+
(defn print-table
5+
"Print a collection of maps as a table to the buffer currently bound to
6+
:lpy:var:`basilisp.core/*out*`.
7+
8+
If there is at least one element in ``rows``, a header row will be printed
9+
followed by a single divider row followed by a line for each element in ``rows``.
10+
11+
If no keys are given (as ``ks``), then use the keys returned from the first
12+
element in ``rows`` (as by ``(keys (first rows))``). Note that in this case,
13+
the order of headers in the resulting table is based on the order of keys
14+
returned by :lpy:fn:`basilisp.core/keys`."
15+
([rows]
16+
(when (seq rows)
17+
(print-table (keys (first rows)) rows)))
18+
([ks rows]
19+
(when (seq rows)
20+
(let [widths (persistent!
21+
(reduce (fn [counts row]
22+
(reduce (fn [counts [k col]]
23+
(if-let [cnt (get counts k)]
24+
(->> (max cnt (count (str col)))
25+
(assoc! counts k))
26+
counts))
27+
counts
28+
row))
29+
(->> ks
30+
(map (comp count str))
31+
(zipmap ks)
32+
transient)
33+
rows))]
34+
(letfn [(fmt-row [start end joiner elems]
35+
(as-> elems $
36+
(str/join joiner $)
37+
(str start $ end)))
38+
(row-str [row]
39+
(->> (map #(str/lpad (str (get row %)) (get widths %)) ks)
40+
(fmt-row "| " " |" " | ")))]
41+
(println (row-str (zipmap ks ks)))
42+
(->> (map #(apply str (repeat (get widths %) "-")) ks)
43+
(fmt-row "+-" "-+" "-+-")
44+
(println))
45+
(doseq [row rows]
46+
(println (row-str row))))))))

tests/basilisp/test_pprint.lpy

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
(ns tests.basilisp.test-pprint
2+
(:require
3+
[basilisp.pprint :as pprint]
4+
[basilisp.string :as str]
5+
[basilisp.test :refer [deftest are is testing]])
6+
(:import os textwrap))
7+
8+
(defn trim-newlines-and-dedent
9+
[s]
10+
(-> (textwrap/dedent s)
11+
(str/ltrim)
12+
(str/replace "\n" os/linesep)))
13+
14+
(deftest print-table-test
15+
(is (= "" (with-out-str (pprint/print-table []))))
16+
(is (= "" (with-out-str (pprint/print-table [:a :b :c] []))))
17+
18+
(is (= (trim-newlines-and-dedent
19+
"
20+
| :a |
21+
+--------+
22+
| 1 |
23+
| b |
24+
| :horse |
25+
")
26+
(with-out-str (pprint/print-table [{:a 1} {:a "b"} {:a :horse}]))))
27+
28+
(is (= (trim-newlines-and-dedent
29+
"
30+
| :a | :b | :c |
31+
+-----+----+--------------------+
32+
| 1 | 2 | 3 |
33+
| 7 | 5 | catdogbirdsquirrel |
34+
| 432 | f | |
35+
")
36+
(with-out-str
37+
(pprint/print-table [:a :b :c]
38+
[{:a 1 :b 2 :c 3}
39+
{:b 5 :a 7 :c "catdogbirdsquirrel"}
40+
{:a 432 :b "f"}]))))
41+
42+
(is (= (trim-newlines-and-dedent
43+
"
44+
| :a | :b | :c | :d |
45+
+-----+----+--------------------+----+
46+
| 1 | 2 | 3 | |
47+
| 7 | 5 | catdogbirdsquirrel | |
48+
| 432 | f | | |
49+
")
50+
(with-out-str
51+
(pprint/print-table [:a :b :c :d]
52+
[{:a 1 :b 2 :c 3}
53+
{:b 5 :a 7 :c "catdogbirdsquirrel"}
54+
{:a 432 :b "f"}])))))

0 commit comments

Comments
 (0)