Clojure/ClojureScript Boot literate programming template
1 Introduction
1.1 Clojure/ClojureScript/Boot literate programing project template for Emacs + Org mode
This is a skeleton of a Literate Clojure/Boot project in Emacs/Org envirenoment. It shows how to shape a literate programming project from several org-files, and no just one, and still have proper documentation and code export (tangling) both from Emacs directly as well as from project generated shell-scripts.
The project is self-documenting, get started from project.org and it should be more or less clear how to use it,
or navigate to pre-exported documentation.
2 Quick start
- Git clone from https://github.com/MaximGB/clojure-boot-literate.git.
- Load project Library of Babel, by executing the following code block
(org-babel-lob-ingest "build/lob.org"), to execute it place the cursor on the block and press C-c C-c. - Fill in the table in the Project specification section.
- Read the Environment and project requirements section, setup your environment accordingly and create
the code exporting scripts
tangle.shandtangle-all.sh. - Export initial project code by runing
./tangle-all.sh, place the cursor on the code block and press C-c C-c to execute it from Emacs, or runtangle-all.shfrom a terminal. - Build the project with Boot:
- For Clojure
boot clj-build, place the cursor on the code block and press C-c C-c to execute it, or runboot clj-buildfrom a terminal. - For ClojureScript
boot cljs-figwheel, place the cursor on the code block and press C-c C-c to execute it, or runboot cljs-figwheelfrom a terminal.
- For Clojure
- Run the project by running
java -jar target/project.jar, place the cursor on the code block and press C-c C-c, or runjava jar target/project.jarfrom a terminal. - Keep working on the project export the code periodically.
- To export the project documentation:
- Into
project.pdfpress С-с С-e l p. - Into
project.htmlpress C-c C-e h h.
- Into
3 Project specification
Project specification is given in the table following. The project file system as well as boot.properties
and build.boot files are generated according to the specification.
| Property | Value |
|---|---|
| Boot | |
| Version | 2.6.0 |
| Project name | literate-boot |
| Project version | 0.1.0-SNAPSHOT |
| Org sources path | org |
| Tests path | tests |
| Resource path | resources |
| Assets path | assets |
| Target path | target |
| Main namespace | core |
| Clojure | yes |
| Version | 1.8.0 |
| Sources path | src |
| ClojureScript | yes |
| Version | 1.9.225 |
| Sources path | src |
| Public resources path | resources/public |
| Cider | |
| Version | 0.14.0 |
3.1 Dependencies
Project dependencies are given in the dependencies table
One dependency per the table row should be given. The table columns correspond to options supported by pomegranate library, which in it's turn, is used by Boot for dependecies resolution 1:
- Name - artifact name
- Version - artifact version
- Scope - dependency scope (in Maven terms), mighe be one of:
compile, provided, runtime, test, system, import - Optional - dependency optionality flag, any dependency having
noor empty value in this column is considired to be optional - Classifier - dependency classifier (in Maven terms)
- Extension - dependency extension (in Maven-terms)
- Exclusion - transitive dependencies exclusions for the dependency, one exclusion per the table row is allowed if you need to setup several exclusions for one dependency than for second and other exclusions name, version, scope, optional, classifier, extension columns should be empty
- Classifier - exclusion dependency classifier (in Maven terms)
- Extension - exclusion dependency extension (in Maven-terms)
- Note - this column is ignored, it's used for documentation purposes
| Name | Version | Scope | Optional | Classifier | Extension | Exclusion | Classifier | Extension | Note |
4 Environment and project requirements
4.1 Environtment
This project template requires Emacs/Org-mode, Clojure, Boot. The project which might be built using this template will follow principles of the literate programming, i.e. when program code is extracted from Org files, which in turn combine a project documentation and code.
4.2 Code export from org-files.
To exctract code from org-files into files with Clojure source code tangle.sh file is used 2.
Unfortunatelly it's impossible to export code from Emacs by simply executing M-x org-babel-tangle
call out of the box using this template. The project org-files are using the so called "Library of Babel" feature,
the code of which is inside build/lob.org file. To initialize the library a call to (org-babel-lob-ingest)
is required. This call is done inside tangle.sh file and if you run it from a terminal everything should work
out of the box. To export code from Emacs you will have to execute (org-babel-lib-ingest "build/lob.org")
call once per session (Emacs run).
To create tangle.sh file in the project's root directory place the cursor into the following source code block
and press C-u C-c C-v t, this will put the code block contents into tangle.sh file on your disk.
DIR=`pwd` FILES="" # wrap each argument in the code required to call tangle on it for i in $@; do FILES="$FILES \"$i\"" done emacs -Q --batch \ --eval \ "(progn (require 'package) (let ((default-directory package-user-dir)) (normal-top-level-add-subdirs-to-load-path)) (require 'cl)(require 'org)(require 'ob)(require 'ob-tangle)(require 'ob-lob) (org-babel-lob-ingest \"build/lob.org\") (setq org-confirm-babel-evaluate nil) (mapc (lambda (file) (find-file (expand-file-name file \"$DIR\")) (org-babel-tangle) (kill-buffer)) '($FILES)))" \ 2>&1 | grep Tangled
This script receives org-file names which to extract source code from: tangle.sh file ..., where file is
name or names of org-files to process.
4.3 Project code export
To extract project source code from all org-files the tangle-all.sh shell-script is used 2.
To create tangle-all.sh file in the project's root directory place the cursor into the following source code block
and press C-u C-c C-v t, this will put the code block contents into tangle-all.sh file on your disk.
./tangle.sh project.org build/*.org org/*.org
5 "Library of Babel" helper code blocks library
Helper code blocks constituting the project's "Library of Babel" are defined here. This code blocks work in Emacs/Org environment and are not supposed to be called from Clojure or ClojureScript.
5.1 time-is-now
Returns current time as a string in a given format.
Examples:
<<time-is-now()>> <<time-is-now(format="%F") #+CALL: time-is-now()
| Name | Default value | Description |
|---|---|---|
| [format] | "%F %X" | Time string format as supported by (format-time-string) function. Optional. |
(format-time-string format)
5.2 get-table-param
Returns a value of a parameter defined in a table. Table must follow given requirements: parameter names are given
in the first column, parameter values - in the second column. Hierarchical queries are supported in a way,
if parameter name is given as name/subname then first name will be searched and then subname will be searched
starting from name a row where name has been found.
Examples:
<<get-table-param(table=../project.org:project-specification, title="Project name")>> <<get-table-param(table=../project.org:project-specification, title="Project name", splitby="-", joinby="_")>> <<get-table param(table=../project.org:project-specification, title="Clojure/Version")>> #+CALL: get-table-param(table=../project.org:project-specification, title="Project name")
| Name | Default value | Description |
|---|---|---|
| table | (quote ()) | Table reference. Reference format is [table containing org-file path:]table-name, |
for example ../file.org:table_name or just table_name if a table is given |
||
| in the same file the call is done from. Default value simply allows return nil if | ||
| parameter is not given, since internally code block receives a table as a list. | ||
| title | "" | Parameter name. Path-like parameter names are supported (i.e. names containing '/'. |
| If such complex parameter is given, than it'll be splited, and each resulting part | ||
| will be considered as a separate parameter name. The following parameter name search | ||
| will be started from a row where the preceding parameter name has been found, a value | ||
| of a preceding parameter is ignored. A value of the last parameter will be returned. | ||
| [splitby] | "" | Parameter value splitter. Optional. Works in pair with joinby. If parameter values |
a listed in a cell as comma-separated list, for example, than, giving splitby=",", |
||
will split'em, and splitted values will be joined with joinby value. |
||
| [joinby] | "" | Parameter value combinator. Optional. Works in pair with splitby. |
(let* ((table-adopted (mapcar (lambda (x) (if (equal x 'hline) '(hline hline hline) x)) table)) (titles (mapcar #'car table-adopted)) (path (split-string title (regexp-quote "/"))) (last-index (reduce (lambda (index title) (cl-position title titles :start index :test #'equal)) path :initial-value nil))) (if last-index (let* ((result (nth 1 (nth last-index table-adopted)))) (if (and result splitby joinby) (mapconcat #'identity (split-string result (regexp-quote splitby) t "\s+") joinby) result))))
5.3 get-specification-param
Returns parameter value given in the project specification table inside ../project.org file.
Examples:
<<get-specification-param(title="Project name")>> <<get-specification-param(title="Main namespace", splitby="." joinby="/")>> #+CALL: get-specification-param(title="Project name")
| Name | Default value | Description |
|---|---|---|
| title | "" | Parameter name (see (get-table-param)). |
| [splitby] | "" | Parameter value separator (see (get-table-param)). |
| [joinby] | "" | Parameter value combinator (see. (get-table-param)). |
(save-excursion (let ((project-org-dir (locate-dominating-file (buffer-file-name) "project.org"))) (if project-org-dir (let ((project-spec-ref (concat project-org-dir "project.org:project-specification"))) (org-babel-execute-src-block nil (cdr (assoc 'get-table-param org-babel-library-of-babel)) (list (cons :var (format "table=%s" project-spec-ref)) (cons :var (format "title=\"%s\"" title)) (cons :var (format "splitby=\"%s\"" splitby)) (cons :var (format "joinby=\"%s\"" joinby))))))))
5.4 in-some-path
Returns an absolute path to a file in one of the project directories given in the project specification table, will take project name into account and insert it as intermediate directory if requested.
Requirements: Project specification must have following parameters defined:
- Project name
- Parameter given in
paramcode block parameter.
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-some-path (param="Clojure/Sources path" path \"core.clj\")) ... #+END_SRC <<in-some-path(param="Clojure/Sources path", path="core.clj")>> #+CALL: in-some-path(param="Clojure/Sources path", path="core.clj")
| Name | Default value | Description |
|---|---|---|
| param | "Clojure/Sources path" | Parameter name defining the base directory (relative to project root) |
| [path] | "" | Path relative to built directory name |
| [projectvise] | t | Whether to insert project name between base directory path and the path |
part given in path parameter |
(save-excursion (let* ((project-org-dir (locate-dominating-file (buffer-file-name) "project.org")) (src-path (org-babel-execute-src-block nil (cdr (assoc 'get-specification-param org-babel-library-of-babel)) (list (cons :var (format "title=\"%s\"" param))))) (project-name (org-babel-execute-src-block nil (cdr (assoc 'get-specification-param org-babel-library-of-babel)) (list (cons :var "title=\"Project name\"") (cons :var "splitby=\".\"") (cons :var "joinby=\"/\"")))) (ns-path (replace-regexp-in-string "\-" "_" project-name))) (concat project-org-dir src-path "/" (if projectvise (concat ns-path "/") "") path)))
5.5 in-clj-path
Return an absolute path to a file in project's exported Clojure sources directory with respect to project name.
Requirements: Project specification must have following parameters defined:
- Project name
- Clojure/Sources path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-clj-path (path \"core.clj\")) ... #+END_SRC <<in-clj-path(path="core.clj")>> #+CALL: in-clj-path(path="core.clj")
| Name | Default value | Description |
|---|---|---|
| path | "" | Path relative to project's exported Clojure sources directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"Clojure/Sources path\"") (cons :var (format "path=\"%s\"" path)))))
5.6 in-cljs-path
Return an absolute path to a file in project's exported Clojure Script sources directory with respect to project name.
Requirements: Project specification must have following parameters defined:
- Project name
- ClojureScript/Sources path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-cljs-path (path \"core.clj\")) ... #+END_SRC <<in-cljs-path(path="core.clj")>> #+CALL: in-cljs-path(path="core.clj")
| Name | Default value | Description |
|---|---|---|
| path | "" | Path relative to project's exported Clojure Script sources directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"ClojureScript/Sources path\"") (cons :var (format "path=\"%s\"" path)))))
5.7 in-tests-path
Return an absolute path to a file in project's exported tests sources directory with respect to project name.
Requirements: Project specification must have following parameters defined:
- Project name
- Tests path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-tests-path (path \"core.clj\")) ... #+END_SRC <<in-tests-path(path="core.clj")>> #+CALL: in-tests-path(path="core.clj")
| Name | Default value | Description |
|---|---|---|
| path | "" | Path relative to project's exported tests directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"Tests path\"") (cons :var (format "path=\"%s\"" path)))))
5.8 in-resources-path
Return an absolute path to a file in project's exported resources directory.
Requirements: Project specification must have following parameters defined:
- Project name
- Resource path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-resources-path (path \"index.html")) ... #+END_SRC <<in-resources-path(path="index.html")>> #+CALL: in-resources-path(path="index.html")
| Name | Default value | Description |
|---|---|---|
| path | "" | A path relative to project's exported resources directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"Resource path\"") (cons :var (format "path=\"%s\"" path)) (cons :var "projectvise=()"))))
5.9 in-assets-path
Return an absolute path to a file in project's exported assets directory.
Requirements: Project specification must have following parameters defined:
- Project name
- Assets path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-resources-path (path \"index.html")) ... #+END_SRC <<in-resources-path(path="index.html")>> #+CALL: in-resources-path(path="index.html")
| Name | Default value | Description |
|---|---|---|
| path | "" | A path relative to project's exported assets directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"Assets path\"") (cons :var (format "path=\"%s\"" path)) (cons :var "projectvise=()"))))
5.10 in-target-path
Returns an absolute path to a file in project's target directory.
Requirements: Project specification must have following parameters defined:
- Project name
- Target path
Examples:
#+BEGIN_SRC clojure :tangle (org-sbe in-target-path (path \"project.jar")) ... #+END_SRC <<in-target-path(path="project.jar")>> #+CALL: in-target-path(path="project.jar")
| Name | Default value | Description |
|---|---|---|
| path | "" | A path relative to project's target directory to be appended |
(save-excursion (org-babel-execute-src-block nil (cdr (assoc 'in-some-path org-babel-library-of-babel)) (list (cons :var "param=\"Target path\"") (cons :var (format "path=\"%s\"" path)) (cons :var "projectvise=()"))))
5.11 render-project-dependencies
Renders (returns as a string) project dependencies, defined in the project dependencies table, as a list of Clojure vectors.
Examples:
<<render-project-dependencies()>> #+CALL: render-project-dependencies() (org-sbe render-project-dependencies)
; Full dependency definition specification is given here ; https://github.com/cemerick/pomegranate/blob/master/src/main/clojure/cemerick/pomegranate/aether.clj ; in resolve-dependencies function (require 'subr-x) (require 'seq) (let ((project-org-dir (locate-dominating-file (buffer-file-name) "project.org"))) (if project-org-dir (let* ((project-spec-ref (concat project-org-dir "project.org:project-dependencies")) ; deps-table is a list of lists and hlines (deps-table (org-babel-ref-resolve project-spec-ref)) ; Dependency representing hash-map key traversing sequence (serialize-key-traversing-seq '(name version scope optional classifier extension exclusions))) (cl-labels ( ; dependency hash map has following keys ; - name - dependency artifact name ; - version - dependency artifact version ; - scope - dependency scope ; - optional - flag showing whether a dependency is optional, any value but "" and "no" is considered to be true ; - classifier - dependency Maven-classifier ; - extension - dependency Maven-extension ; - exclusions - list of transient dependency exclusions for a dependency (make-dependency (name version scope optional classifier extension exclusions) (let ((new-dep (make-hash-table))) (puthash 'name name new-dep) (puthash 'version (format "%s" version) new-dep) (puthash 'scope scope new-dep) (puthash 'optional (if (or (string-empty-p optional) (string= "no" (downcase optional))) nil 't) new-dep) (puthash 'classifier classifier new-dep) (puthash 'extension extension new-dep) (puthash 'exclusions exclusions new-dep) new-dep)) ; Dependency serializing function (serialize-dependency (dependency) (concat "[" ; Traversing every key in the dependency hash table and building dependency definition string (mapconcat (lambda (key) (let ((value (gethash key dependency))) (cond ; name is always given ((equal key 'name) value) ; I'm not sure but maybe version might be empty ((and (equal key 'version) (not (string-empty-p value))) (format "\"%s\"" value)) ; Scope is optional ((and (equal key 'scope) (not (string-empty-p value))) (format ":scope \"%s\"" value)) ; Optional flag should be set only if it's true ((and (equal key 'optional) value) ":optional true") ; Classifier is optinal ((and (equal key 'classifier) (not (string-empty-p value))) (format ":classifier \"%s\"" value)) ; Extension is optional ((and (equal key 'extension) (not (string-empty-p value))) (format ":extension \"%s\"" value)) ; Exclusions should be given if there're any ((and (equal key 'exclusions) (not (seq-empty-p value))) (concat ":exclusions [" (mapconcat #'serialize-dependency value " ") "]"))))) serialize-key-traversing-seq " ") "]"))) (let ( ; deps-adopted is a list of hash tables representing dependencies (deps-adopted (reduce (lambda (deps-adopted dependency) ; Skip any hlines and empty rows (if (or (equal dependency 'hline) (every #'string-empty-p dependency)) deps-adopted ; Else destructuring the dependency given (destructuring-bind (name version scope optional classifier extension exclusions ex-classifier ex-extension _) dependency (cond ; Append new dependency hash map in case there's a name given ((not (string-empty-p name)) (append deps-adopted (list (make-dependency name version scope optional classifier extension (if (not (string-empty-p exclusions)) (list (make-dependency exclusions "" "" "" ex-classifier ex-extension nil))))))) ; Append another exclusion in case there's no name but exclusions given ((and (string-empty-p name) (not (string-empty-p exclusions))) (let* ((last-dep (car (last deps-adopted)))) (puthash 'exclusions (append (gethash 'exclusions last-dep nil) (list (make-dependency exclusions "" "" "" ex-classifier ex-extension nil))) last-dep) deps-adopted)))))) ; Skipping title line (cdr deps-table) :initial-value nil))) ; So now I have list of dependencies (as hash maps) which I'm to transform into Clojure's vector of vectors ; in Clojure syntax (mapconcat #'serialize-dependency deps-adopted "\n"))))))
5.12 render-code-block-if
Renders a code block if the project specification table contains a parameter with a given name and a value passing an equality condition.
Requirements:
- A code block with a given name must be defined in file the call is done from.
Examples:
<<render-codeblock-if(name="project-clojurescript-dependencies" if="ClojureScript=yes")>> #+CALL: render-codeblock-if(name="project-clojurescript-dependencies" if="ClojureScript=yes")
| Name | Default value | Description |
|---|---|---|
| name | "" | A code block name to be rendered, the one given in it's #+NAME: dirrective. |
| condition | "" | Rendering condition given as "parameter = value", where = is string comparison |
| operation. |
(save-excursion (destructuring-bind (&optional (param-name "") &optional (cond-value "")) (split-string condition "=" t "\s+") (let ((param-value (org-babel-execute-src-block nil (cdr (assoc 'get-specification-param org-babel-library-of-babel)) (list (cons :var (format "title=\"%s\"" param-name)))))) (if (string= param-value cond-value) (progn (org-babel-goto-named-src-block name) (let ((tangle-result (org-babel-tangle-single-block ""))) (nth 5 tangle-result))) ""))))
6 Boot-project
6.1 boot.properties
boot.properties file is used by Boot to link your Clojure/ClojureScript project to a particular version
of Boot executing by a particular version of Clojure.
#http://boot-clj.com #2016-12-19 07:29:34 BOOT_CLOJURE_NAME=org.clojure/clojure BOOT_CLOJURE_VERSION=1.8.0 BOOT_VERSION=2.6.0
6.2 build.boot
build.boot file is executed by Boot upon running the following command boot task, where task
is a name of Boot-task to execute. Project's tasks are defined below in a corresponding sections.
Setting up corresponding project directories if they are defined in the project specification table and exist on build machine disk.
(def paths [ [:source-paths "src"] [:source-paths "src"] [:resource-paths "resources"] [:asset-paths "assets"] ] ) (doseq [[ env-key path ] paths] (if (and (seq path) (not ((get-env env-key) path))) (let [dir (file path)] (if (.isDirectory dir) (set-env! env-key #(conj % (.getName dir)))))))
If dependency from Clojure is defined in the project specification table, i.e. value yes is given against
parameter Clojure, than adding org.clojure/clojure dependency.
(set-env! :dependencies #(conj % '[org.clojure/clojure "1.8.0"]))
If dependency from ClojureScript is defined in the project specification table, i.e. value yes is given against
parameter ClojureScript, than adding org.clojure/clojurescript dependency.
(set-env! :dependencies #(conj % '[org.clojure/clojurescript "1.9.225"]))
Adding project dependencies defined in the project dependencies table.
(let [deps '[ ]] (set-env! :dependencies #(into % deps)))
6.2.1 Clojure related project's Boot-tasks
These tasks will be added into resulting build.boot file, if Clojure parameter is set to yes
in the project specification table
All blocks of code defining Boot-tasks for Clojure must have boot-clojure-task name. Each task defined
in code block with boot-clojure-task name will be added into resulting build.boot file.
6.2.1.1 clj-build
This task builds project's uberjar which might be run with
java -jar target/project.jar
(deftask clj-build "Builds project's uberjar" [] (comp (pom :project 'literate-boot :version "0.1.0-SNAPSHOT") (aot :all true) (uber) (jar :main 'literate-boot.core) (target :dir #{"target"})))
To execute the task run: boot clj-build
6.2.1.2 clj-run
This task executes project's main function in the Boot's Java environment.
(deftask clj-run "Runs the project's main function" [] (require 'literate-boot.core) (let [main-fn (resolve 'literate-boot.core/-main)] (comp (aot :all true) (with-pass-thru _ (main-fn)))))
To execute the task run: boot clj-run
6.2.2 ClojureScript related project's Boot-задачи
These tasks will be added into resulting build.boot file, if ClojureScript parameter is set to yes
in the project specification table
All blocks of code defining Boot-tasks for Clojure must have boot-clojurescript-task name. Each task defined
in a code block with boot-clojurescript-task name will be added into resulting build.boot file.
6.2.2.1 cljs-figwheel
This task is an interface to figwheel, to execute it run boot cljs-figwheel.
The task compiles ClojureScript files, runs HTTP-server serving project's public resources directory,
runs changes monitor and automaticaly recompiles and reloads the project upon *.cljs files change,
runs nRepl server.
To run a ClojureScript repl one has to go through "9 steps to success":
- run
boot cljs-figwheel - wait for Clojure repl prompt
- look for address and port of a run web-server (usually http://localhost:3449/) in the console output
- open a browser, novigate to web-server address:port URL, open browser's developer tools console and make sure there's "Opened Websocket REPL connection" message present
- look address and port of a nRepl server, in the console output and pass it to
(cider-connect)call at the next step - execute
(cider-connect HOST PORT)orM-x cider-connectand input nRepl HOST and PORT, though, it appears as if cider is able to take the values needed from.nrepl-portfile, so one can just press ENTER twice - execute
(cljs-repl)in repl-buffer to run a ClojureScript REPL - execute
(.log js/console "OK!")in repl-buffer and make sure there's "OK!" message present in the brower's developer tools console. - done!
(set-env! :dependencies #(into % '[[ajchemist/boot-figwheel "0.5.4-6" :scope "test"] [org.clojure/tools.nrepl "0.2.12" :scope "test"] [com.cemerick/piggieback "0.2.1" :scope "test"] [figwheel-sidecar "0.5.7" :scope "test"]])) (require '[boot-figwheel :refer [figwheel start-figwheel! stop-figwheel! start-autobuild stop-autobuild cljs-repl fig-status]]) ;; This is for (cider-connect) to work. ;; NOTE: do not use (cider-jack-in), use (cider-connect) instead ;; --------------------------- ;; Start of cider related code (swap! boot.repl/*default-dependencies* concat '[[cider/cider-nrepl "0.14.0"]]) (swap! boot.repl/*default-middleware* conj 'cider.nrepl/cider-middleware) ;; End of cider related code (deftask cljs-figwheel "Compiles ClojureScript, serves it, autobuilds" [] (comp (figwheel :build-ids ["dev"] ;:once-build ["advanced"] :all-builds [{:id "dev" :source-paths (seq (get-env :source-paths)) :compiler {:main 'literate-boot.core :optimizations :none :source-map true :output-to "app.js"} :figwheel {:build-id "dev" :on-jsload 'literate-boot.core/-main :heads-up-display true :autoload true :debug false}}] :figwheel-options {:http-server-root "public" :open-file-command "emacsclient" :repl false} :target-path "resources/public") (speak) (repl)))
6.2.3 User's Boot-tasks
All code blocks defining user's Boot-tasks must have boot-user-task name. Each tasks defined in a code block
with boot-user-task name will be included into resulting build.boot file.
7 Project code
7.1 Core namespace
7.1.1 Functions
7.1.1.1 -main
(ns literate-boot.core (:gen-class)) (defn -main "Project's entry point" [& args] (println "Hello, from literate-boot!"))
(ns literate-boot.core (:refer-clojure)) (enable-console-print!) (defn ^:export -main "Project's entry point" [& args] (println "Hello, from literate-boot!!"))
<!doctype html> <html> <head> <title>literate-boot</title> </head> <body> <script src="app.js"></script> </body> </html>
Footnotes:
For the one interested please see the documentation for cemeric.pomegranate.aether/resolve-dependencies function
tangle.sh and tangle-all.sh shell-script has been taken from thi.ng/babel project and adopted to this project a bit.