# File lib/faster_csv.rb, line 1460 def shift ######################################################################### ### This method is purposefully kept a bit long as simple conditional ### ### checks are faster than numerous (expensive) method calls. ### ######################################################################### # handle headers not based on document content if header_row? and @return_headers and [Array, String].include? @use_headers.class if @unconverted_fields return add_unconverted_fields(parse_headers, Array.new) else return parse_headers end end # begin with a blank line, so we can always add to it line = "" # # it can take multiple calls to <tt>@io.gets()</tt> to get a full line, # because of \r and/or \n characters embedded in quoted fields # loop do # add another read to the line line += @io.gets(@row_sep) rescue return nil # copy the line so we can chop it up in parsing parse = line.dup parse.sub!(@parsers[:line_end], "") # # I believe a blank line should be an <tt>Array.new</tt>, not # CSV's <tt>[nil]</tt> # if parse.empty? @lineno += 1 if @skip_blanks line = "" next elsif @unconverted_fields return add_unconverted_fields(Array.new, Array.new) elsif @use_headers return FasterCSV::Row.new(Array.new, Array.new) else return Array.new end end # # shave leading empty fields if needed, because the main parser chokes # on these # csv = if parse.sub!(@parsers[:leading_fields], "") [nil] * ($&.length / @col_sep.length) else Array.new end # # then parse the main fields with a hyper-tuned Regexp from # Mastering Regular Expressions, Second Edition # parse.gsub!(@parsers[:csv_row]) do csv << if $1.nil? # we found an unquoted field if $2.empty? # switch empty unquoted fields to +nil+... nil # for CSV compatibility else # I decided to take a strict approach to CSV parsing... if $2.count("\r\n").zero? # verify correctness of field... $2 else # or throw an Exception raise MalformedCSVError, "Unquoted fields do not allow " + "\\r or \\n (line #{lineno + 1})." end end else # we found a quoted field... $1.gsub('""', '"') # unescape contents end "" # gsub!'s replacement, clear the field end # if parse is empty?(), we found all the fields on the line... if parse.empty? @lineno += 1 # save fields unconverted fields, if needed... unconverted = csv.dup if @unconverted_fields # convert fields, if needed... csv = convert_fields(csv) unless @use_headers or @converters.empty? # parse out header rows and handle FasterCSV::Row conversions... csv = parse_headers(csv) if @use_headers # inject unconverted fields and accessor, if requested... if @unconverted_fields and not csv.respond_to? :unconverted_fields add_unconverted_fields(csv, unconverted) end # return the results break csv end # if we're not empty?() but at eof?(), a quoted field wasn't closed... if @io.eof? raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}." end # otherwise, we need to loop and pull some more data to complete the row end end