This is a very lightweight version of the Ruby library class CSV. That class changed significantly from 1.8 to 1.9 and is a compatibility nightmare. Hence we use our own class.
At construction time you need to specify the data container. This is an Array of Arrays that holds the table. Optionally, you can specify a separator and a quote string for the CSV file.
# File lib/reports/CSVFile.rb, line 27 27: def initialize(data = nil, separator = ';', quote = '"') 28: @data = data 29: raise "Illegal separator: #{separator}" if '."'.include?(separator) 30: @separator = separator 31: raise "Illegal quote: #{separator}" if quote == '.' 32: @quote = quote 33: end
Utility function that tries to convert a String into a native type that is supported by the CSVFile generator. If no native type is found, the input String str will be returned unmodified. nil is returned as nil.
# File lib/reports/CSVFile.rb, line 182 182: def CSVFile.strToNative(str) 183: if str.nil? 184: nil 185: elsif /^[-+]?\d+$/ =~ str 186: # field is a Fixnum 187: str.to_i 188: elsif /^[-+]?\d*\.?\d+([eE][-+]?\d+)?$/ =~ str 189: # field is a Float 190: str.to_f 191: else 192: # Everything else is kept as String 193: str 194: end 195: end
Read the data as Array of Arrays from a CSV formated String str.
# File lib/reports/CSVFile.rb, line 84 84: def parse(str) 85: @data = [] 86: state = :startOfRecord 87: fields = field = quoted = nil 88: 89: # Make sure the input is terminated with a record end. 90: str += "\n" unless str[1] == \n\ 91: 92: str.each_utf8_char do |c| 93: #puts "c: #{c} State: #{state}" 94: case state 95: when :startOfRecord 96: # This will store the fields of a record 97: fields = [] 98: state = :startOfField 99: redo 100: when :startOfField 101: field = '' 102: quoted = false 103: if c == @quote 104: # We've found the start of a quoted field. 105: state = :inQuotedField 106: quoted = true 107: elsif c == @separator || c == "\n" 108: # We've found an empty field 109: field = nil 110: state = :fieldEnd 111: redo 112: else 113: # We've found the first character of an unquoted field 114: field << c 115: state = :inUnquotedField 116: end 117: when :inQuotedField 118: # We are processing the content of a quoted field 119: if c == @quote 120: # This could be then end of the field or a quoted quote. 121: state = :quoteInQuotedField 122: else 123: # We've found a normal character of the quoted field 124: field << c 125: end 126: when :quoteInQuotedField 127: # We are processing a quoted quote or the end of a quoted field 128: if c == @quote 129: # We've found a quoted quote 130: field << c 131: state = :inQuotedField 132: elsif c == @separator || c == "\n" 133: state = :fieldEnd 134: redo 135: else 136: raise "Unexpected character #{c} in CSV" 137: end 138: when :inUnquotedField 139: # We are processing an unquoted field 140: if c == @separator || c == "\n" 141: # We've found the end of a unquoted field 142: state = :fieldEnd 143: redo 144: else 145: # A normal character of an unquoted field 146: field << c 147: end 148: when :fieldEnd 149: # We've completed processing a field. Add the field to the list of 150: # fields. Convert Fixnums and Floats in native types. 151: fields << unMarshal(field, quoted) 152: 153: if c == "\n" 154: # The field end is an end of a record as well. 155: state = :recordEnd 156: redo 157: else 158: # Get the next field. 159: state = :startOfField 160: end 161: when :recordEnd 162: # We've found the end of a record. Add fields to the @data 163: # structure. 164: @data << fields 165: # Look for a new record. 166: state = :startOfRecord 167: else 168: raise "Unknown state #{state}" 169: end 170: end 171: 172: unless state == :startOfRecord 173: raise "CSV state machine error in state #{state}" 174: end 175: 176: @data 177: end
Read the data as Array of Arrays from a CSV formated file fileName. In case ’.’ is used for the fileName the data is read from $stdin.
# File lib/reports/CSVFile.rb, line 51 51: def read(fileName) 52: if (fileName == '.') 53: file = $stdin 54: else 55: file = File.open(fileName, 'r') 56: end 57: 58: @data = parse(file.read) 59: 60: file.close unless fileName == '.' 61: @data 62: end
Convert the CSV data into a CSV formatted String.
# File lib/reports/CSVFile.rb, line 65 65: def to_s 66: s = '' 67: @data.each do |line| 68: first = true 69: line.each do |field| 70: # Don't output a separator before the first field of the line. 71: if first 72: first = false 73: else 74: s << @separator 75: end 76: s << marshal(field) 77: end 78: s << "\n" 79: end 80: s 81: end
Use this function to write the table into a CSV file fileName. ’.’ can be used to write to $stdout.
# File lib/reports/CSVFile.rb, line 37 37: def write(fileName) 38: if (fileName == '.') 39: file = $stdout 40: else 41: file = File.open(fileName, 'w') 42: end 43: 44: file.write(to_s) 45: 46: file.close unless fileName == '.' 47: end
This function is used to properly quote @quote and @separation characters contained in the field.
# File lib/reports/CSVFile.rb, line 201 201: def marshal(field) 202: if field.nil? 203: '' 204: elsif field.is_a?(Fixnum) || field.is_a?(Float) 205: # Numbers don't have to be quoted. 206: field.to_s 207: else 208: # Duplicate quote characters. 209: f = field.gsub(/@quote/, "#{@quote * 2}") 210: # Enclose the field in quote characters 211: @quote + f.to_s + @quote 212: end 213: end
Convert the String field into a native Ruby type. If field was quoted, the result is always the String.
# File lib/reports/CSVFile.rb, line 217 217: def unMarshal(field, quoted) 218: # Quoted Strings and nil are returned verbatim. 219: if quoted || field.nil? 220: field 221: else 222: # Unquoted fields are inspected for special types 223: CSVFile.strToNative(field) 224: end 225: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.