はてなグラフを試してみた。で,いちいちログインしてデータを入力するのも面倒なので,スクリプトを書こうと思ってヘルプを見たら,はてなグラフ数値登録API の gem があるじゃないか。すばらしい。
早速インストールしてスクリプトを書いた(というかサンプルそのまんま)。
#! ruby -Ku require 'rubygems' require 'hatena/api/graph' graph = Hatena::API::Graph.new('takatoh', 'xxxxxxxx') graph.post('読んだページ数', Time.now, 20)
実行してみるとエラーが……
^o^ >hgpost.rb C:/usr/ruby/lib/ruby/1.8/net/http.rb:560:in `initialize': getaddrinfo: no addres s associated with hostname. (SocketError) from C:/usr/ruby/lib/ruby/1.8/net/http.rb:560:in `open' from C:/usr/ruby/lib/ruby/1.8/net/http.rb:560:in `connect' from C:/usr/ruby/lib/ruby/1.8/timeout.rb:48:in `timeout' (以下略)
えーと,これはあれだ,たぶんプロキシのせいだ。ライブラリのファイル(lib/hatena/api/graph.rb)をのぞいてみると案の定プロキシには対応してないっぽい。とりあえず,べたにプロキシのホスト名とポートを書き足してやるとエラーも出ずちゃんと動いた。
ところが,ブラウザでグラフのページにアクセスしてみると,「読んだページ数」のグラフにデータをポストしたはずなのにそれは更新されず,代わりに「E8AAADE38293E381A0E3839A」という新しいグラフができていた。
これはどういう訳か。ヘルプには
指定されたグラフ名に該当するグラフが存在しない場合はグラフ作成を行った後データ追加、存在する場合は該当日付のデータ上書きを行います。
とある。試しに「TestGraph」というグラフ名でポストしてみるとちゃんと「TestGraph」グラフができていた。どうやら日本語のグラフ名がいけないらしい。文字コードは UTF-8 にしてあるのに。
再度ライブラリをのぞいてみる。グラフ名をリクエストのパラメータに指定するときにエンコードしている(ファイルの29行目,下のコードの2行目)。
params = { :graphname => URI::encode(graphname), :date => date, :value => value, }
もしかしてここか?思い切ってエンコードするのをやめてみたら,おお,うまくいった。
結局,ライブラリファイルを直接書き変えるのはやめて,問題のメソッドを再定義することにした。プロキシは環境変数 http_proxy を参照する。ポストするデータはコマンドラインから指定。ユーザIDやら何やらが直に書いてあるのは単なる手抜き。
#! ruby -Ku require 'rubygems' require 'hatena/api/graph' module Hatena module API class Graph def post(graphname, date, value) value = value.to_f date = date.strftime DATE_FORMAT headers = { 'Access' => 'application/x.atom+xml, application/xml, text/xml, */*', 'X-WSSE' => wsse(@username, @password), } params = { :graphname => graphname, :date => date, :value => value, } res = http_post GRAPH_API_URI, params, headers raise GraphError.new("request not successed: #{res}") if res.code != '201' res end private def http_post(url, params, headers) req = ::Net::HTTP::Post.new(url.path, headers) req.form_data = params req.basic_auth url.user, url.password if url.user proxy_host = nil proxy_port = nil if proxy = ENV['http_proxy'] proxy = URI.parse(proxy) proxy_host = proxy.host proxy_port = proxy.port end ::Net::HTTP.new(url.host, url.port, proxy_host, proxy_port).start {|http| http.request(req) } end end end end graph = Hatena::API::Graph.new('takatoh', 'xxxxxxxx') graph.post('読んだページ数', Time.now, ARGV.shift.to_i)
と,ここまで書いてから気がついたけど,グラフ名はリクエストのパラメータで指定するんだからエンコードするのが正しいんだよな。てことはサービスの側のバグか?
追記:
調べてみたけど,やっぱり hatenaapigraph のバグのようだ。
リクエストオブジェクト(ここでは Net::HTTP::Post)にフォームデータをセットするのは Net::HTTPHeader モジュール(Net::HTTP::Post はこのモジュールを include している)の set_form_data メソッドで,このメソッドは受け取ったデータをエンコードする。だから Hatena::API::Graph の中ではエンコードする必要がない。
# Set header fields and a body from HTML form data. # +params+ should be a Hash containing HTML form data. # Optional argument +sep+ means data record separator. # # This method also set Content-Type: header field to # application/x-www-form-urlencoded. def set_form_data(params, sep = '&') self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep) self.content_type = 'application/x-www-form-urlencoded' end alias form_data= set_form_data
さて,これは何処に報告すればいいのかな。