;;; validate.el --- Schema validation for Emacs-lisp -*- lexical-binding: t; -*-
-;; Copyright (C) 2016 Artur Malabarba
+;; Copyright (C) 2016 Free Software Foundation, Inc.
;; Author: Artur Malabarba <emacs@endlessparentheses.com>
;; Keywords: lisp
;; Package-Requires: ((emacs "24.1") (cl-lib "0.5"))
-;; Version: 0.1
+;; Version: 0.5
;;; Commentary:
;;
"wrong number of elements"
(seq-find #'identity (seq-mapn #'validate--check values schemas))))
+(defun validate--indent-by-2 (x)
+ (replace-regexp-in-string "^" " " x))
+
(defun validate--check (value schema)
"Return nil if VALUE matches SCHEMA.
If they don't match, return an explanation."
(error "`choice' needs at least one argument")
(let ((gather (mapcar (lambda (x) (validate--check value x)) args)))
(when (seq-every-p #'identity gather)
- (concat "all of the options failed\n "
- (mapconcat #'identity gather "\n "))))))
+ (concat "all of the options failed\n"
+ (mapconcat #'validate--indent-by-2 gather "\n"))))))
;; TODO: `restricted-sexp'
(set (or (wtype 'list)
(let ((failed (list t)))
(let ((print-length 4)
(print-level 2))
(format "Looking for `%S' in `%S' failed because:\n%s"
- schema value r))))))
+ schema value
+ (if (string-match "\\`Looking" r)
+ r
+ (validate--indent-by-2 r))))))))
\f
;;; Exposed API
(lambda (val)
(validate-value val (custom-variable-type symbol) 'noerror))))
+(defmacro validate-setq (&rest svs)
+ "Like `setq', but throw an error if validation fails.
+VALUE is validated against SYMBOL's custom type.
+
+\(fn [SYM VAL] ...)"
+ (let ((out))
+ (while svs
+ (let ((symbol (pop svs))
+ (value (if (not svs)
+ (error "`validate-setq' takes an even number of arguments")
+ (pop svs))))
+ (push `(if (boundp ',symbol)
+ (setq ,symbol (validate-value ,value (custom-variable-type ',symbol)))
+ (user-error "Trying to validate a variable that's not defined yet: `%s'.\nYou need to require the package before validating"
+ ',symbol))
+ out)))
+ `(progn ,@(reverse out))))
+
(provide 'validate)
;;; validate.el ends here