Skip to content

Commit

Permalink
added a collect-nil parameter to with-collector that defaults to true…
Browse files Browse the repository at this point in the history
… but can be set to false to never collect a nil
  • Loading branch information
bobbysmith007 committed May 26, 2011
1 parent 4b1ba4b commit 80408c4
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
16 changes: 10 additions & 6 deletions collectors.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ FUNCTION and INITIAL-VALUE are passed directly to MAKE-REDUCER."
;;;;
;;;; Building up a list from multiple values.

(defun make-collector (&optional initial-value)
(defun make-collector (&optional initial-value (collect-nil t))
"Create a collector function.
A Collector function will collect, into a list, all the values
Expand All @@ -133,6 +133,7 @@ current list of values."
(let ((value initial-value)
(cdr (last initial-value)))
(lambda (&rest items)
(unless collect-nil (setf items (delete-if #'null items)))
(if items
(progn
(if value
Expand All @@ -159,14 +160,15 @@ current list of values."
(mapcar #'alexandria:ensure-list items)))
(apply collector items))))

(defun make-pusher (&optional initial-value)
(defun make-pusher (&optional initial-value (collect-nil t))
"Create a function which collects values as by PUSH."
(let ((value initial-value))
(lambda (&rest items)
(if items
(progn
(dolist (i items)
(push i value))
(when (or collect-nil i)
(push i value)))
items)
value))))

Expand All @@ -181,15 +183,17 @@ current list of values."
(apply ,appender items)))
,@body))))

(defmacro with-collector ((name &optional initial-value from-end) &body body)
(defmacro with-collector ((name &key
(collect-nil T)
initial-value from-end) &body body)
"Bind NAME to a collector function and execute BODY. If
FROM-END is true the collector will actually be a pusher, (see
MAKE-PUSHER), otherwise NAME will be bound to a collector,
(see MAKE-COLLECTOR)."
(alexandria:with-unique-names (collector)
`(let ((,collector ,(if from-end
`(make-pusher ,initial-value)
`(make-collector ,initial-value))))
`(make-pusher ,initial-value ,collect-nil)
`(make-collector ,initial-value ,collect-nil))))
(flet ((,name (&rest items)
(apply ,collector items)))
,@body))))
Expand Down
31 changes: 30 additions & 1 deletion tests/collectors.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@

(define-test with-collector
(with-collector (test)
(test :a :key)
(test :a nil :key)
(test :and :a)
(test :value :make)
(test :a :plist)
(assert-equal
'(:a nil :key :and :a :value :make :a :plist)
(test)
))
(with-collector (test :collect-nil nil)
(test :a nil :key)
(test :and :a)
(test :value :make)
(test :a :plist)
Expand All @@ -28,6 +37,26 @@
(test)
)))

(define-test with-collector2
(with-collector (test :from-end t)
(test :a nil :key)
(test :and :a)
(test :value :make)
(test :a :plist)
(assert-equal
'(:plist :a :make :value :a :and :key nil :a)
(test)
))
(with-collector (test :from-end t :collect-nil nil)
(test :a nil :key)
(test :and :a)
(test :value :make)
(test :a :plist)
(assert-equal
'(:plist :a :make :value :a :and :key :a)
(test)
)))

(define-test with-appender
(with-appender (test)
(test :a :key)
Expand Down

0 comments on commit 80408c4

Please sign in to comment.