読者です 読者をやめる 読者になる 読者になる

ファイルの監視3

http://d.hatena.ne.jp/walf443/20070302/1172849934
の続き

分かった。Pathnameを使えばもっと幅の広い監視ができそう。おまけに名前も困らない。(とおもったら一文字足りない。pathname-observer) Pathname#entriesを使って新しいファイルが追加されたらとかもできると思う。*1

==> lib/pathname/observer.rb <== 
require 'pathname'
require 'observer'

$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../')))
require 'pathname/observe_manager'

class Pathname
  class Observer
    def initialize(path, &block) 
      @path = Pathname.new(path) 
      unless @path.exist?
        raise ArgumentError
      end

      @proc = block
    end

    def path
      @path
    end

    def update path, result
      if @path.to_s == path.to_s 
        @proc.call(@path.to_s, result)
      end
    end
  end
end

==> lib/pathname/observe_manager.rb <==
require File.join(File.dirname(__FILE__), '../', 'pathname/observer')

class Pathname
  class ObserveManager
    include Observable

    def initialize glob_expr=nil, interval=1, &block
      @interval = interval

      if glob_expr
        add_paths glob_expr, &block
      end
    end

    attr_accessor :interval

    def add_paths glob_expr, &block
      Pathname.glob(glob_expr).each do |pathname|
        add_observer(Pathname::Observer.new(pathname, &block))
      end
    end

    def observe method
      last_result_of = {}
      @observer_peers.each do |observer|
        last_result_of[observer.path.to_s] = observer.path.__send__(method)
      end
      loop do
        begin
          sleep @interval

          current_result_of = {} 
          @observer_peers.each do |observer|
            current_result_of[observer.path.to_s] = observer.path.__send__(method)
          end

          if (temp_touple = current_result_of.select {|key,val| val != last_result_of[key]}).size > 0
            temp_touple.each do |hash|
              changed
              notify_observers(hash.first, hash.last)
            end
            last_result_of = current_result_of
          end
        rescue Interrupt
          return
        rescue Exception
          next
        end
      end
    end
  end
end

if $PROGRAM_NAME == __FILE__
  observe_manager = Pathname::ObserveManager.new('*.txt') {|path, result| puts "#{path} updated on #{result}" }
  observe_manager.observe(:mtime)
end

*1:追記: pathobserverで登録してみた