Class CSV::StreamBuf
In: lib/csv.rb
Parent: Object

Buffered stream.

EXAMPLE 1 — an IO.

  class MyBuf < StreamBuf
    # Do initialize myself before a super class.  Super class might call my
    # method 'read'. (Could be awful for C++ user. :-)
    def initialize(s)
      @s = s
      super()
    end

    # define my own 'read' method.
    # CAUTION: Returning nil means EnfOfStream.
    def read(size)
      @s.read(size)
    end

    # release buffers. in Ruby which has GC, you do not have to call this...
    def terminate
      @s = nil
      super()
    end
  end

  buf = MyBuf.new(STDIN)
  my_str = ''
  p buf[0, 0]               # => '' (null string)
  p buf[0]                  # => 97 (char code of 'a')
  p buf[0, 1]               # => 'a'
  my_str = buf[0, 5]
  p my_str                  # => 'abcde' (5 chars)
  p buf[0, 6]               # => "abcde\n" (6 chars)
  p buf[0, 7]               # => "abcde\n" (6 chars)
  p buf.drop(3)             # => 3 (dropped chars)
  p buf.get(0, 2)           # => 'de' (2 chars)
  p buf.is_eos?             # => false (is not EOS here)
  p buf.drop(5)             # => 3 (dropped chars)
  p buf.is_eos?             # => true (is EOS here)
  p buf[0]                  # => nil (is EOS here)

EXAMPLE 2 — String.

  This is a conceptual example.  No pros with this.

  class StrBuf < StreamBuf
    def initialize(s)
      @str = s
      @idx = 0
      super()
    end

    def read(size)
      str = @str[@idx, size]
      @idx += str.size
      str
    end
  end

Methods

[]   add_buf   buf_size   drop   get   idx_is_eos?   is_eos?   new   read   rel_buf   terminate  

Constants

BufSize = 1024 * 8

Public Class methods

WARN: Do not instantiate this class directly. Define your own class which derives this class and define ‘read’ instance method.

[Source]

     # File lib/csv.rb, line 888
888:     def initialize
889:       @buf_list = []
890:       @cur_buf = @buf_tail_idx = -1
891:       @offset = 0
892:       @is_eos = false
893:       add_buf
894:       @cur_buf = @buf_tail_idx
895:     end

Public Instance methods

get a char or a partial string from the stream. idx: index of a string to specify a start point of a string to get. unlike String instance, idx < 0 returns nil. n: size of a string to get. returns char at idx if n == nil. returns a partial string, from idx to (idx + n) if n != nil. at EOF, the string size could not equal to arg n.

[Source]

     # File lib/csv.rb, line 803
803:     def [](idx, n = nil) 
804:       if idx < 0
805:         return nil
806:       end
807:       if (idx_is_eos?(idx))
808:         if n and (@offset + idx == buf_size(@cur_buf))
809:           # Like a String, 'abc'[4, 1] returns nil and
810:           # 'abc'[3, 1] returns '' not nil.
811:           return ''
812:         else
813:           return nil
814:         end
815:       end
816:       my_buf = @cur_buf
817:       my_offset = @offset
818:       next_idx = idx
819:       while (my_offset + next_idx >= buf_size(my_buf))
820:         if (my_buf == @buf_tail_idx)
821:           unless add_buf
822:             break
823:           end
824:         end
825:         next_idx = my_offset + next_idx - buf_size(my_buf)
826:         my_buf += 1
827:         my_offset = 0
828:       end
829:       loc = my_offset + next_idx
830:       if !n
831:         return @buf_list[my_buf][loc]           # Fixnum of char code.
832:       elsif (loc + n - 1 < buf_size(my_buf))
833:         return @buf_list[my_buf][loc, n]        # String.
834:       else # should do loop insted of (tail) recursive call...
835:         res = @buf_list[my_buf][loc, BufSize]
836:         size_added = buf_size(my_buf) - loc
837:         if size_added > 0
838:           idx += size_added
839:           n -= size_added
840:           ret = self[idx, n]
841:           if ret
842:             res << ret
843:           end
844:         end
845:         return res
846:       end
847:     end

drop a string from the stream. returns dropped size. at EOF, dropped size might not equals to arg n. Once you drop the head of the stream, access to the dropped part via [] or get returns nil.

[Source]

     # File lib/csv.rb, line 854
854:     def drop(n)
855:       if is_eos?
856:         return 0
857:       end
858:       size_dropped = 0
859:       while (n > 0)
860:         if !@is_eos or (@cur_buf != @buf_tail_idx)
861:           if (@offset + n < buf_size(@cur_buf))
862:             size_dropped += n
863:             @offset += n
864:             n = 0
865:           else
866:             size = buf_size(@cur_buf) - @offset
867:             size_dropped += size
868:             n -= size
869:             @offset = 0
870:             unless rel_buf
871:               unless add_buf
872:                 break
873:               end
874:               @cur_buf = @buf_tail_idx
875:             end
876:           end
877:         end
878:       end
879:       size_dropped
880:     end
get(idx, n = nil)

Alias for #[]

[Source]

     # File lib/csv.rb, line 882
882:     def is_eos?
883:       return idx_is_eos?(0)
884:     end

Protected Instance methods

protected method ‘read’ must be defined in derived classes. CAUTION: Returning a string which size is not equal to ‘size’ means EnfOfStream. When it is not at EOS, you must block the callee, try to read and return the sized string.

[Source]

     # File lib/csv.rb, line 907
907:     def read(size) # raise EOFError
908:       raise NotImplementedError.new('Method read must be defined in a derived class.')
909:     end

[Source]

     # File lib/csv.rb, line 899
899:     def terminate
900:       while (rel_buf); end
901:     end

Private Instance methods

[Source]

     # File lib/csv.rb, line 917
917:     def add_buf
918:       if @is_eos
919:         return false
920:       end
921:       begin
922:         str_read = read(BufSize)
923:       rescue EOFError
924:         str_read = nil
925:       rescue
926:         terminate
927:         raise
928:       end
929:       if str_read.nil?
930:         @is_eos = true
931:         @buf_list.push('')
932:         @buf_tail_idx += 1
933:         false
934:       else
935:         @buf_list.push(str_read)
936:         @buf_tail_idx += 1
937:         true
938:       end
939:     end

[Source]

     # File lib/csv.rb, line 913
913:     def buf_size(idx)
914:       @buf_list[idx].size
915:     end

[Source]

     # File lib/csv.rb, line 955
955:     def idx_is_eos?(idx)
956:       (@is_eos and ((@cur_buf < 0) or (@cur_buf == @buf_tail_idx)))
957:     end

[Source]

     # File lib/csv.rb, line 941
941:     def rel_buf
942:       if (@cur_buf < 0)
943:         return false
944:       end
945:       @buf_list[@cur_buf] = nil
946:       if (@cur_buf == @buf_tail_idx)
947:         @cur_buf = -1
948:         return false
949:       else
950:         @cur_buf += 1
951:         return true
952:       end
953:     end

[Validate]