Add variable documentation
[sheep] / src / main / docgen.lisp
index 2ed740bdd66a51892a3afe9556c52c4ce55a1530..f873f994857d07e2699e00a4ea797498db32db64 100644 (file)
 (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 'variable) :variable)
+  ((documentation symb 'structure) :structure)
+  ((documentation symb 'function) :function)))
 
 (defun validate-package (pkg)
- (let
-  ((symbs nil))
-  (do-external-symbols (symb pkg) (push symb symbs))
-  (setf symbs (sort symbs #'string< :key #'symbol-name))
-  (remove :success
+ "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 (symb &rest f)
+    `(handler-case
+      (progn ,@f :success)
+      (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 pkg (docgen-pkg:doc->ast (find-package pkg))))
+     (mapcar
+      (lambda (symb)
+       (with-success-check symb
+        (case (get-symb-type symb)
+         (:function (docgen-func:doc->ast symb))
+         (:structure (docgen-struc:doc->ast symb))
+         (:variable (docgen-var:doc->ast symb))
+         (t (error (make-condition 'validation-failure :msg (format nil "Symbol ~A has no documentation" symb)))))))
+      symbs))))))
+
+(defun pretty-print-validate-packages (&rest 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"
+ (every
+  #'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)
-     (handler-case
-      (progn
-       (docgen-func:doc->ast symb)
-       :success)
-      (validation-failure (v) (list :failure :msg (validation-failure-msg v)))))
+     (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))))
+      (:variable
+       (list
+        (docgen-var:ast->category-name (docgen-var:doc->ast symb))
+        (docgen-var:ast->short-name (docgen-var:doc->ast symb))
+        (docgen-var:ast->link (docgen-var:doc->ast symb))
+        (docgen-var:ast->short-desc (docgen-var: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))
-  (format nil "~{~A~^~%~}" (mapcar (lambda (symb) (docgen-func:ast->md (docgen-func:doc->ast symb))) symbs))))
+  (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)
+      (case (get-symb-type symb)
+       (:variable (docgen-var:ast->md (docgen-var:doc->ast symb)))
+       (:function (docgen-func:ast->md (docgen-func:doc->ast symb)))
+       (:structure (docgen-struc:ast->md (docgen-struc:doc->ast symb)))))
+     symbs)))))