我有时会将函数调用及其输出的示例放在函数定义的文档字符串中。
(defun js-[] (&rest args)
"Javascript array literal statement.
(js-[] 1 2 3)
> \"[1, 2, 3]\"
"
(format nil "[~{~A~^, ~}]" (mapcar #'js-expr args)))
但有时函数的输出是一个字符串。所以我必须在示例输出中转义双引号。这很快就会变得单调乏味。
有没有办法将文档字符串分隔符从双引号更改为其他内容,以便我不必继续转义它们?
请注意,有时它比仅仅逃避一次更糟糕:
(defun js-~ (str)
"Javascript string statement. This is needed so that double quotes are inserted.
(js-~ \"string\")
> \"\\\"string\\\"\"
"
(format nil "\"~A\"" str))
这里还有一个问题。阅读文档是很困难的。
答案 0 :(得分:6)
是 ,您可以 没有 ,您不想这样做。
在Common Lisp中表示字符串的唯一方法是使用
Double-Quote "
,例如,假设您希望通过@
来启动和停止字符串。
(这是一个很少用于符号名称的普通字符,
与%
和$
相反,后者通常用于实现内部符号。)
从@
设置"
的属性:
(multiple-value-bind (function non-terminating-p)
(get-macro-character #\")
(set-macro-character #\@ function non-terminating-p))
现在:
(read-from-string "@123@")
==> "123" ; 5
(read-from-string @"123"@)
==> "123" ; 5
不要忘记restore the input syntax to standard Common Lisp syntax:
(setq *readtable* (copy-readtable nil))
请参阅Reader。
该标准不要求打印标准物体
(例如string
)
使用修改的。
您可以尝试定义print-object
方法:
(defmethod print-object ((o string) (d stream))
...)
然而,
代码存在供人们阅读。
更改Lisp语法会让其他人更难阅读您的代码。
它还会混淆您使用的各种工具(编辑器& c)。
CL有很多疣,但这不是其中之一; - )
PS。另请参阅documentation
和describe
,以及评论语法Sharpsign Vertical-Bar和Semicolon。
答案 1 :(得分:5)
你可以制作一个读取器宏,它会像这样在多行字符串中徘徊:
(defun hash-slash-reader (stream slash arg)
(declare (ignore slash arg))
(loop :with s := (make-string-output-stream)
:for c := (read-char stream)
:if (and (eql #\/ c) (eql #\# (peek-char nil stream)))
:do (read-char stream) (return (get-output-stream-string s))
:if (eql #\Newline c)
:do (peek-char t stream)
:do (princ c s)))
(set-dispatch-macro-character #\# #\/ #'hash-slash-reader)
现在你可以做到:
(defun js-~ (str)
#/ --------------------------
Javascript string statement.
This is needed so that double quotes are inserted.
(js-~ "string")
> "\"string\""
-------------------------- /#
(format nil "\"~A\"" str))
将添加文档字符串,就像您使用双引号编写它一样。 这实际上与更改字符串的分隔符相同!。实际上,这是一种 附加 分隔字符串的方式。
这就是为什么你可以在常规的lisp代码中使用它(不推荐使用),而不仅仅是出于文档目的。
使用/
作为调度宏的子字符,有助于使其在概念上接近多行注释,但避免被读者完全忽略。
答案 2 :(得分:2)
另一个想法。像往常一样写下你的文档字符串,没有例子。
(defun js-~ (str)
"Javascript array literal statement."
...)
定义测试。这可以很简单:
(defparameter *tests*
'(((js-~ "string") . "\"string\"")
...))
使用该列表执行测试:
(loop for (form . expected) in *tests*
for (fn . args) = form
for actual = (apply fn args)
do (assert (equalp actual expected)))
...并更新文档。请注意,这会附加到现有的文档字符串,因此请不要运行两次。
(loop for (form . expected) in *tests*
for (fn . args) = form
do (setf (documentation fn 'function)
(format nil
"~a~%~% ~S~% => ~S"
(documentation fn 'function)
form
expected)))
答案 3 :(得分:2)
您可以(ab)使用cl-interpol。虽然库的目的是启用字符串插值,但如果您不介意使用#?
预先校对字符串,它也允许自定义字符串分隔符。 e.j。
CL-USER> (cl-interpol:enable-interpol-syntax)
; No values
CL-USER> #?'foo'
"foo"
CL-USER> #?/foo/
"foo"
CL-USER> #?{foo}
"foo"
CL-USER>
所以启用interpol reader宏后你可以写
(defun js-[] (&rest args)
#?'Javascript array literal statement.
(js-[] 1 2 3)
> "[1, 2, 3]"
'