ChangeLog.new そのに

id:ha-tan:20060212:1139749716を実装してみました。こんな感じかな。get_chunkまわりが美しくないです。この辺を別クラスに切り出すべきかなー。Raccとか使った方がいいかも(でもRaccが必要なほど複雑ってわけでもないし…)。それから、このコードはライブラリというにはネームスペースに無頓着です。例外も適当だし。

#!/usr/bin/env ruby
# -*- ruby -*-

class ChangeLogEntry
  def initialize(date, content)
    @date, @content = date, content
  end
  attr_reader :date, :content

  def to_s
    @content
  end
end

class ChangeLog
  def initialize(filename)
    @date = {}
    @category = {}
    @tmpline = ''
    date = nil
    each_chunk(filename) do |chunk|
      if /^(\d\d\d\d-\d\d-\d\d)/ =~ chunk
        date = $1
        @date[date] ||= []
      else
        entries = @date[date]
        raise "not found date #{date}." unless entries
        entry = ChangeLogEntry.new(date, chunk)
        entries.push entry
        if /^\t\*\s*([^:]*)\s*:/ =~ chunk
          @category[$1] ||= []
          @category[$1].push entry
        end
      end
    end
  end

  def each_chunk(filename)
    open(filename, 'r') do |file|
      while chunk = get_chunk(file)
        yield(chunk)
      end
    end
  end
  private :each_chunk

  def get_chunk(file)
    chunk = @tmpline
    @tmpline = ''
    while line = file.gets
      if /^(?:\d\d\d\d-\d\d-\d\d|\t\*)/ !~ line or chunk.size == 0
        chunk += line
      else
        @tmpline = line
        return chunk
      end
    end
    (chunk.size > 0) ? chunk : nil
  end
  private :get_chunk

  def each_days
    @date.keys.sort.reverse.each do |date|
      yield(date, @date[date])
    end
  end

  def search_by_date(date)
    @date[date]
  end

  def search_by_category(category)
    @category[category]
  end

  def search(re)
    result = []
    each_days do |date, entries|
      entries.each do |entry|
        result.push entry if re =~ entry.content
      end
    end
    result
  end
end

if $0 == __FILE__
  log = ChangeLog.new('ChangeLog')
  puts '######## each_day ########'
  log.each_days do |date, enties|
    puts '----'
    puts date
    enties.each do |entry|
      puts '--'
      puts entry
    end
  end
  
  puts '######## seach_by_date ########'
  log.search_by_date('2006-02-12').each do |entry|
    puts '--'
    puts entry
  end
  
  puts '######## seach_by_category ########'
  log.search_by_category('hoge').each do |entry|
    puts '--'
    puts entry
  end
  
  puts '######## seach ########'
  log.search(/ruby/).each do |entry|
    puts '--'
    puts entry
  end
end