class Class

  def persist(mode = nil, *ops_files_a)
    ops_files = []
    a = nil
    ops_files_a.each_with_index do |x, i|
      if i % 2 == 0
	a = [x]
      else
	a.push x
	ops_files.push a
      end
    end
    ops = ops_files.collect{|x| x[0]}
    files = ops_files.collect{|x| x[1]}
    case mode
    when "r"
      if y = files.find{|x| !File.file? x}
	$stderr.puts "#{y} is not found."
	exit
      end
      persist_operation(*ops)
      ops_files.each do |op, file|
	load_operation(op, file)
      end
      yield
    when "w"
      if y = files.find{|x| File.file? x}
	$stderr.puts "#{y} already exists."
	exit
      end
      persist_operation(*ops)
      yield
      ops_files.each do |op, file|
	store_operation(op, file)
      end
      yield
    when "u"
      oldfiles = files.find_all{|x| File.file? x}
      newfiles = files - oldfiles
      persist_operation(*ops)
      ops_files.each do |op, file|
	load_operation(op, file) if oldfiles.include? file
      end
      yield
      ops_files.each do |op, file|
	store_operation(op, file) if newfiles.include? file
      end
    end
  end

  def persist_operation(*ops)
    ops.each do |op|
      op, opname = op.is_a?(String) ? [op.intern, op] : [op, op.id2name]
      const = "C__#{op.to_i}__"
      meth = "c__#{op.to_i}__"
      
      evalstr = <<-__END_OF_EVAL__
      class #{name}
	raise '#{const} is already defined.' if defined?(#{const})

        #{const} = {}
	alias #{meth} #{opname}
							 
        def #{opname}(*other)
          if u = #{const}[[self, *other]]
	    r, ar = u
	    if ar
	      if block_given?
		ar.each do |*x|
		  yield *x
		end
	      else
#		raise "has no block"
	      end
	    else
	      raise "has block" if block_given?
	    end
	    r
	  else
	    if block_given?
	      ar = []
	      r = #{meth}(*other) do |*x|
		ar.push x
	        yield *x
	      end
	    else
	      ar = nil
	      r = #{meth}(*other)
	    end
	    #{const}[[self.dup.freeze, *other]]= [r, ar]
	    r
	  end
        end
      end
      __END_OF_EVAL__
      eval(evalstr, TOPLEVEL_BINDING)
    end

    const = "C__\#{op.to_i}__"
    evalstr = <<-__END_OF_EVAL__
    class #{name}
      def self.update_operation(op, h)
	op = op.intern if op.is_a? String
	eval("#{const}").update h
      end

      def self.fetch_operation(op)
	op = op.intern if op.is_a? String
	eval "#{const}"
      end

      def self.store_operation(op, filename)
	Marshal.put(fetch_operation(op), filename)
      end
      
      def self.load_operation(op, filename)
	h = Marshal.get(filename)
	update_operation(op, h)
	h
      end

    end
    __END_OF_EVAL__
    eval(evalstr, TOPLEVEL_BINDING)
  end
end
