2007/12/16

Common Lisp で Twitter API をたたいてみる

いまさらながら Twitter を再開しています。
そこで Common Lisp で Twitter API をたたいてみたいと思います。

REST なので Drakma で http-request すればできちゃいます。フォーマットは JSON を指定して、CL-JSON でデコードします。
デコードまでしてしまえば alist のリストが手に入るので、後は煮るなり焼くなり好きなように。なのですが、せっかくの Common Lisp なので無駄に with-selector なんていうマクロを書いて遊んでいます。

次のページを参考にさせていただきました。ありがとうございます。
観測気球さんのTwitter API 仕様書 (勝手に日本語訳シリーズ)
Twitter Development Talk API Documentation

(eval-when (:compile-toplevel :load-toplevel :execute)
(require :drakma)
(require :cl-json))

;; 文字コードは UTF-8 で
(setf drakma:*drakma-default-external-format* :utf-8)

;; ボディを文字列で取得するために、テキストとして判定される Content-Type を追加
(pushnew '("application" . "json") drakma:*text-content-types* :test #'equal)

(defparameter *basic-authorization*
(with-open-file (in (merge-pathnames #p".twitter.lisp" (user-homedir-pathname)))
(read in))
"Basic 認証のパラメータを取得する。~/.twitter.lisp の中身は (\"username\" \"password\")")

(defun public-timeline ()
"public_timeline を取得する。"
(json:decode-json-from-string
(drakma:http-request "http://twitter.com/statuses/public_timeline.json"
:basic-authorization *basic-authorization*)))

(defmacro select (accessor data)
"各フィールドへ assoc でアクセスするマクロ。"
`(reduce #'(lambda (acc key)
`(cdr (assoc ,key ,acc)))
,accessor
:initial-value ,data))

(defmacro with-selector (fields from &body body)
"レスポンスボディの各フィールドへのアクセスマクロ。
(loop for each in (public-timeline)
do (with-selector ((user :user :screen_name)
(text :text))
each
(format t \"~15a ~a~%\" user text)))"

(let ((data (gensym)))
`(let ((,data ,from))
(let ,(mapcar #'(lambda (x)
(list (car x) (select (cdr x) data)))
fields)
,@body))))

;; public_timeline を取ってきてスクリーンネームとテキストを表示する。
(loop for each in (public-timeline)
do (with-selector ((user :user :screen_name)
(text :text))
each
(format t "~15a ~a~%" user text)))

0 件のコメント: