TwitterのDM送信プログラムを書いてみた

グリーンバンドが届きました!
ほいで、賛同者の方々に住所を聞くDMをがんがん投げたくなったので、自動送信プログラムを書いてみました。もちろんTDDです。

テスト

#! /opt/local/bin/ruby -w
# -*- mode:ruby; coding:utf-8 -*-
require 'dmsender'

$sleep = 0
def sleep(sec)
  $sleep += sec
end

describe DMSender do
  before do
    $sleep   = 0
    @twitter = mock 'twitter4r'
    @log     = mock 'log'
    @sender  = DMSender.new @twitter, @log
  end
  it "はログイン/DM送信をする" do
    @twitter.should_receive(:message).with(:post,"hi","mzp").once
    @log.should_receive(:info).with("sending to mzp")
    @sender.send_message ["mzp"],"hi"
  end

  it "は複数の宛先にメッセージを送る" do
    @twitter.should_receive(:message).
      with(:post,"hi",match(/mzp|nzp/)).
      exactly(2)
    @log.should_receive(:info).
      with(match(/sending to (mzp|nzp)/)).
      exactly(2)
    @sender.send_message ["mzp", "nzp"],"hi"
  end

  it "は送信ごとにsleepする" do
    @twitter.stub!(:message)
    @log.stub!(:info)
    @sender.send_message ["a","b","c"],"hi"
    $sleep.should == DMSender::WaitTime * 3
  end

  it "は本文にerbが使える" do
    @twitter.should_receive(:message).with(:post,"hi, @mzp","mzp").once
    @log.should_receive(:info).with("sending to mzp")
    @sender.send_message ["mzp"],"hi, <%= screen_name %>"
  end

  it "はサーバがエラーを返したら停止する" do
    e= StandardError.new
    @twitter.should_receive(:message).and_raise(e)
    @log.should_receive(:info).with("sending to a")
    @log.should_receive(:error).with("Error: #{e.inspect}")
    @sender.send_message ["a", "b", "c" ],"hi"
  end
end

送信毎にwaitをいれたり、エラーがおきたら中止したりするのはとても重要です。逮捕されちゃうからね。

本体

#! /opt/local/bin/ruby -w
# -*- mode:ruby; coding:utf-8 -*-
require 'erb'

class DMSender
  WaitTime = 2
  def initialize(twitter, logger)
    @twitter = twitter
    @logger  = logger
  end

  def send_message(users, message)
    erb = ERB.new message
    begin
      users.each do|user|
        @logger.info "sending to #{user}"
        screen_name = "@#{user}"
        @twitter.message :post, erb.result(binding), user
        sleep WaitTime
      end
    rescue =>  e
      @logger.error "Error: #{e.inspect}"
    end
  end
end

if __FILE__ == $0
  require "rubygems"
  gem "twitter4r"
  require "twitter"
  require 'logger'

  client = Twitter::Client.new(:login => 'username', :password => 'pass')
  logger = Logger.new STDOUT
  sender = DMSender.new client, logger
  sender.send_message ["mzp"],<<END
hi! <%= screen_name %>
END
end