Simple database: Difference between revisions
Content deleted Content added
see also |
|||
Line 24: | Line 24: | ||
See also [[Take notes on the command line]] for a related task. |
See also [[Take notes on the command line]] for a related task. |
||
=={{header|Common Lisp}}== |
|||
a tool to track the episodes you have watched in a series. |
|||
tested with [[SBCL]] but should work with other implementations. |
|||
run from the commandline as: |
|||
sbcl --script watch.lisp |
|||
without arguments the function <code>(watch-list)</code> is invoked to show the last episode of each series. |
|||
with the argument <code>add</code> the function <code>(watch-add)</code> will allow you to add a new episode with series name, episode title, episode number and date watched. if the series does not yet exist you will be asked if you want to create it. |
|||
this code is also available under the GNU GPLv3. |
|||
<lang lisp>(defun make-episode (series title episode date-watched) |
|||
`((series . ,series) (episode . ,episode) (title . ,title) (date . ,date-watched))) |
|||
(defvar db nil) |
|||
(defun dump-db (database) |
|||
(format t "~{~{~a:~10t~a~%~}~%~}" database)) |
|||
(defun print-episode (episode) |
|||
(format t "~30a ~10a ~30a (~{~a~^.~})~%" (cdr (assoc 'series episode)) (cdr (assoc 'episode episode)) (cdr (assoc 'title episode)) (cdr (assoc 'date episode)))) |
|||
(defun get-latest (database) |
|||
(cond ((endp database) nil) |
|||
(T (cons (cadr (assoc 'episodes (cdar database))) (get-latest (cdr database)))))) |
|||
(defun compare-date (a b) |
|||
(cond ((not (and (listp a) (listp b))) nil) |
|||
((null a) (not (null b))) |
|||
((null b) nil) |
|||
((= (first a) (first b)) (compare-date (rest a) (rest b))) |
|||
(t (< (first a) (first b))) )) |
|||
(defun compare-by-date (a b) |
|||
(compare-date (reverse (cdr (assoc 'date a))) (reverse (cdr (assoc 'date b))))) |
|||
(defun watch-list () |
|||
(mapcar #'print-episode (sort (get-latest db) #'compare-by-date))) |
|||
(defun prompt-read (prompt) |
|||
(format *query-io* "~a: " prompt) |
|||
(force-output *query-io*) |
|||
(read-line *query-io*)) |
|||
(defun split (seperator string) |
|||
(loop for i = 0 then (1+ j) |
|||
as j = (search seperator string :start2 i) |
|||
collect (subseq string i j) |
|||
while j)) |
|||
(defun parse-date (date) |
|||
(mapcar #'parse-integer (split "." date))) |
|||
(defun prompt-for-episode () |
|||
(make-episode |
|||
(prompt-read "Series") |
|||
(prompt-read "Title") |
|||
(prompt-read "Episode") |
|||
(parse-date (prompt-read "Date watched")))) |
|||
(defun add-episodes () |
|||
(loop (push (prompt-for-episode) db) |
|||
(if (not (y-or-n-p "Another? [y/n]: ")) (return)))) |
|||
(defun save-db (filename database) |
|||
(with-open-file (out filename |
|||
:direction :output |
|||
:if-exists :supersede) |
|||
(with-standard-io-syntax |
|||
(pprint database out)))) |
|||
(defun watch-save () |
|||
(save-db "lwatch" db)) |
|||
(defun load-db (filename database) |
|||
(with-open-file (in filename) |
|||
(with-standard-io-syntax |
|||
(setf database (read in))))) |
|||
(defun has-series (name list) |
|||
(assoc name list :test #'equal)) |
|||
(defun get-series (name list) |
|||
(cdr (assoc name list :test #'equal))) |
|||
(defun get-episode-list (series list) |
|||
(cdr (assoc 'episodes (get-series series list)))) |
|||
(defun watch-add-series (name status) |
|||
(cdar (push `(,name (series . ,name) (status . ,status) (episodes)) db))) |
|||
(defun get-or-add-series (name database) |
|||
(or (get-series name database) |
|||
(if (y-or-n-p "Add new series? [y/n]: ") |
|||
(watch-add-series name 'active) nil))) |
|||
(defun watch-add () |
|||
(let* ((episode (prompt-for-episode)) |
|||
(series-name (cdr (assoc 'series episode))) |
|||
(series (get-or-add-series series-name db))) |
|||
(if (endp series) (watch-add) |
|||
(rplacd (assoc 'episodes series) |
|||
(cons episode (get-episode-list series-name db)))))) |
|||
(defun watch-load () |
|||
(with-open-file (in "lwatch") (with-standard-io-syntax (setf db (read in))))) |
|||
(defun argv () |
|||
(or |
|||
#+clisp (ext:argv) |
|||
#+sbcl sb-ext:*posix-argv* |
|||
#+clozure (ccl::command-line-arguments) |
|||
#+gcl si:*command-args* |
|||
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i)) |
|||
#+cmu extensions:*command-line-strings* |
|||
#+allegro (sys:command-line-arguments) |
|||
#+lispworks sys:*line-arguments-list* |
|||
nil)) |
|||
(defun main (argv) |
|||
(watch-load) |
|||
(cond ((equal (cadr argv) "add") (watch-add) (watch-save)) |
|||
(T (watch-list)))) |
|||
(main (argv))</lang> |
|||
=={{header|UNIX Shell}}== |
=={{header|UNIX Shell}}== |
||
This format is guaranteed to be human readable: if you can type it, you can read it. |
This format is guaranteed to be human readable: if you can type it, you can read it. |