# Common Lisp Document Generator
-Enforcement of documentation guidelines for my Common Lisp Projects, as well as conversion to markdown for github repositories.
+Enforcement of documentation guidelines for my Common Lisp Projects, as well as conversion to markdown for my github repositories.
+
+I wish I had aspirations for this being some standard that someone else might follow, but realistically I'm just irritated at my own laziness with regard to documentation, so I wrote a solution. The forceful nature of the validator is really just because I didn't want to write a smarter parser. As an added bonus, all the docs now look the same when I look at them in the repl, so that's kind of nice.
+
+## Usage
+
+See the [wiki](https://github.com/frankduncan/docgen/wiki) for usage information (generated by this package).
+
+To see how that page was created, take a look at bin/generatedocs.sh
+
+## Package documentation
+
+Packages are documented by sections broken up by one empty line, with the first section limited to 120 characters.
+
+## Structure/Condition documentation
+
+Requirements are the same as the package
+
+## Function documentation
+
+Functions should follow the template:
+
+````
+FUNC PATH => RESULT
+
+ RESULT: SUCCESS-RESULTS | FAILURE-RESULT
+ SUCCESS-RESULTS: SUCCESS-RESULT*
+ SUCCESS-RESULT: (:success FILENAME)
+ FAILURE-RESULT: (:failure FILENAME MSG)
+
+ARGUMENTS AND VALUES:
+
+ PATH: a pathname
+ FILENAME: the file this func was run on
+ MSG: a string containing the failure message
+
+DESCRIPTION:
+
+ FUNC runs all the things against a file located at PATH and returns
+ as soon as the first func error is found.
+
+EXAMPLES:
+
+ (func #P\"path/to/file.lisp\" t) => (:success \"path/to/file.lisp\")
+ (func #P\"path/to/error.lisp\" nil) => (:failure \"path/to/error.lisp\" \"Error msg\")
+````
+
+There are four sections to each function definition:
+
+### Header section
+
+Arguments should all be upper case, but &rest, &optional, and &key should be lower case. Arguments are seperated by a space.
+
+Results should also be upper case, and in the case of values, separated by commas.
+
+Types can be further elucidated by providing more information either as a list of options seperated by pipes, a tuple contained in parens, or a list denoted by an *
+
+### Arguments and values section:
+
+All the types that weren't broken down into subtypes must be explained. The form is type name in all upper case, a colon, then a description. That description can have upper case type names in it which will then get italicized later.
+
+### Description
+
+Descriptins should be indented two spaces, and not longer than 120 characters wide. Like the arguments and values, upper cased types will be italicized later.
+
+### Examples
+
+This section is optional.
+
+Examples are of the form: example-code => example result
--- /dev/null
+#!/bin/bash
+
+sbcl \
+ --eval "(asdf:load-system :docgen)" \
+ --eval "(format t \"----~%\")" \
+ --eval "(format t \"~A\" (docgen:export-package :docgen))" \
+ --eval "(quit)" 2> /dev/null | sed -n '/^----$/,$p' | tail -n +2 > wiki/Home.md
(when (not (syntax-checker:pretty-print-check-directory "src"))
(format t "~c[1;31mFailed style check!~c[0m~%" #\Esc #\Esc)
(sb-ext:exit :code 1))
+(format t "~c[1;32m- Style Passed!~c[0m~%" #\Esc #\Esc)
-(format t "~c[1;32mSuccess!~c[0m~%" #\Esc #\Esc)
+(format t "~%~c[1;33mChecking Docs~c[0m~%" #\Esc #\Esc)
+(when (not (docgen:pretty-print-validate-packages :docgen))
+ (format t "~c[1;31mFailed doc check!~c[0m~%" #\Esc #\Esc)
+ (sb-ext:exit :code 1))
+(format t "~c[1;32m- Doc Check Passed!~c[0m~%" #\Esc #\Esc)
+
+(format t "~c[1;30m--------------~c[0m~%" #\Esc #\Esc)
+(format t "~c[1;32mBuild Success!~c[0m~%" #\Esc #\Esc)
(sb-ext:exit :code 0)
DESCRIPTION:
- NOARGS runs all the things against a file and returns
+ RESULT-LIST runs all the things against a file and returns
as soon as the first func error is found."
nil)
This is should all get pulled in and the markdown.md should be equal to success1.md.
+## Contents
+
+* **function [func-that-does-stuff](#function-func-that-does-stuff)** - _func-that-does-stuff_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [has-keywords](#function-has-keywords)** - _has-keywords_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [has-no-examples](#function-has-no-examples)** - _has-no-examples_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [has-optional](#function-has-optional)** - _has-optional_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [has-rest](#function-has-rest)** - _has-rest_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [noargs](#function-noargs)** - _noargs_ runs all the things against a file and returns as soon as the first func error is found.
+* **function [result-list](#function-result-list)** - _result-list_ runs all the things against a file and returns as soon as the first func error is found.
+* **condition [test-condition](#condition-test-condition)** - Simple documentation.
+* **function [values-result](#function-values-result)** - _values-result_ runs all the things against a file and returns as soon as the first func error is found.
+
## Function **FUNC-THAT-DOES-STUFF**
#### Syntax:
#### Description:
-NOARGS runs all the things against a file and returns as soon as the first func error is found.
+_result-list_ runs all the things against a file and returns as soon as the first func error is found.
## Condition TEST-CONDITION
(in-package #:docgen)
-(define-condition validation-failure nil ((msg :initarg :msg :reader validation-failure-msg)))
+(define-condition validation-failure nil ((msg :initarg :msg :reader validation-failure-msg))
+ (:documentation "Used internally for docgen parts to signal a validation error."))
(defun get-symb-type (symb)
(cond
((documentation symb 'function) :function)))
(defun validate-package (pkg)
+ "VALIDATE-PACKAGE PKG => FAILURES
+
+ FAILURES: FAILURE*
+ FAILURE: (:failure SYMB MSG)
+
+ARGUMENTS AND VALUES:
+
+ PKG: A package symbol
+ SYMB: Symbol the check failed on
+ MSG: Message containing information about the failure
+
+DESCRIPTION:
+
+ VALIDATE-PACKAGE takes in PKG and validates that all the external symbols
+ adhere to documentation guidelines, exist, and can be parsed to be used
+ for exporting.
+
+ Only one error per symbol will be reported at a time, all concatenated to
+ a list in the aforementioned form."
(macrolet
- ((with-success-check (&rest f)
+ ((with-success-check (symb &rest f)
`(handler-case
(progn ,@f :success)
- (validation-failure (v) (list :failure (validation-failure-msg v))))))
+ (validation-failure (v) (list :failure ,symb (validation-failure-msg v))))))
(let
((symbs nil))
(do-external-symbols (symb pkg) (push symb symbs))
(setf symbs (sort symbs #'string< :key #'symbol-name))
(remove :success
(append
- (list (with-success-check (docgen-pkg:doc->ast (find-package pkg))))
+ (list (with-success-check pkg (docgen-pkg:doc->ast (find-package pkg))))
(mapcar
(lambda (symb)
- (with-success-check
+ (with-success-check symb
(case (get-symb-type symb)
(:function (docgen-func:doc->ast symb))
(:structure (docgen-struc:doc->ast symb))
symbs))))))
(defun pretty-print-validate-packages (&rest pkgs)
- (mapcar
- (lambda (pkg)
- (let
- ((failures (validate-package pkg)))
- (mapcar
- (lambda (failure)
- (format t "In package ~A, documentation error found:~% ~A" pkg (cadr failure)))
- failures)
- (not failures)))
- pkgs))
+ "PRETTY-PRINT-VALIDATE-PACKAGES &rest PKGS => SUCCESS
+
+ PKGS: PKG*
+
+ARGUMENTS AND VALUES:
+
+ SUCCESS: Whether or not all symbols passed validation
+ PKG: A package symbol
+
+DESCRIPTION:
+
+ PRETTY-PRINT-VALIDATE-PACKAGES takes PKGS and runs validation on all of them.
+ It dumps to standard out failures as it comes upon them, finally returning
+ whether it was successful or not.
+
+ This can be used in travis tests to ensure that documentation can be generated
+ at a later date.
+
+EXAMPLES:
+
+ (pretty-print-validate-packages :pkg1 :pkg2) => t"
+ (some
+ #'identity
+ (mapcar
+ (lambda (pkg)
+ (let
+ ((failures (validate-package pkg)))
+ (mapcar
+ (lambda (failure)
+ (format t "In ~A : ~A, documentation error found:~% ~A~%" pkg (second failure) (third failure)))
+ failures)
+ (not failures)))
+ pkgs)))
+
+(defun table-of-contents (pkg)
+ (format nil "## Contents~%~%~{~{* **~A [~A](#~A)** - ~A~}~%~}"
+ (let
+ ((symbs nil))
+ (do-external-symbols (symb pkg) (push symb symbs))
+ (setf symbs (sort symbs #'string< :key #'symbol-name))
+ (mapcar
+ (lambda (symb)
+ (case (get-symb-type symb)
+ (:function
+ (list
+ (docgen-func:ast->category-name (docgen-func:doc->ast symb))
+ (docgen-func:ast->short-name (docgen-func:doc->ast symb))
+ (docgen-func:ast->link (docgen-func:doc->ast symb))
+ (docgen-func:ast->short-desc (docgen-func:doc->ast symb))))
+ (:structure
+ (list
+ (docgen-struc:ast->category-name (docgen-struc:doc->ast symb))
+ (docgen-struc:ast->short-name (docgen-struc:doc->ast symb))
+ (docgen-struc:ast->link (docgen-struc:doc->ast symb))
+ (docgen-struc:ast->short-desc (docgen-struc:doc->ast symb))))))
+ symbs))))
(defun export-package (pkg)
+ "EXPORT-PACKAGE PKG => MARKDOWN
+
+ARGUMENTS AND VALUES:
+
+ PKG: A package symbol
+ MARKDOWN: A string containing the markdown representation of this packages documentation
+
+DESCRIPTION:
+
+ EXPORT-PACKAGE takes in PKG and converts all the documentation for the symbols
+ into markdown with the hope of emulating the hyperspec style.
+
+ It should only be run after the package has been validated, as it assumes that
+ all documentation it gets will be valid."
(let
((symbs nil))
(do-external-symbols (symb pkg) (push symb symbs))
(setf symbs (sort symbs #'string< :key #'symbol-name))
(with-output-to-string (str)
(format str "~A~%~%" (docgen-pkg:ast->md (docgen-pkg:doc->ast (find-package pkg))))
+ (format str "~A~%" (table-of-contents pkg))
(format str "~{~A~^~%~}"
(mapcar
(lambda (symb)
- (format t "HAHAHAH ~A ~A~%" symb (get-symb-type symb))
(case (get-symb-type symb)
(:function (docgen-func:ast->md (docgen-func:doc->ast symb)))
(:structure (docgen-struc:ast->md (docgen-struc:doc->ast symb)))))
(format-args-and-values (get-section :arguments-and-values))
(format-description (get-section :description))
(format-examples (get-section :examples)))))
+
+(defun ast->category-name (ast)
+ (declare (ignore ast))
+ "function")
+
+(defun ast->short-name (ast)
+ (format nil "~(~A~)" (second (find :function ast :key #'car))))
+
+(defun ast->link (ast)
+ (format nil "function-~(~A~)" (second (find :function ast :key #'car))))
+
+(defun ast->short-desc (ast)
+ (format-text (car (cadr (find :description ast :key #'car)))))
(defpackage #:docgen (:use :cl)
- (:export #:validate-package #:export-package #:validation-failure #:pretty-print-validate-packages))
+ (:export #:validate-package #:export-package #:validation-failure #:pretty-print-validate-packages)
+ (:documentation "Main docgen package.
+
+Use docgen to validate that documentation strings on external symbols adhere to
+a strict format and exist, so that they can be output to markdown format, while
+looking decent when used within a common lisp process."))
(defpackage #:docgen-func (:use :cl)
- (:export #:doc->ast #:ast->md))
+ (:export #:doc->ast #:ast->md #:ast->link #:ast->short-name #:ast->short-desc #:ast->category-name))
(defpackage #:docgen-pkg (:use :cl)
(:export #:doc->ast #:ast->md))
(defpackage #:docgen-struc (:use :cl)
- (:export #:doc->ast #:ast->md))
+ (:export #:doc->ast #:ast->md #:ast->link #:ast->short-name #:ast->short-desc #:ast->category-name))
(first ast)
(second ast)
(cddr ast)))
+
+(defun ast->category-name (ast)
+ (case (first ast)
+ (:condition "condition")
+ (t "structure")))
+
+(defun ast->short-name (ast)
+ (format nil "~(~A~)" (second ast)))
+
+(defun ast->link (ast)
+ (format nil "~(~A-~A~)" (first ast) (second ast)))
+
+(defun ast->short-desc (ast)
+ (third ast))
(defsuccesstest :success1 "resources/success1.lisp" "resources/success1.md")
(deffailuretest :emptydocs "resources/emptydocs.lisp"
- '((:failure "Package EMPTYDOCS has no documentation")
- (:failure "Symbol NO-DOC-CONDITION has no documentation")
- (:failure "Symbol NO-DOC-FUNC has no documentation")))
+ `((:failure :emptydocs "Package EMPTYDOCS has no documentation")
+ (:failure ,(intern "NO-DOC-CONDITION" :emptydocs) "Symbol NO-DOC-CONDITION has no documentation")
+ (:failure ,(intern "NO-DOC-FUNC" :emptydocs) "Symbol NO-DOC-FUNC has no documentation")))
-Subproject commit 1a8916ff9faac67cbb461da9cc939d8bee63bf25
+Subproject commit 06c150fca744ae5052741ca676e09d7081d0eefe