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