Table of Contents
By using this package(literate-lisp), Emacs org mode and elisp library polymode, literate programming can be very easy in one org file containing both documentation and source codes, and this org file can interact well with SLIME.
This library contains the following files:
The implementation and documentation of literate lisp reader.
The tangled codes of literate lisp reader, generated from ./tangle.org
The weaved documentation, generated from ./tangle.org by org mode’s publish feature.
This file contains introduction and demo codes for how to do literate lisp in an org file.
The config file used by Web service travis ci to test this library.
The ASDF definition for literate-lisp project.
The ASDF definition for literate demo project.
install polymode in Emacs
It’s better to edit the org file with polymode,which will make code block use its native file mode. The following elisp scripts in .emacs will install it.
(use-package poly-org :ensure t)
a new code block header argument
Please have a look of the section function to handle reader syntax for “# “(# + Space) in ./literate-lisp.org.
A demo lisp package
Prepare the asd definition file
(eval-when (:load-toplevel :execute) (asdf:load-system :literate-lisp))
Now let’s define the ASDF system for this demo package
(asdf:defsystem literate-demo :author "Xu Jingtao <email@example.com>" :version "0.1" :licence "MIT" :serial t :description "an demo project of literate-lisp" :components ((:module org :pathname "./" :components ((:org "readme")))) :properties ((version "0.1")) :depends-on (:literate-lisp))
Which will load this ./readme.org directly as a lisp source file.
The whole content of ASDF definition file is in ./literate-demo.asd.
Firstly we define a new package for this demo project and switch to it.
(in-package :common-lisp-user) (defpackage :literate-demo (:use :cl)) (in-package :literate-demo)
a demo function to a recursive assoc implementation
As a demo project, we just show a demo function
The function assoc only find first level item from an association list. When I want to find item from an association list contains a lot of other association list with very deep level, I have to write codes like this which is too long.
(cdr (assoc :b (cdr (assoc :a '((:a . ((:b . c))))))))
To simplify the expression, a macro
recursive-assoc to simply to the following form provides:
(recursive-assoc '((:a . ((:b . c)))) :a :b)
A macro function to expand lisp expressions recursively provides firstly.
(eval-when (:compile-toplevel :load-toplevel :execute) (defun expand-recursive-assoc (alist recursive-properties) (if (cdr recursive-properties) (expand-recursive-assoc `(cdr (assoc ,(car recursive-properties) ,alist)) (cdr recursive-properties)) `(cdr (assoc ,(car recursive-properties) ,alist)))))
Then the implementation macro is simple(test is here: ref:test-recursive-assoc)
(defmacro recursive-assoc (alist &rest recursive-properties) (when recursive-properties (expand-recursive-assoc alist recursive-properties)))
For example, you can use it like this,which get
:b part of the sub association list
:a part of the original list.
(equal 'c (recursive-assoc '((:a . ((:b . c)))) :a :b))
Test cases for this demo project
Now it’s time to validate some functions. The FiveAM library is used to test.
(eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package :fiveam) #+quicklisp (ql:quickload :fiveam) #-quicklisp (asdf:load-system :fiveam))) (5am:def-suite literate-demo-suite :description "The test suite of literate-demo.") (5am:in-suite literate-demo-suite)
(5am:test recursive-assoc (5am:is (equal 'c (recursive-assoc '((:a . ((:b . c)))) :a :b))))
run all tests in this library
This function is the entry point to run all tests and return true if all test cases pass.
(defun run-test () (5am:run! 'literate-demo-suite))