Twitter4R で & や + を含む post を送信できるようにした


Twitter4R 0.3.0 で & や + を含む文字を post できないという問題がありました。

原因を追いかけていくと twitter4r-0.3.0/lib/twitter/ext/stdlib.rb の

# Extension to Hash to create URL encoded string from key-values
class Hash
  # Returns string formatted for HTTP URL encoded name-value pairs.
  # For example,
  #  {:id => 'thomas_hardy'}.to_http_str 
  #  # => "id=thomas_hardy"
  #  {:id => 23423, :since => Time.now}.to_http_str
  #  # => "since=Thu,%2021%20Jun%202007%2012:10:05%20-0500&id=23423"
  def to_http_str
    result = ''
    return result if self.empty?
    self.each do |key, val|
      result << "#{key}=#{URI.encode(val.to_s)}&"
    end
    result.chop # remove the last '&' character, since it can be discarded
  end
end

の中で使われている URI.escape を & や + が通り抜けてしまうのが原因みたい。

irb(main):006:0> URI.encode("&+")
=> "&+"

ふむ。自分は CGI.escape を使うことが多くて、CGI.escapeならば

irb(main):008:0> CGI.escape("&+")
=> "%26%2B"

となって大丈夫そう。リファレンスを確認すると URI.encode でも第二引数を自分で指定すれば良いようだ。

irb(main):005:0> URI.encode("&+", /[^-_.!~*'()a-zA-Z\d;\/?:@=$,\[\]]/n)
=> "%26%2B"

さて、パッチを書くかと思って Contribute のページを見てtrunkを取ってこようとすると

% svn co svn://rubyforge.org/var/svn/twitter4r/trunk twitter4r
svn: URL 'svn://rubyforge.org/var/svn/twitter4r/trunk' は存在しません

気を取り直して Twitter4R Retrospectiva を開くもサーバの応答が無い。というわけで、とりあえずモンキーパッチ。

require 'cgi'
class Hash
  def to_http_str
    self.map{|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
  end
end