2008-02-11
■ [biwascheme] JSONPを実装した
動機
twitterクライアントを書きたいので、クライアントのみで行うならJSONPが必要。
JSONP?
普通のAjaxはhtmlと同じドメインにしか接続できないため、twitter.comを見に行けない。
そこで、以下のようなscriptタグを動的に生成する。
<script src="http://twitter.com/statuses/friend_timeline.json?callback=recieve_json"></script>
さらに、受け側となる関数を用意する。
function recieve_json(data){ //dataを利用した処理 }
twitterのサーバは、callback=(関数名)のような引数があると通常のJSONの代わりに以下のようなデータを返す。
recieve_json([{user: "yhara", ...}]);
これはJavaScriptの関数呼び出しになっている。
さてどうするか
Scheme側のAPIを考える。
(print (recieve-jsonp url))
とかやりたいよねw
receive-jsonpが2つ同時に呼ばれなけば、WebScheme.receive_jsonp みたいな受け皿を用意するだけで良さそう。
じゃあ2つ同時に呼ばれたらどうするか。 例えば、イベントハンドラの中にreceive_jsonpがあって、 ボタンが押されるたびに違うURLのJSONPを取りに行くとか。
(add-handler! ($ "run") "click" (print (receive_jsonp (get-content ($ "url")))))
;; ↑ちなみにこれはjquery風に書くとこういう意味だよ ;; $("run").click(function(){ ;; receive_jsonp($("url").text, ;; function(data){ print(data); }); ;; }
これだと、WebScheme.receive_jsonpがどっちの継続を実行したらいいのか分からんくて困る。
案1
関数名を動的に増やす。WebScheme.receive_jsonp_1, WebScheme.receive_jsonp_2 ... みたいに。
いや、WebScheme.jsonp_receiver[0], WebScheme.jsonp_receiver[1], ... でもいいのか。 twitterのJSONPの関数名って記号使えるのかな。
試してみた
「.」も「[」もOK。というわけで案1を採用。うまく動いているようだ。
あとjsonはScheme側から見るとVector+Objectとかで使いにくいので、これをリスト+alistに変換する関数json->sexpを書いた。
■ [biwascheme] BiwaSchemeでtwitterビューアを実装しました
twitter にログイン中であることを確認して、以下のページを開いてみてください。
ソースはこんなかんじ。結構、短くね?
<script src="../lib/biwascheme.js"> ;; access twitter (define (get-timeline type) (json->sexp (receive-jsonp (string-append "http://twitter.com/statuses/" type "_timeline.json")))) ;; class user (define (screen-name-of user) (cadr (assoc "screen_name" user))) ;; class post (define (text-of post) (cadr (assoc "text" post))) (define (date-of post) (parse-date (cadr (assoc "created_at" post)))) (define (user-of post) (cadr (assoc "user" post))) (define (screen-name post) (screen-name-of (user-of post))) (define (describe-post post) (print (date->string (date-of post) "~T") ": " "<" (screen-name post) "> " (text-of post))) (define (reload-timeline) (element-update! ($ "bs-console") "loading...") (let1 timeline (get-timeline "friends") (element-empty! ($ "bs-console")) (for-each describe-post timeline))) (add-handler! ($ "reload") "click" reload-timeline) (reload-timeline) </script>
JSONPなんで、全てクライアント側(BiwaScheme)のみで実装してます。twitter.com以外のサーバには接続してませんよ。
めんどさを軽減するために、srfi-19の時間関係の関数とか、prototype.jsのElement.* の一部を実装した。
IEだけ日付がバグるのは、Date.parse("Mon Feb 11 02:50:33 +0000 2008") が失敗するせい。 そのうち直す。(date->stringは実装したけどstring->dateはまだ^^;)