twitter apiを使ったクライアントが、ユーザアイコンなどの情報を子細に表示できるように、1ツイートにはたくさんの情報が詰まっている。Twitter gem のTweetオブジェクトは、1ツイートあたり6KBになることもある。
大量のツイートを処理することを考えると、データを小さく抑える工夫が欲しい。
Tweetオブジェクト
Tweetオブジェクトの正体はただのHashである。twitter gemでは、twitter apiから受け取ったjsonは、ほとんどそのままの状態でTweetオブジェクトにされる。
Twitter::Tweet.new
によって、:id
のキーを持つHashなら、なんでもTweetオブジェクトにすることができる。
t0 = Twitter::Tweet.new({})
#=> KeyError: key not found: :id
t1 = Twitter::Tweet.new({ id: 2.718281828459045235360287471352 })
#=> #<Twitter::Tweet id=2.718281828459045>
Tweetオブジェクトになってしまえば、Twitter::Tweet#methods
に反応することができる。しかし、上述のTweetオブジェクトはほとんど空っぽである。
特定のkeyが存在しない、あるいはfalse, nilのとき、Twitter::NullObject
が返却される。
t1.text
#=> #<Twitter::NullObject:0x80cd77e4>
retweet?,retweeted?,text?,user?
等のメソッドはそれぞれ、特定のkeyに対応する呼び出しの返値がTwitter::NullObject
か否かを判定している。
t1.text? #=> false
t2 = Twitter::Tweet.new({ id: 314, text: :foo })
#=> #<Twitter::Tweet id=314>
t2.text? #=> true
t2.text #=> :foo
軽量化
Tweetオブジェクト(twitter apiのレスポンス)は多様なニーズに応えるよう様々な情報を含めている。だが、ある用途については、それらの情報のほとんどは無駄なものである。したがって、捨ててしまうのがいい。それでいて、twitter gemの用意してくれた快適なメソッド群を(自分が実際に使いたい範囲において)そのまま使えるほうがいい。
「Tweetオブジェクトをto_h
したHashから情報を間引いて、再度Tweetオブジェクトに戻す」という方法が考えられる。
この「間引かれたTweetオブジェクト」では、適切に反応できないメソッドが出てくる。そのため、使用目的にあわせて、残す情報を考えなければならない。「140字の投稿内容」の数百バイトの情報さえあれば、それでいい人も居るだろう。
以下は、text, text?, retweet?, user, user?
等への対応を想定した軽量化の実装である。
class Twitter::Tweet
def downsizing
h = to_h
t = {
id: h[:id],
text: h[:text],
user: {
id: h[:user][:id],
name: h[:user][:name],
screen_name: h[:user][:screen_name],
},
retweeted_status: begin h[:retweeted_status][:id] rescue nil end
}
Twitter::Tweet.new(t)
end
end
元Hashのkey-valueの対応を一部維持していることが、「間引かれたTweetオブジェクト」に対するgemの一部メソッドへの反応を可能にしている。