Alternate syntax for Clojure, similar to what Pollen brings to Racket.
Git coords:
{fr.jeremyschoffen/prose-alpha {:git/url "https://github.com/JeremS/prose.git", :sha "56f85b5fbd711efe6f0f1fc8ef02beb24159cb0e"}}
The main idea is to provide a tool that allows the creation of textual documents in which clojure can be embedded. The way Prose goes about it is by flipping the relationship between palin text and code. In a clojure file, text is assumed to be code except in special case like strings and comments. In prose, text is assumed to be just plain text except in special cases i.e. clojure code.
One of the main use of Prose is to use it as a text processor when wanting to generate different kinds of text documents. The examples following will describe Prose from this angle.
Prose provides a reader similar to what we can find in Pollen. Text is either plain text or a special construct.
All special constructs begin with the character ◊
(lozenge).
The text:
We can call ◊(str "code") in text
reads as:
["We can call " (str "code") " in text"]
The text:
We can use symbols ◊|some-symbol
reads as:
["We can use symbols " some-symbol]
The text:
There is a tag function syntax looking like:
◊div[{:class "grid"}]{ some content}
◊div{ some ◊em{content}}
or even:
◊str{text}
reads as:
["There is a tag function syntax looking like:\n" (div {:class "grid"} " some content") "\n" (div " some " (em "content")) "\n\nor even:\n" (str "text")]
The text:
The ◊"◊" character.
reads as:
["The " "◊" " character."]
Prose provides some helpers in defining html tag. These functions work as follow:
(div "content")
;=> {:tag :div, :content ["content"], :type :tag}
(div {} "content")
;=> {:tag :div, :attrs {}, :content ["content"], :type :tag}
(div (div) (div) (div))
;=> {:tag :div, :content [{:tag :div, :type :tag} {:tag :div, :type :tag} {:tag :div, :type :tag}], :type :tag}
With this api we can create documents such as:
◊(require '[fr.jeremyschoffen.prose.alpha.out.html.tags :refer [div ul li]])
◊div{
some text
◊ul {
◊li {1}
◊li {2}
}
}
This document would result in the following html:
<div>
some text
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
To do so we use Prose's apis this way:
(ns fr.jeremyschoffen.prose.alpha.docs.pages.readme.example-evaluation
(:require
[fr.jeremyschoffen.prose.alpha.document.sci :as doc]
[fr.jeremyschoffen.prose.alpha.document.sci.bindings :as bindings]
[fr.jeremyschoffen.prose.alpha.eval.sci :as eval-sci]
[fr.jeremyschoffen.prose.alpha.reader.core :as reader]
[fr.jeremyschoffen.prose.alpha.out.markdown.compiler :as cplr]
fr.jeremyschoffen.prose.alpha.out.html.tags))
(def docs-root "src/build/fr/jeremyschoffen/prose/alpha/docs/pages/readme/")
(def example-src (str docs-root "example-doc.html.prose"))
(def example-dest (str docs-root "example-doc.html"))
;; Preparing the namespaces accessible to the sci evaluation env
(def sci-nss {:namespaces
(bindings/make-ns-bindings
fr.jeremyschoffen.prose.alpha.out.html.tags)})
;; Making the sci environment
(def sci-ctxt (doc/init sci-nss))
;; Making a sci eval function using our environment
(def eval-forms (partial eval-sci/eval-forms-in-temp-ns sci-ctxt))
;; Putting together a function that reads and evals documents
(def eval-doc (doc/make-evaluator {:slurp-doc slurp
:read-doc reader/read-from-string
:eval-forms eval-forms}))
;; Generation of the html example
(defn make-example []
(-> example-src
eval-doc
cplr/compile!
clojure.string/trim
(->> (spit example-dest))))
(comment
(make-example))
The first question that came to mind when I discovered Pollen was: why this ◊
character? I expect
the same question will arise for this project.
Pollen and Prose use ◊
for several reasons. Mainly this character isn't used as a special character in
programming languages. To stick to clojure, characters like @
, #
or even &
have special meaning.
◊
not being used either in clojure nor very much in plain text allows us to have expressions such as:
◊(defn template [v]
◊div { Some value: ◊|v})
In this example there is prose syntax used inside clojure code without ambiguity. Using the @
as
Scribble does would cause problems:
@(defn template [v]
@div { Some value: @|v})
In that case which @
hold Prose's meaning and which are a deref
reader macro? Using ◊
gets us out of most of
these problems. When we want to use ◊
as text we can use the escaping/verbatim syntax ◊"◊"
. Also this:
◊(str "◊")
behaves as you'd expect, the ◊ insisde the clojure string isn't special. That should be the extent of our troubles with this character.
For reference here is the answer in the case of pollen from its documentation.
Prose provides 2 apis to evaluate code. The first one uses Clojure's eval function. The second uses Sci.
There are pros and cons to each approach.
Pros:
Cons:
Pros:
Cons:
This work is of course inspired and influenced by Pollen and Scribble.
Copyright © 2020 Jeremy Schoffen.
Distributed under the Eclipse Public License v 2.0.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close