Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Gorilla To Markdown
(ns gorilla-to-markdown.core
(:require [clojure.string :as str]
[cheshire.core :as json]))
(defn- process-output-json
"Builds the HTML from the output JSON.
Assumes the JSON has already been parsed, and that j is a map."
[j]
(case (:type j)
"html" (:content j)
"list-like" (str (:open j)
(str/join (:separator j)
(map #(process-output-json %) (:items j)))
(:close j))))
(defn- process-code-cell
"Formats a code cell in Github flavored Markdown.
c is a seq of strings containing the code in the cell."
[c]
(str "```clojure\n"
(str/join "\n" c)
"\n```\n"))
(defn- process-markdown-cell
"Formats a markdown cell.
c is a sequence of strings containing markdown."
[c]
(->> c
;; Strip out leading comment characters.
(map #(str/replace % #"^;;; " ""))
;; Mash back into string.
(str/join "\n")
;; Add one last newline.
(#(str % "\n"))))
(defn- process-stdout-cell
"Formats a STDOUT cell.
c is a sequence of strings containing the STDOUT output in the notebook."
[c]
(->> c
;; Strip out leading comment characters.
(map #(str/replace % #"^;;; " ""))
;; Mash back into string.
(str/join "\n")
;; Add code fences.
((fn [s] (str "```\n"
s
"\n```\n")))))
(defn- process-output-cell
"Formats an output cell.
c is a sequence of strings containing the output to be formatted.
There should be only one string in the sequence."
[c]
(let [output (->> c
;; Strip out leading comment characters.
(map #(str/replace % #"^;;; " ""))
;; There should only be a single string.
first)]
(if (str/blank? output)
"\n"
(str (process-output-json (json/parse-string output true)) "\n"))))
(defn- process-cell
"Formats a cell.
cell is a 3-element sequence containing an open marker, contents, and close
marker."
[cell]
(case (first cell)
[";; @@"] (process-code-cell (second cell))
[";; **"] (process-markdown-cell (second cell))
[";; ->"] (process-stdout-cell (second cell))
[";; =>"] (process-output-cell (second cell))))
(defn gorilla-to-markdown
"Converts the notebook string nb into a Markdown string."
[nb]
(let [cell-splitter #"^;; (@@|\*\*|<-|->|<=|=>)"]
;; Split on lines.
(->> (str/split-lines nb)
;; Drop first comment about gorilla version.
rest
;; Split into partitions based on cell marker.
(partition-by (fn [s] (re-find cell-splitter s)))
;; Drop seqs with blank strings.
(remove (fn [s] (every? str/blank? s)))
;; Group into cells (open-contents-close).
;; This will break if there are blank cells in the
;; workbook (except at the end).
(partition 3)
;; Process each cell.
(map process-cell)
;; Mash back into a big string.
(str/join "\n"))))
(defn -main
"Converts the Gorilla REPL notebook to raw Markdown."
[& args]
(let [nb (slurp (first args)]
(spit "gorilla-nb.md" (gorilla-to-markdown nb))))
@timothyrenner

This comment has been minimized.

Copy link
Owner Author

commented Dec 6, 2015

process-cell seems to be a prime target for a multimethod.

@ksseono

This comment has been minimized.

Copy link

commented Aug 29, 2017

Hi Timothy, thank you so much for your work! 👍
I've opened a repository based on your work and I would appreciate you could let me know if you have any concerns regarding the license and so on. I'm considering to deploy the project as a leiningen plugin to convert all the REPL files to markdown scripts conveniently at once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.