はてなブックマーク件数を blog に貼り付けるウィジェット

  ウィジェットというほどのものではないけど,はてなブックマーク件数を簡単に blog に貼り付けることが出来る部品を作ってみました.
  はてなブックマーク件数とは以下の画像の赤枠のようなものです.

  はてなブックマーク件数


  この赤枠の中で囲まれた部品を blog に貼り付けることが出来ます.


  このウィジェットの使い方はとても簡単で

<link rel="stylesheet" type="text/css" href="./styles/hatebu-count.css" />
<script type="text/javascript" src="./js/prototype.js"></script>
<script type="text/javascript" src="./js/hatebu-count.js"></script>


  をヘッダに書いておいて

<p id="hatebu-count"></p>


  id に hatebu-count を持つ要素 (この場合は p) を一つ用意しておくだけ.あとはこれを貼り付けたページのはてなブックマーク件数が
  ここに,表示されます.

  以下,サンプル.このページ (表示されている URI) のはてなブックマーク件数.



  (Ajax を使って非同期で読み込んでいるので,そのうち表示されるはずです)

  動作確認をしたのは,Forefox 1.5.0.1,IE 6.0,Opera 8.2,Netscape 7.1 いずれも Windows 版です.


  このウィジェットを作ったきっかけは,prototype.js を読んでいたら,Ajax.Request に evalJSON なんてメソッドがあって,どうもこれは

X-JSON

  というヘッダに入っている,JSON データを処理してくれるものらしいです.これを見つけて何か作ろうかなと...


  このウィジェットの仕組みは

  まず,ページが読み込まれると Ajax で hatebu-count.cgi を呼び出しています.
  hatebu-count.cgi は何をやるかというと,はてなブックマーク件数取得 API を XML-RPC で取得して JSON で返します.
  あとは,それを表示するだけですね.

  図に示すと以下の通り.

  はてなブックマーク件数を blog に貼り付けるウィジェット

  今回は練習を兼ねて初めて Ruby で書いてみた.XML-RPC ライブラリが標準で入っていたりしてなかなか使いやすかった.
  ちなみに,Ruby 1.8.2 より前に含まれる XML-RPC には脆弱性があるらしいので注意が必要.

  CGI のソースは以下のようになっています.


#!/usr/local/bin/ruby

require 'xmlrpc/client'
require 'cgi'

def print_json(name, count)
    printf "X-JSON: ({'name': '%s', 'count': '%s'})\n\n", name, count
    exit
end

param = CGI.new
print_json('error', 'unkown URI.') if !param['uri']

# クライアントを準備
client = XMLRPC::Client.new('b.hatena.ne.jp', '/xmlrpc')

begin
    # XML-RPC を呼び出し
    result = client.call('bookmark.getCount', param['uri'])
    print_json(param['uri'], result[param['uri']].to_s)
rescue XMLRPC::FaultException => e
    # 例外
    print_json('error', e.faultString)
end


  慣れていないので,変な書き方をしていたら指摘してください.
  ポイントは HTTP ヘッダで X-JSON を投げている点で,これを prototype.js の Ajax.Request が自動的に処理してくれるので楽が出来ます.

  JSON のデータは以下のようにハッシュになっています.

{
    name: URI
    count: ブックマーク件数
}


  JavaScript のソースは以下のようになっています.

var HatebuCount = Class.create();

HatebuCount.prototype = {
    initialize: function(uri) {
        this.doAjax(uri);
    },
    doAjax: function(uri) {
        var url = 'hatebu-count.cgi';
        var param = new Date().getTime() + '&uri=' + encodeURI(uri);
        new Ajax.Request(url, {
            method: 'get',
            parameters: param,
            onComplete: this.doResponse
        });
    },
    doResponse: function(response, json) {
        if (json.name == 'error') return false;
        
        var tag = '';
        if (json.count >= 10) {
            tag = 'strong';
        } else if (json.count >= 5) {
            tag = 'em';
        }
        var anchor = document.createElement('a');
        anchor.setAttribute('href', 'http://b.hatena.ne.jp/entry/' + json.name);
        anchor.setAttribute('target', '_blank');
        
        var text = json.count + ' ' + (json.count > 1 ? 'users' : 'user');
        anchor.appendChild(document.createTextNode(text));
        
        var element;
        // document.createElement('') だと Firefox でうまくいかない
        if (tag == '') {
            element = anchor;
        } else {
            element = document.createElement(tag);
            element.appendChild(anchor);
        }
        $('hatebu-count').appendChild(element);
    }
};

Event.observe(window, 'load', function() {
    new HatebuCount(document.URL);
}, false);


  ポイントは,doResponse でレスポンスといっしょに JSON データが入ってくところ.
  今回の場合は,json.name と json.count に値が入ってきます.
  後は,返ってきた値を,id が hatebu-count な要素に追加しています.

  Ruby をはじめて使ってすごく便利だと感じたのは,CGI のデバッグのときで,

% ruby hatebu-count.cgi

  とやってコンソールで実行すると

(offline mode: enter name=value pairs on standard input)

  このように,name と value の組み合わせを入れなさいと出てくるところ.
  ここに,例えば,

uri=http://www.google.com/
^D

  などと入れると GET のパラメータに値が入って CGI が実行されます.ちなみに,以下がその結果.

X-JSON: ({'name': 'http://www.google.com/', 'count': '16'})

  これは,今回,非常に便利でした.

  最後にソース一式を置いておきます.ライセンスは,Creative Commons 帰属 にします.

- ソース一式 (tar.bz2)
  http://pocari.org/tools/ajax/hatebu-count/hatebu-count.tar.bz2

- Creative Commons 帰属
  http://creativecommons.org/licenses/by/2.1/jp/


- ref.: はてなブックマーク件数取得APIとは
  http://d.hatena.ne.jp/keyword/%a4%cf%a4%c6%a4%ca%a5%d6%a5%c3%a5%af%a5%de%a ...

- ref.: Rubyist Magazine - 標準添付ライブラリ紹介 【第 1 回】 XMLRPC4R
  http://jp.rubyist.net/magazine/?0007-BundledLibraries

- ref.: prototype.js v1.4.0 の使い方
  http://www.imgsrc.co.jp/~kuriyama/prototype/prototype.js.html

- ref.: まちゅダイアリー - JSON + prototype.js
  http://www.machu.jp/diary/20060110.html

- ref.: 2nd life - prototype.js 1.4.0 pre6 でのJSONサポート
  http://d.hatena.ne.jp/secondlife/20050927/1127814722