@m_seki の

I like ruby tooから引っ越し

QDBM

OSXでビルドするときは、

make mac; make install-mac

って「mac」が要るのね。ちょっとはまるところだった。

更新モードでopenできるのは一人だけなのかな。更新よりも検索に比重があるんだろうなあ。なのでバッチぽいネタを。MapReduceもどきのミニチュアで素振り。インスタンス変数が一つしかないのか。#なんちゃって関数型?

require 'villa'

class Sink
  def initialize(name)
    @name = name
  end

  def writer(&block)
    open(Villa::OWRITER | Villa::OCREAT, &block)
  end

  def reader(&block)
    open(Villa::OREADER, &block)
  end

  def put(key, value)
    villa.put(key, value, Villa::DDUP)
  end

  def each(&block)
    reader do
      villa.each(&block)
    end
  end

  def reduce
    reader do |v|
      v.curfirst
      yield(v.curkey, v.curval)
    end
  end

  def next_value(key)
    return nil unless villa.curnext
    return nil unless key == villa.curkey
    villa.curval
  end

  def next_key(key)
    while true
      return villa.curkey, villa.curval unless key == villa.curkey
      return nil unless villa.curnext
    end
  end

  private
  def var_name
    "#{self.class}:#{self.object_id}"
  end

  def open(mode)
    Villa::new(@name, mode) do |v|
      v.silent = true
      Thread.current[var_name]  = v
      yield(v)
    end
  ensure
    Thread.current[var_name]  = nil
  end

  def villa
    Thread.current[var_name]
  end
end

def main
  sink = Sink.new('sink.db')
  sink.writer do |v|
    v.clear
  end
  
  sink.writer do
    while s = gets
      s.chomp.scan(/[A-Za-z]+/) do |w|
        sink.put(w, '1')
      end
    end
  end
  
  result = Sink.new('sink2.db')
  
  result.writer do |v|
    v.clear
    sink.reduce do |key, value|
      while key
        count = value.to_i
        while value = sink.next_value(key)
          count += value.to_i
        end
        result.put(key, count.to_s)
        key, value = sink.next_key(key)
      end
    end
  end
  
  result.each do |k, v|
    p [k, v]
  end
end

main