リハビリ開始

休み中に Rails アプリを作りたいのですが、まずは Ruby のリハビリから。

問題:Web 上からコンテンツを取得する。ただし更新されていない場合はムダなので持ってこない

回答:

#!/usr/local/bin/ruby -Ke
#
# $Id$
#

require 'time'
require 'net/http'
require 'uri'
require 'fileutils'
require 'tempfile'

Net::HTTP.version_1_2

class HTTPFile

    def initialize(url, path)
        @uri = URI.parse(url)
        @path = path
        @lastupdate = begin
                File.ctime(@path)
            rescue
                nil
            end
    end

    def update?
        return true unless @lastupdate

        Net::HTTP.start(@uri.host, @uri.port) do |http|

            case http.head(@uri.path, {"If-Modified-Since" => @lastupdate.httpdate})
            when Net::HTTPSuccess
                true
            when Net::HTTPNotModified
                false
            else
                raise "unknown HTTP status"
            end
        end
    end

    def get
        Net::HTTP.start(@uri.host, @uri.port) do |http|
            tempfile = Tempfile.open("tmp-" + File.basename(@path), File.dirname(@path))

            open(tempfile.path, "wb") do |f|
                http.get(@uri.path) do |data|
                    f.write data
                end
            end
            FileUtils.install(tempfile.path, @path, {:mode => 0755})

            tempfile.close
        end
    end
end


if __FILE__ == $0
[{:url => 'http://drweb.jp/download/programs/cureit/cureit.exe', :path => 'c:/temp/cureit.exe'},
    {:url => 'http://drweb.jp/feeds/vbase.xml', :path => 'c:/temp/vbase.xml'}].each do |data|
    print data[:url] + " ... "
    httpfile = HTTPFile.new(data[:url], data[:path])
    if httpfile.update?
        puts "modified, so get"
        httpfile.get
    else
        puts "not modified"
    end
end
puts "complete."

end

感想

  • これで簡単な処理なら wget 呼ばなくて済みます。
  • 更新されていないコンテンツを毎回ダウンロードしてしまうムダもなくなります。
  • 恥ずかしながら If-Modified-Since ヘッダの使い方を初めて学びました。