csv 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/csv.rb +162 -188
- metadata +5 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ad2099f5d8d905cf648927ecbcd076c0725ecf62
         | 
| 4 | 
            +
              data.tar.gz: ae7361c59a7f61e93e4264b630966edbec9f8c5b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: dac41f73ab3bd16409e90e03d5983d5553d190c4c361361af015dfe2b85973a8219f14114552115a5ad31667e3a37280c243b5a6a5c86801c8f4250f1146a3ad
         | 
| 7 | 
            +
              data.tar.gz: 309bca2a3dcdd805c9a45e83283c8ac878af4e0156277ac801d86848aeb7892228ccb7fb9adfd4845579d22d7bd51c39ab8e620e97211ec229b89828eaa2af21
         | 
    
        data/lib/csv.rb
    CHANGED
    
    | @@ -242,7 +242,7 @@ class CSV | |
| 242 242 | 
             
                  @row = if headers.size >= fields.size
         | 
| 243 243 | 
             
                    headers.zip(fields)
         | 
| 244 244 | 
             
                  else
         | 
| 245 | 
            -
                    fields.zip(headers). | 
| 245 | 
            +
                    fields.zip(headers).each(&:reverse!)
         | 
| 246 246 | 
             
                  end
         | 
| 247 247 | 
             
                end
         | 
| 248 248 |  | 
| @@ -267,7 +267,7 @@ class CSV | |
| 267 267 |  | 
| 268 268 | 
             
                # Returns the headers of this row.
         | 
| 269 269 | 
             
                def headers
         | 
| 270 | 
            -
                  @row.map | 
| 270 | 
            +
                  @row.map(&:first)
         | 
| 271 271 | 
             
                end
         | 
| 272 272 |  | 
| 273 273 | 
             
                #
         | 
| @@ -451,21 +451,23 @@ class CSV | |
| 451 451 | 
             
                #
         | 
| 452 452 | 
             
                def fields(*headers_and_or_indices)
         | 
| 453 453 | 
             
                  if headers_and_or_indices.empty?  # return all fields--no arguments
         | 
| 454 | 
            -
                    @row.map | 
| 454 | 
            +
                    @row.map(&:last)
         | 
| 455 455 | 
             
                  else                              # or work like values_at()
         | 
| 456 | 
            -
                     | 
| 457 | 
            -
             | 
| 456 | 
            +
                    all = []
         | 
| 457 | 
            +
                    headers_and_or_indices.each do |h_or_i|
         | 
| 458 | 
            +
                      if h_or_i.is_a? Range
         | 
| 458 459 | 
             
                        index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :
         | 
| 459 460 | 
             
                                                                    index(h_or_i.begin)
         | 
| 460 461 | 
             
                        index_end   = h_or_i.end.is_a?(Integer)   ? h_or_i.end :
         | 
| 461 462 | 
             
                                                                    index(h_or_i.end)
         | 
| 462 463 | 
             
                        new_range   = h_or_i.exclude_end? ? (index_begin...index_end) :
         | 
| 463 464 | 
             
                                                            (index_begin..index_end)
         | 
| 464 | 
            -
                        fields.values_at(new_range)
         | 
| 465 | 
            +
                        all.concat(fields.values_at(new_range))
         | 
| 465 466 | 
             
                      else
         | 
| 466 | 
            -
                         | 
| 467 | 
            +
                        all << field(*Array(h_or_i))
         | 
| 467 468 | 
             
                      end
         | 
| 468 469 | 
             
                    end
         | 
| 470 | 
            +
                    return all
         | 
| 469 471 | 
             
                  end
         | 
| 470 472 | 
             
                end
         | 
| 471 473 | 
             
                alias_method :values_at, :fields
         | 
| @@ -532,8 +534,7 @@ class CSV | |
| 532 534 | 
             
                # order and clobbers duplicate fields.
         | 
| 533 535 | 
             
                #
         | 
| 534 536 | 
             
                def to_hash
         | 
| 535 | 
            -
                   | 
| 536 | 
            -
                  Hash[*@row.inject(Array.new) { |ary, pair| ary.push(*pair) }]
         | 
| 537 | 
            +
                  @row.to_h
         | 
| 537 538 | 
             
                end
         | 
| 538 539 |  | 
| 539 540 | 
             
                #
         | 
| @@ -541,7 +542,7 @@ class CSV | |
| 541 542 | 
             
                #
         | 
| 542 543 | 
             
                #   csv_row.fields.to_csv( options )
         | 
| 543 544 | 
             
                #
         | 
| 544 | 
            -
                def to_csv(options | 
| 545 | 
            +
                def to_csv(**options)
         | 
| 545 546 | 
             
                  fields.to_csv(options)
         | 
| 546 547 | 
             
                end
         | 
| 547 548 | 
             
                alias_method :to_s, :to_csv
         | 
| @@ -836,11 +837,10 @@ class CSV | |
| 836 837 | 
             
                  if @mode == :row or @mode == :col_or_row  # by index
         | 
| 837 838 | 
             
                    @table.delete_if(&block)
         | 
| 838 839 | 
             
                  else                                      # by header
         | 
| 839 | 
            -
                     | 
| 840 | 
            -
                    headers. | 
| 841 | 
            -
                       | 
| 840 | 
            +
                    deleted = []
         | 
| 841 | 
            +
                    headers.each do |header|
         | 
| 842 | 
            +
                      deleted << delete(header) if block[[header, self[header]]]
         | 
| 842 843 | 
             
                    end
         | 
| 843 | 
            -
                    to_delete.map { |header| delete(header) }
         | 
| 844 844 | 
             
                  end
         | 
| 845 845 |  | 
| 846 846 | 
             
                  self  # for chaining
         | 
| @@ -871,7 +871,8 @@ class CSV | |
| 871 871 |  | 
| 872 872 | 
             
                # Returns +true+ if all rows of this table ==() +other+'s rows.
         | 
| 873 873 | 
             
                def ==(other)
         | 
| 874 | 
            -
                  @table == other.table
         | 
| 874 | 
            +
                  return @table == other.table if other.is_a? CSV::Table
         | 
| 875 | 
            +
                  @table == other
         | 
| 875 876 | 
             
                end
         | 
| 876 877 |  | 
| 877 878 | 
             
                #
         | 
| @@ -879,13 +880,11 @@ class CSV | |
| 879 880 | 
             
                # then all of the field rows will follow.
         | 
| 880 881 | 
             
                #
         | 
| 881 882 | 
             
                def to_a
         | 
| 882 | 
            -
                   | 
| 883 | 
            -
             | 
| 884 | 
            -
             | 
| 885 | 
            -
                    else
         | 
| 886 | 
            -
                      array + [row.fields]
         | 
| 887 | 
            -
                    end
         | 
| 883 | 
            +
                  array = [headers]
         | 
| 884 | 
            +
                  @table.each do |row|
         | 
| 885 | 
            +
                    array.push(row.fields) unless row.header_row?
         | 
| 888 886 | 
             
                  end
         | 
| 887 | 
            +
                  return array
         | 
| 889 888 | 
             
                end
         | 
| 890 889 |  | 
| 891 890 | 
             
                #
         | 
| @@ -895,15 +894,12 @@ class CSV | |
| 895 894 | 
             
                # This method assumes you want the Table.headers(), unless you explicitly
         | 
| 896 895 | 
             
                # pass <tt>:write_headers => false</tt>.
         | 
| 897 896 | 
             
                #
         | 
| 898 | 
            -
                def to_csv( | 
| 899 | 
            -
                   | 
| 900 | 
            -
                  @table. | 
| 901 | 
            -
                     | 
| 902 | 
            -
             | 
| 903 | 
            -
             | 
| 904 | 
            -
                      rows + [row.fields.to_csv(options)]
         | 
| 905 | 
            -
                    end
         | 
| 906 | 
            -
                  end.join('')
         | 
| 897 | 
            +
                def to_csv(write_headers: true, **options)
         | 
| 898 | 
            +
                  array = write_headers ? [headers.to_csv(options)] : []
         | 
| 899 | 
            +
                  @table.each do |row|
         | 
| 900 | 
            +
                    array.push(row.fields.to_csv(options)) unless row.header_row?
         | 
| 901 | 
            +
                  end
         | 
| 902 | 
            +
                  return array.join('')
         | 
| 907 903 | 
             
                end
         | 
| 908 904 | 
             
                alias_method :to_s, :to_csv
         | 
| 909 905 |  | 
| @@ -1014,8 +1010,8 @@ class CSV | |
| 1014 1010 | 
             
              HeaderConverters = {
         | 
| 1015 1011 | 
             
                downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
         | 
| 1016 1012 | 
             
                symbol:   lambda { |h|
         | 
| 1017 | 
            -
                  h.encode(ConverterEncoding).downcase. | 
| 1018 | 
            -
             | 
| 1013 | 
            +
                  h.encode(ConverterEncoding).downcase.gsub(/[^\s\w]+/, "").strip.
         | 
| 1014 | 
            +
                                                       gsub(/\s+/, "_").to_sym
         | 
| 1019 1015 | 
             
                }
         | 
| 1020 1016 | 
             
              }
         | 
| 1021 1017 |  | 
| @@ -1061,14 +1057,14 @@ class CSV | |
| 1061 1057 | 
             
              # If a block is given, the instance is passed to the block and the return
         | 
| 1062 1058 | 
             
              # value becomes the return value of the block.
         | 
| 1063 1059 | 
             
              #
         | 
| 1064 | 
            -
              def self.instance(data = $stdout, options | 
| 1060 | 
            +
              def self.instance(data = $stdout, **options)
         | 
| 1065 1061 | 
             
                # create a _signature_ for this method call, data object and options
         | 
| 1066 1062 | 
             
                sig = [data.object_id] +
         | 
| 1067 1063 | 
             
                      options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
         | 
| 1068 1064 |  | 
| 1069 1065 | 
             
                # fetch or create the instance for this signature
         | 
| 1070 1066 | 
             
                @@instances ||= Hash.new
         | 
| 1071 | 
            -
                instance | 
| 1067 | 
            +
                instance = (@@instances[sig] ||= new(data, options))
         | 
| 1072 1068 |  | 
| 1073 1069 | 
             
                if block_given?
         | 
| 1074 1070 | 
             
                  yield instance  # run block, if given, returning result
         | 
| @@ -1079,9 +1075,9 @@ class CSV | |
| 1079 1075 |  | 
| 1080 1076 | 
             
              #
         | 
| 1081 1077 | 
             
              # :call-seq:
         | 
| 1082 | 
            -
              #   filter( options  | 
| 1083 | 
            -
              #   filter( input, options  | 
| 1084 | 
            -
              #   filter( input, output, options  | 
| 1078 | 
            +
              #   filter( **options ) { |row| ... }
         | 
| 1079 | 
            +
              #   filter( input, **options ) { |row| ... }
         | 
| 1080 | 
            +
              #   filter( input, output, **options ) { |row| ... }
         | 
| 1085 1081 | 
             
              #
         | 
| 1086 1082 | 
             
              # This method is a convenience for building Unix-like filters for CSV data.
         | 
| 1087 1083 | 
             
              # Each row is yielded to the provided block which can alter it as needed.
         | 
| @@ -1101,25 +1097,23 @@ class CSV | |
| 1101 1097 | 
             
              # The <tt>:output_row_sep</tt> +option+ defaults to
         | 
| 1102 1098 | 
             
              # <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
         | 
| 1103 1099 | 
             
              #
         | 
| 1104 | 
            -
              def self.filter( | 
| 1100 | 
            +
              def self.filter(input=nil, output=nil, **options)
         | 
| 1105 1101 | 
             
                # parse options for input, output, or both
         | 
| 1106 1102 | 
             
                in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
         | 
| 1107 | 
            -
                 | 
| 1108 | 
            -
                   | 
| 1109 | 
            -
             | 
| 1110 | 
            -
                     | 
| 1111 | 
            -
             | 
| 1112 | 
            -
                     | 
| 1113 | 
            -
             | 
| 1114 | 
            -
                     | 
| 1115 | 
            -
             | 
| 1116 | 
            -
                      out_options[key] = value
         | 
| 1117 | 
            -
                    end
         | 
| 1103 | 
            +
                options.each do |key, value|
         | 
| 1104 | 
            +
                  case key.to_s
         | 
| 1105 | 
            +
                  when /\Ain(?:put)?_(.+)\Z/
         | 
| 1106 | 
            +
                    in_options[$1.to_sym] = value
         | 
| 1107 | 
            +
                  when /\Aout(?:put)?_(.+)\Z/
         | 
| 1108 | 
            +
                    out_options[$1.to_sym] = value
         | 
| 1109 | 
            +
                  else
         | 
| 1110 | 
            +
                    in_options[key]  = value
         | 
| 1111 | 
            +
                    out_options[key] = value
         | 
| 1118 1112 | 
             
                  end
         | 
| 1119 1113 | 
             
                end
         | 
| 1120 1114 | 
             
                # build input and output wrappers
         | 
| 1121 | 
            -
                input  = new( | 
| 1122 | 
            -
                output = new( | 
| 1115 | 
            +
                input  = new(input  || ARGF,    in_options)
         | 
| 1116 | 
            +
                output = new(output || $stdout, out_options)
         | 
| 1123 1117 |  | 
| 1124 1118 | 
             
                # read, yield, write
         | 
| 1125 1119 | 
             
                input.each do |row|
         | 
| @@ -1142,7 +1136,7 @@ class CSV | |
| 1142 1136 | 
             
              # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
         | 
| 1143 1137 | 
             
              # but transcode it to UTF-8 before CSV parses it.
         | 
| 1144 1138 | 
             
              #
         | 
| 1145 | 
            -
              def self.foreach(path, options | 
| 1139 | 
            +
              def self.foreach(path, **options, &block)
         | 
| 1146 1140 | 
             
                return to_enum(__method__, path, options) unless block
         | 
| 1147 1141 | 
             
                open(path, options) do |csv|
         | 
| 1148 1142 | 
             
                  csv.each(&block)
         | 
| @@ -1151,8 +1145,8 @@ class CSV | |
| 1151 1145 |  | 
| 1152 1146 | 
             
              #
         | 
| 1153 1147 | 
             
              # :call-seq:
         | 
| 1154 | 
            -
              #   generate( str, options  | 
| 1155 | 
            -
              #   generate( options  | 
| 1148 | 
            +
              #   generate( str, **options ) { |csv| ... }
         | 
| 1149 | 
            +
              #   generate( **options ) { |csv| ... }
         | 
| 1156 1150 | 
             
              #
         | 
| 1157 1151 | 
             
              # This method wraps a String you provide, or an empty default String, in a
         | 
| 1158 1152 | 
             
              # CSV object which is passed to the provided block.  You can use the block to
         | 
| @@ -1167,19 +1161,17 @@ class CSV | |
| 1167 1161 | 
             
              # String to set the base Encoding for the output.  CSV needs this hint if you
         | 
| 1168 1162 | 
             
              # plan to output non-ASCII compatible data.
         | 
| 1169 1163 | 
             
              #
         | 
| 1170 | 
            -
              def self.generate( | 
| 1164 | 
            +
              def self.generate(str=nil, **options)
         | 
| 1171 1165 | 
             
                # add a default empty String, if none was given
         | 
| 1172 | 
            -
                if  | 
| 1173 | 
            -
                  io = StringIO.new( | 
| 1166 | 
            +
                if str
         | 
| 1167 | 
            +
                  io = StringIO.new(str)
         | 
| 1174 1168 | 
             
                  io.seek(0, IO::SEEK_END)
         | 
| 1175 | 
            -
                  args.unshift(io)
         | 
| 1176 1169 | 
             
                else
         | 
| 1177 | 
            -
                  encoding =  | 
| 1170 | 
            +
                  encoding = options[:encoding]
         | 
| 1178 1171 | 
             
                  str      = String.new
         | 
| 1179 1172 | 
             
                  str.force_encoding(encoding) if encoding
         | 
| 1180 | 
            -
                  args.unshift(str)
         | 
| 1181 1173 | 
             
                end
         | 
| 1182 | 
            -
                csv = new( | 
| 1174 | 
            +
                csv = new(str, options) # wrap
         | 
| 1183 1175 | 
             
                yield csv         # yield for appending
         | 
| 1184 1176 | 
             
                csv.string        # return final String
         | 
| 1185 1177 | 
             
              end
         | 
| @@ -1197,12 +1189,11 @@ class CSV | |
| 1197 1189 | 
             
              # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
         | 
| 1198 1190 | 
             
              # (<tt>$/</tt>) when calling this method.
         | 
| 1199 1191 | 
             
              #
         | 
| 1200 | 
            -
              def self.generate_line(row, options | 
| 1201 | 
            -
                options | 
| 1202 | 
            -
                 | 
| 1203 | 
            -
                 | 
| 1204 | 
            -
             | 
| 1205 | 
            -
                  str.force_encoding(encoding)
         | 
| 1192 | 
            +
              def self.generate_line(row, **options)
         | 
| 1193 | 
            +
                options = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
         | 
| 1194 | 
            +
                str = String.new
         | 
| 1195 | 
            +
                if options[:encoding]
         | 
| 1196 | 
            +
                  str.force_encoding(options[:encoding])
         | 
| 1206 1197 | 
             
                elsif field = row.find { |f| not f.nil? }
         | 
| 1207 1198 | 
             
                  str.force_encoding(String(field).encoding)
         | 
| 1208 1199 | 
             
                end
         | 
| @@ -1211,10 +1202,10 @@ class CSV | |
| 1211 1202 |  | 
| 1212 1203 | 
             
              #
         | 
| 1213 1204 | 
             
              # :call-seq:
         | 
| 1214 | 
            -
              #   open( filename, mode = "rb", options  | 
| 1215 | 
            -
              #   open( filename, options  | 
| 1216 | 
            -
              #   open( filename, mode = "rb", options  | 
| 1217 | 
            -
              #   open( filename, options  | 
| 1205 | 
            +
              #   open( filename, mode = "rb", **options ) { |faster_csv| ... }
         | 
| 1206 | 
            +
              #   open( filename, **options ) { |faster_csv| ... }
         | 
| 1207 | 
            +
              #   open( filename, mode = "rb", **options )
         | 
| 1208 | 
            +
              #   open( filename, **options )
         | 
| 1218 1209 | 
             
              #
         | 
| 1219 1210 | 
             
              # This method opens an IO object, and wraps that with CSV.  This is intended
         | 
| 1220 1211 | 
             
              # as the primary interface for writing a CSV file.
         | 
| @@ -1272,17 +1263,16 @@ class CSV | |
| 1272 1263 | 
             
              # * truncate()
         | 
| 1273 1264 | 
             
              # * tty?()
         | 
| 1274 1265 | 
             
              #
         | 
| 1275 | 
            -
              def self.open( | 
| 1276 | 
            -
                # find the +options+ Hash
         | 
| 1277 | 
            -
                options = if args.last.is_a? Hash then args.pop else Hash.new end
         | 
| 1266 | 
            +
              def self.open(filename, mode="r", **options)
         | 
| 1278 1267 | 
             
                # wrap a File opened with the remaining +args+ with no newline
         | 
| 1279 1268 | 
             
                # decorator
         | 
| 1280 1269 | 
             
                file_opts = {universal_newline: false}.merge(options)
         | 
| 1270 | 
            +
             | 
| 1281 1271 | 
             
                begin
         | 
| 1282 | 
            -
                  f = File.open( | 
| 1272 | 
            +
                  f = File.open(filename, mode, file_opts)
         | 
| 1283 1273 | 
             
                rescue ArgumentError => e
         | 
| 1284 | 
            -
                  raise unless /needs binmode/ =~ e.message and  | 
| 1285 | 
            -
                   | 
| 1274 | 
            +
                  raise unless /needs binmode/ =~ e.message and mode == "r"
         | 
| 1275 | 
            +
                  mode = "rb"
         | 
| 1286 1276 | 
             
                  file_opts = {encoding: Encoding.default_external}.merge(file_opts)
         | 
| 1287 1277 | 
             
                  retry
         | 
| 1288 1278 | 
             
                end
         | 
| @@ -1307,14 +1297,14 @@ class CSV | |
| 1307 1297 |  | 
| 1308 1298 | 
             
              #
         | 
| 1309 1299 | 
             
              # :call-seq:
         | 
| 1310 | 
            -
              #   parse( str, options  | 
| 1311 | 
            -
              #   parse( str, options  | 
| 1300 | 
            +
              #   parse( str, **options ) { |row| ... }
         | 
| 1301 | 
            +
              #   parse( str, **options )
         | 
| 1312 1302 | 
             
              #
         | 
| 1313 1303 | 
             
              # This method can be used to easily parse CSV out of a String.  You may either
         | 
| 1314 1304 | 
             
              # provide a +block+ which will be called with each row of the String in turn,
         | 
| 1315 1305 | 
             
              # or just use the returned Array of Arrays (when no +block+ is given).
         | 
| 1316 1306 | 
             
              #
         | 
| 1317 | 
            -
              # You pass your +str+ to read from, and an optional +options+  | 
| 1307 | 
            +
              # You pass your +str+ to read from, and an optional +options+ containing
         | 
| 1318 1308 | 
             
              # anything CSV::new() understands.
         | 
| 1319 1309 | 
             
              #
         | 
| 1320 1310 | 
             
              def self.parse(*args, &block)
         | 
| @@ -1337,7 +1327,7 @@ class CSV | |
| 1337 1327 | 
             
              #
         | 
| 1338 1328 | 
             
              # The +options+ parameter can be anything CSV::new() understands.
         | 
| 1339 1329 | 
             
              #
         | 
| 1340 | 
            -
              def self.parse_line(line, options | 
| 1330 | 
            +
              def self.parse_line(line, **options)
         | 
| 1341 1331 | 
             
                new(line, options).shift
         | 
| 1342 1332 | 
             
              end
         | 
| 1343 1333 |  | 
| @@ -1368,7 +1358,7 @@ class CSV | |
| 1368 1358 | 
             
              #                     converters:        :numeric,
         | 
| 1369 1359 | 
             
              #                     header_converters: :symbol }.merge(options) )
         | 
| 1370 1360 | 
             
              #
         | 
| 1371 | 
            -
              def self.table(path, options | 
| 1361 | 
            +
              def self.table(path, **options)
         | 
| 1372 1362 | 
             
                read( path, { headers:           true,
         | 
| 1373 1363 | 
             
                              converters:        :numeric,
         | 
| 1374 1364 | 
             
                              header_converters: :symbol }.merge(options) )
         | 
| @@ -1526,51 +1516,55 @@ class CSV | |
| 1526 1516 | 
             
              # Options cannot be overridden in the instance methods for performance reasons,
         | 
| 1527 1517 | 
             
              # so be sure to set what you want here.
         | 
| 1528 1518 | 
             
              #
         | 
| 1529 | 
            -
              def initialize(data,  | 
| 1530 | 
            -
             | 
| 1531 | 
            -
             | 
| 1532 | 
            -
             | 
| 1533 | 
            -
             | 
| 1534 | 
            -
                # build the options for this read/write
         | 
| 1535 | 
            -
                options = DEFAULT_OPTIONS.merge(options)
         | 
| 1519 | 
            +
              def initialize(data, col_sep: ",", row_sep: :auto, quote_char: '"', field_size_limit:   nil,
         | 
| 1520 | 
            +
                             converters: nil, unconverted_fields: nil, headers: false, return_headers: false,
         | 
| 1521 | 
            +
                             write_headers: nil, header_converters: nil, skip_blanks: false, force_quotes: false,
         | 
| 1522 | 
            +
                             skip_lines: nil, liberal_parsing: false, internal_encoding: nil, external_encoding: nil, encoding: nil)
         | 
| 1523 | 
            +
                raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?
         | 
| 1536 1524 |  | 
| 1537 1525 | 
             
                # create the IO object we will read from
         | 
| 1538 | 
            -
                @io | 
| 1526 | 
            +
                @io = data.is_a?(String) ? StringIO.new(data) : data
         | 
| 1539 1527 | 
             
                # honor the IO encoding if we can, otherwise default to ASCII-8BIT
         | 
| 1540 | 
            -
                 | 
| 1541 | 
            -
             | 
| 1542 | 
            -
             | 
| 1543 | 
            -
             | 
| 1544 | 
            -
             | 
| 1545 | 
            -
             | 
| 1546 | 
            -
             | 
| 1547 | 
            -
                            ( case encoding = options.delete(:encoding)
         | 
| 1548 | 
            -
                              when Encoding; encoding
         | 
| 1549 | 
            -
                              when /\A[^:]+/; Encoding.find($&)
         | 
| 1550 | 
            -
                              end ) ||
         | 
| 1528 | 
            +
                internal_encoding = Encoding.find(internal_encoding) if internal_encoding
         | 
| 1529 | 
            +
                external_encoding = Encoding.find(external_encoding) if external_encoding
         | 
| 1530 | 
            +
                if encoding
         | 
| 1531 | 
            +
                  encoding, = encoding.split(":", 2) if encoding.is_a?(String)
         | 
| 1532 | 
            +
                  encoding = Encoding.find(encoding)
         | 
| 1533 | 
            +
                end
         | 
| 1534 | 
            +
                @encoding = raw_encoding(nil) || internal_encoding || encoding ||
         | 
| 1551 1535 | 
             
                            Encoding.default_internal || Encoding.default_external
         | 
| 1552 1536 | 
             
                #
         | 
| 1553 1537 | 
             
                # prepare for building safe regular expressions in the target encoding,
         | 
| 1554 1538 | 
             
                # if we can transcode the needed characters
         | 
| 1555 1539 | 
             
                #
         | 
| 1556 | 
            -
                @re_esc   = | 
| 1557 | 
            -
                @re_chars = | 
| 1540 | 
            +
                @re_esc   = "\\".encode(@encoding).freeze rescue ""
         | 
| 1541 | 
            +
                @re_chars = /#{%"[-\\]\\[\\.^$?*+{}()|# \r\n\t\f\v]".encode(@encoding)}/
         | 
| 1542 | 
            +
                @unconverted_fields = unconverted_fields
         | 
| 1558 1543 |  | 
| 1559 | 
            -
                 | 
| 1560 | 
            -
                 | 
| 1561 | 
            -
                 | 
| 1562 | 
            -
                 | 
| 1563 | 
            -
                init_comments(options)
         | 
| 1544 | 
            +
                # Stores header row settings and loads header converters, if needed.
         | 
| 1545 | 
            +
                @use_headers    = headers
         | 
| 1546 | 
            +
                @return_headers = return_headers
         | 
| 1547 | 
            +
                @write_headers  = write_headers
         | 
| 1564 1548 |  | 
| 1565 | 
            -
                 | 
| 1566 | 
            -
                 | 
| 1567 | 
            -
             | 
| 1568 | 
            -
                 | 
| 1569 | 
            -
             | 
| 1570 | 
            -
                 | 
| 1549 | 
            +
                # headers must be delayed until shift(), in case they need a row of content
         | 
| 1550 | 
            +
                @headers = nil
         | 
| 1551 | 
            +
             | 
| 1552 | 
            +
                init_separators(col_sep, row_sep, quote_char, force_quotes)
         | 
| 1553 | 
            +
                init_parsers(skip_blanks, field_size_limit, liberal_parsing)
         | 
| 1554 | 
            +
                init_converters(converters, :@converters, :convert)
         | 
| 1555 | 
            +
                init_converters(header_converters, :@header_converters, :header_convert)
         | 
| 1556 | 
            +
                init_comments(skip_lines)
         | 
| 1557 | 
            +
             | 
| 1558 | 
            +
                @force_encoding = !!encoding
         | 
| 1571 1559 |  | 
| 1572 1560 | 
             
                # track our own lineno since IO gets confused about line-ends is CSV fields
         | 
| 1573 1561 | 
             
                @lineno = 0
         | 
| 1562 | 
            +
             | 
| 1563 | 
            +
                # make sure headers have been assigned
         | 
| 1564 | 
            +
                if header_row? and [Array, String].include? @use_headers.class and @write_headers
         | 
| 1565 | 
            +
                  parse_headers  # won't read data for Array or String
         | 
| 1566 | 
            +
                  self << @headers
         | 
| 1567 | 
            +
                end
         | 
| 1574 1568 | 
             
              end
         | 
| 1575 1569 |  | 
| 1576 1570 | 
             
              #
         | 
| @@ -1656,7 +1650,7 @@ class CSV | |
| 1656 1650 | 
             
              # The line number of the last row read from this file.  Fields with nested
         | 
| 1657 1651 | 
             
              # line-end characters will not affect this count.
         | 
| 1658 1652 | 
             
              #
         | 
| 1659 | 
            -
              attr_reader :lineno
         | 
| 1653 | 
            +
              attr_reader :lineno, :line
         | 
| 1660 1654 |  | 
| 1661 1655 | 
             
              ### IO and StringIO Delegation ###
         | 
| 1662 1656 |  | 
| @@ -1687,9 +1681,8 @@ class CSV | |
| 1687 1681 | 
             
              #
         | 
| 1688 1682 | 
             
              def <<(row)
         | 
| 1689 1683 | 
             
                # make sure headers have been assigned
         | 
| 1690 | 
            -
                if header_row? and [Array, String].include? @use_headers.class
         | 
| 1684 | 
            +
                if header_row? and [Array, String].include? @use_headers.class and !@write_headers
         | 
| 1691 1685 | 
             
                  parse_headers  # won't read data for Array or String
         | 
| 1692 | 
            -
                  self << @headers if @write_headers
         | 
| 1693 1686 | 
             
                end
         | 
| 1694 1687 |  | 
| 1695 1688 | 
             
                # handle CSV::Row objects and Hashes
         | 
| @@ -1735,7 +1728,7 @@ class CSV | |
| 1735 1728 | 
             
              # converted field or the field itself.
         | 
| 1736 1729 | 
             
              #
         | 
| 1737 1730 | 
             
              def convert(name = nil, &converter)
         | 
| 1738 | 
            -
                add_converter( | 
| 1731 | 
            +
                add_converter(:@converters, self.class::Converters, name, &converter)
         | 
| 1739 1732 | 
             
              end
         | 
| 1740 1733 |  | 
| 1741 1734 | 
             
              #
         | 
| @@ -1750,7 +1743,7 @@ class CSV | |
| 1750 1743 | 
             
              # effect.
         | 
| 1751 1744 | 
             
              #
         | 
| 1752 1745 | 
             
              def header_convert(name = nil, &converter)
         | 
| 1753 | 
            -
                add_converter(  | 
| 1746 | 
            +
                add_converter( :@header_converters,
         | 
| 1754 1747 | 
             
                               self.class::HeaderConverters,
         | 
| 1755 1748 | 
             
                               name,
         | 
| 1756 1749 | 
             
                               &converter )
         | 
| @@ -1831,6 +1824,12 @@ class CSV | |
| 1831 1824 | 
             
                    return nil
         | 
| 1832 1825 | 
             
                  end
         | 
| 1833 1826 |  | 
| 1827 | 
            +
                  if in_extended_col
         | 
| 1828 | 
            +
                    @line.concat(parse)
         | 
| 1829 | 
            +
                  else
         | 
| 1830 | 
            +
                    @line = parse.clone
         | 
| 1831 | 
            +
                  end
         | 
| 1832 | 
            +
             | 
| 1834 1833 | 
             
                  parse.sub!(@parsers[:line_end], "")
         | 
| 1835 1834 |  | 
| 1836 1835 | 
             
                  if csv.empty?
         | 
| @@ -1868,32 +1867,32 @@ class CSV | |
| 1868 1867 | 
             
                  parts.each do |part|
         | 
| 1869 1868 | 
             
                    if in_extended_col
         | 
| 1870 1869 | 
             
                      # If we are continuing a previous column
         | 
| 1871 | 
            -
                      if part | 
| 1870 | 
            +
                      if part.end_with?(@quote_char) && part.count(@quote_char) % 2 != 0
         | 
| 1872 1871 | 
             
                        # extended column ends
         | 
| 1873 | 
            -
                        csv | 
| 1872 | 
            +
                        csv.last << part[0..-2]
         | 
| 1874 1873 | 
             
                        if csv.last =~ @parsers[:stray_quote]
         | 
| 1875 1874 | 
             
                          raise MalformedCSVError,
         | 
| 1876 1875 | 
             
                                "Missing or stray quote in line #{lineno + 1}"
         | 
| 1877 1876 | 
             
                        end
         | 
| 1878 | 
            -
                        csv.last.gsub!(@ | 
| 1877 | 
            +
                        csv.last.gsub!(@double_quote_char, @quote_char)
         | 
| 1879 1878 | 
             
                        in_extended_col = false
         | 
| 1880 1879 | 
             
                      else
         | 
| 1881 | 
            -
                        csv.last | 
| 1880 | 
            +
                        csv.last << part << @col_sep
         | 
| 1882 1881 | 
             
                      end
         | 
| 1883 | 
            -
                    elsif part | 
| 1882 | 
            +
                    elsif part.start_with?(@quote_char)
         | 
| 1884 1883 | 
             
                      # If we are starting a new quoted column
         | 
| 1885 1884 | 
             
                      if part.count(@quote_char) % 2 != 0
         | 
| 1886 1885 | 
             
                        # start an extended column
         | 
| 1887 | 
            -
                        csv <<  | 
| 1886 | 
            +
                        csv << (part[1..-1] << @col_sep)
         | 
| 1888 1887 | 
             
                        in_extended_col =  true
         | 
| 1889 | 
            -
                      elsif part | 
| 1888 | 
            +
                      elsif part.end_with?(@quote_char)
         | 
| 1890 1889 | 
             
                        # regular quoted column
         | 
| 1891 1890 | 
             
                        csv << part[1..-2]
         | 
| 1892 1891 | 
             
                        if csv.last =~ @parsers[:stray_quote]
         | 
| 1893 1892 | 
             
                          raise MalformedCSVError,
         | 
| 1894 1893 | 
             
                                "Missing or stray quote in line #{lineno + 1}"
         | 
| 1895 1894 | 
             
                        end
         | 
| 1896 | 
            -
                        csv.last.gsub!(@ | 
| 1895 | 
            +
                        csv.last.gsub!(@double_quote_char, @quote_char)
         | 
| 1897 1896 | 
             
                      elsif @liberal_parsing
         | 
| 1898 1897 | 
             
                        csv << part
         | 
| 1899 1898 | 
             
                      else
         | 
| @@ -1927,7 +1926,7 @@ class CSV | |
| 1927 1926 | 
             
                    if @io.eof?
         | 
| 1928 1927 | 
             
                      raise MalformedCSVError,
         | 
| 1929 1928 | 
             
                            "Unclosed quoted field on line #{lineno + 1}."
         | 
| 1930 | 
            -
                    elsif @field_size_limit and csv.last. | 
| 1929 | 
            +
                    elsif @field_size_limit and csv.last.size >= @field_size_limit
         | 
| 1931 1930 | 
             
                      raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}."
         | 
| 1932 1931 | 
             
                    end
         | 
| 1933 1932 | 
             
                    # otherwise, we need to loop and pull some more data to complete the row
         | 
| @@ -2006,11 +2005,12 @@ class CSV | |
| 2006 2005 | 
             
              #
         | 
| 2007 2006 | 
             
              # This method also establishes the quoting rules used for CSV output.
         | 
| 2008 2007 | 
             
              #
         | 
| 2009 | 
            -
              def init_separators( | 
| 2008 | 
            +
              def init_separators(col_sep, row_sep, quote_char, force_quotes)
         | 
| 2010 2009 | 
             
                # store the selected separators
         | 
| 2011 | 
            -
                @col_sep    =  | 
| 2012 | 
            -
                @row_sep    =  | 
| 2013 | 
            -
                @quote_char =  | 
| 2010 | 
            +
                @col_sep    = col_sep.to_s.encode(@encoding)
         | 
| 2011 | 
            +
                @row_sep    = row_sep # encode after resolving :auto
         | 
| 2012 | 
            +
                @quote_char = quote_char.to_s.encode(@encoding)
         | 
| 2013 | 
            +
                @double_quote_char = @quote_char * 2
         | 
| 2014 2014 |  | 
| 2015 2015 | 
             
                if @quote_char.length != 1
         | 
| 2016 2016 | 
             
                  raise ArgumentError, ":quote_char has to be a single character String"
         | 
| @@ -2075,13 +2075,11 @@ class CSV | |
| 2075 2075 | 
             
                @row_sep = @row_sep.to_s.encode(@encoding)
         | 
| 2076 2076 |  | 
| 2077 2077 | 
             
                # establish quoting rules
         | 
| 2078 | 
            -
                @force_quotes | 
| 2079 | 
            -
                do_quote | 
| 2080 | 
            -
                  field | 
| 2078 | 
            +
                @force_quotes = force_quotes
         | 
| 2079 | 
            +
                do_quote = lambda do |field|
         | 
| 2080 | 
            +
                  field = String(field)
         | 
| 2081 2081 | 
             
                  encoded_quote = @quote_char.encode(field.encoding)
         | 
| 2082 | 
            -
                  encoded_quote | 
| 2083 | 
            -
                  field.gsub(encoded_quote, encoded_quote * 2) +
         | 
| 2084 | 
            -
                  encoded_quote
         | 
| 2082 | 
            +
                  encoded_quote + field.gsub(encoded_quote, encoded_quote * 2) + encoded_quote
         | 
| 2085 2083 | 
             
                end
         | 
| 2086 2084 | 
             
                quotable_chars = encode_str("\r\n", @col_sep, @quote_char)
         | 
| 2087 2085 | 
             
                @quote         = if @force_quotes
         | 
| @@ -2105,11 +2103,11 @@ class CSV | |
| 2105 2103 | 
             
              end
         | 
| 2106 2104 |  | 
| 2107 2105 | 
             
              # Pre-compiles parsers and stores them by name for access during reads.
         | 
| 2108 | 
            -
              def init_parsers( | 
| 2106 | 
            +
              def init_parsers(skip_blanks, field_size_limit, liberal_parsing)
         | 
| 2109 2107 | 
             
                # store the parser behaviors
         | 
| 2110 | 
            -
                @skip_blanks      =  | 
| 2111 | 
            -
                @field_size_limit =  | 
| 2112 | 
            -
                @liberal_parsing  =  | 
| 2108 | 
            +
                @skip_blanks      = skip_blanks
         | 
| 2109 | 
            +
                @field_size_limit = field_size_limit
         | 
| 2110 | 
            +
                @liberal_parsing  = liberal_parsing
         | 
| 2113 2111 |  | 
| 2114 2112 | 
             
                # prebuild Regexps for faster parsing
         | 
| 2115 2113 | 
             
                esc_row_sep = escape_re(@row_sep)
         | 
| @@ -2137,45 +2135,23 @@ class CSV | |
| 2137 2135 | 
             
              # The <tt>:unconverted_fields</tt> option is also activated for
         | 
| 2138 2136 | 
             
              # <tt>:converters</tt> calls, if requested.
         | 
| 2139 2137 | 
             
              #
         | 
| 2140 | 
            -
              def init_converters( | 
| 2141 | 
            -
                 | 
| 2142 | 
            -
             | 
| 2143 | 
            -
             | 
| 2144 | 
            -
             | 
| 2145 | 
            -
             | 
| 2146 | 
            -
             | 
| 2147 | 
            -
                 | 
| 2148 | 
            -
                convert = method(field_name.to_s.sub(/ers\Z/, ""))
         | 
| 2138 | 
            +
              def init_converters(converters, ivar_name, convert_method)
         | 
| 2139 | 
            +
                converters = case converters
         | 
| 2140 | 
            +
                             when nil then []
         | 
| 2141 | 
            +
                             when Array then converters
         | 
| 2142 | 
            +
                             else [converters]
         | 
| 2143 | 
            +
                             end
         | 
| 2144 | 
            +
                instance_variable_set(ivar_name, [])
         | 
| 2145 | 
            +
                convert = method(convert_method)
         | 
| 2149 2146 |  | 
| 2150 2147 | 
             
                # load converters
         | 
| 2151 | 
            -
                 | 
| 2152 | 
            -
                   | 
| 2153 | 
            -
             | 
| 2154 | 
            -
             | 
| 2155 | 
            -
             | 
| 2156 | 
            -
                  # load each converter...
         | 
| 2157 | 
            -
                  options[field_name].each do |converter|
         | 
| 2158 | 
            -
                    if converter.is_a? Proc  # custom code block
         | 
| 2159 | 
            -
                      convert.call(&converter)
         | 
| 2160 | 
            -
                    else                     # by name
         | 
| 2161 | 
            -
                      convert.call(converter)
         | 
| 2162 | 
            -
                    end
         | 
| 2148 | 
            +
                converters.each do |converter|
         | 
| 2149 | 
            +
                  if converter.is_a? Proc  # custom code block
         | 
| 2150 | 
            +
                    convert.call(&converter)
         | 
| 2151 | 
            +
                  else                     # by name
         | 
| 2152 | 
            +
                    convert.call(converter)
         | 
| 2163 2153 | 
             
                  end
         | 
| 2164 2154 | 
             
                end
         | 
| 2165 | 
            -
             | 
| 2166 | 
            -
                options.delete(field_name)
         | 
| 2167 | 
            -
              end
         | 
| 2168 | 
            -
             | 
| 2169 | 
            -
              # Stores header row settings and loads header converters, if needed.
         | 
| 2170 | 
            -
              def init_headers(options)
         | 
| 2171 | 
            -
                @use_headers    = options.delete(:headers)
         | 
| 2172 | 
            -
                @return_headers = options.delete(:return_headers)
         | 
| 2173 | 
            -
                @write_headers  = options.delete(:write_headers)
         | 
| 2174 | 
            -
             | 
| 2175 | 
            -
                # headers must be delayed until shift(), in case they need a row of content
         | 
| 2176 | 
            -
                @headers = nil
         | 
| 2177 | 
            -
             | 
| 2178 | 
            -
                init_converters(options, :header_converters)
         | 
| 2179 2155 | 
             
              end
         | 
| 2180 2156 |  | 
| 2181 2157 | 
             
              # Stores the pattern of comments to skip from the provided options.
         | 
| @@ -2184,9 +2160,9 @@ class CSV | |
| 2184 2160 | 
             
              # Strings are converted to a Regexp.
         | 
| 2185 2161 | 
             
              #
         | 
| 2186 2162 | 
             
              # See also CSV.new
         | 
| 2187 | 
            -
              def init_comments( | 
| 2188 | 
            -
                @skip_lines =  | 
| 2189 | 
            -
                @skip_lines = Regexp.new(@skip_lines) if @skip_lines.is_a? String
         | 
| 2163 | 
            +
              def init_comments(skip_lines)
         | 
| 2164 | 
            +
                @skip_lines = skip_lines
         | 
| 2165 | 
            +
                @skip_lines = Regexp.new(Regexp.escape(@skip_lines)) if @skip_lines.is_a? String
         | 
| 2190 2166 | 
             
                if @skip_lines and not @skip_lines.respond_to?(:match)
         | 
| 2191 2167 | 
             
                  raise ArgumentError, ":skip_lines has to respond to matches"
         | 
| 2192 2168 | 
             
                end
         | 
| @@ -2201,7 +2177,7 @@ class CSV | |
| 2201 2177 | 
             
              #
         | 
| 2202 2178 | 
             
              def add_converter(var_name, const, name = nil, &converter)
         | 
| 2203 2179 | 
             
                if name.nil?  # custom converter
         | 
| 2204 | 
            -
                  instance_variable_get( | 
| 2180 | 
            +
                  instance_variable_get(var_name) << converter
         | 
| 2205 2181 | 
             
                else          # named converter
         | 
| 2206 2182 | 
             
                  combo = const[name]
         | 
| 2207 2183 | 
             
                  case combo
         | 
| @@ -2210,7 +2186,7 @@ class CSV | |
| 2210 2186 | 
             
                      add_converter(var_name, const, converter_name)
         | 
| 2211 2187 | 
             
                    end
         | 
| 2212 2188 | 
             
                  else        # individual named converter
         | 
| 2213 | 
            -
                    instance_variable_get( | 
| 2189 | 
            +
                    instance_variable_get(var_name) << combo
         | 
| 2214 2190 | 
             
                  end
         | 
| 2215 2191 | 
             
                end
         | 
| 2216 2192 | 
             
              end
         | 
| @@ -2228,7 +2204,7 @@ class CSV | |
| 2228 2204 |  | 
| 2229 2205 | 
             
                fields.map.with_index do |field, index|
         | 
| 2230 2206 | 
             
                  converters.each do |converter|
         | 
| 2231 | 
            -
                    break if field.nil?
         | 
| 2207 | 
            +
                    break if headers && field.nil?
         | 
| 2232 2208 | 
             
                    field = if converter.arity == 1  # straight field converter
         | 
| 2233 2209 | 
             
                      converter[field]
         | 
| 2234 2210 | 
             
                    else                             # FieldInfo converter
         | 
| @@ -2290,7 +2266,7 @@ class CSV | |
| 2290 2266 | 
             
                class << row
         | 
| 2291 2267 | 
             
                  attr_reader :unconverted_fields
         | 
| 2292 2268 | 
             
                end
         | 
| 2293 | 
            -
                row. | 
| 2269 | 
            +
                row.instance_variable_set(:@unconverted_fields, fields)
         | 
| 2294 2270 | 
             
                row
         | 
| 2295 2271 | 
             
              end
         | 
| 2296 2272 |  | 
| @@ -2321,8 +2297,6 @@ class CSV | |
| 2321 2297 | 
             
                chunks.map { |chunk| chunk.encode(@encoding.name) }.join('')
         | 
| 2322 2298 | 
             
              end
         | 
| 2323 2299 |  | 
| 2324 | 
            -
              private
         | 
| 2325 | 
            -
             | 
| 2326 2300 | 
             
              #
         | 
| 2327 2301 | 
             
              # Returns the encoding of the internal IO object or the +default+ if the
         | 
| 2328 2302 | 
             
              # encoding cannot be determined.
         | 
| @@ -2365,7 +2339,7 @@ class Array # :nodoc: | |
| 2365 2339 | 
             
              #
         | 
| 2366 2340 | 
             
              #   ["CSV", "data"].to_csv
         | 
| 2367 2341 | 
             
              #     #=> "CSV,data\n"
         | 
| 2368 | 
            -
              def to_csv(options | 
| 2342 | 
            +
              def to_csv(**options)
         | 
| 2369 2343 | 
             
                CSV.generate_line(self, options)
         | 
| 2370 2344 | 
             
              end
         | 
| 2371 2345 | 
             
            end
         | 
| @@ -2375,7 +2349,7 @@ class String # :nodoc: | |
| 2375 2349 | 
             
              #
         | 
| 2376 2350 | 
             
              #   "CSV,data".parse_csv
         | 
| 2377 2351 | 
             
              #     #=> ["CSV", "data"]
         | 
| 2378 | 
            -
              def parse_csv(options | 
| 2352 | 
            +
              def parse_csv(**options)
         | 
| 2379 2353 | 
             
                CSV.parse_line(self, options)
         | 
| 2380 2354 | 
             
              end
         | 
| 2381 2355 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: csv
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0 | 
| 4 | 
            +
              version: 0.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - James Edward Gray II
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2017- | 
| 11 | 
            +
            date: 2017-09-12 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -30,14 +30,14 @@ dependencies: | |
| 30 30 | 
             
                requirements:
         | 
| 31 31 | 
             
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: ' | 
| 33 | 
            +
                    version: '12'
         | 
| 34 34 | 
             
              type: :development
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 38 | 
             
                - - "~>"
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: ' | 
| 40 | 
            +
                    version: '12'
         | 
| 41 41 | 
             
            description: the CSV library began its life as FasterCSV.
         | 
| 42 42 | 
             
            email:
         | 
| 43 43 | 
             
            - 
         | 
| @@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 66 66 | 
             
                  version: '0'
         | 
| 67 67 | 
             
            requirements: []
         | 
| 68 68 | 
             
            rubyforge_project: 
         | 
| 69 | 
            -
            rubygems_version: 2.6. | 
| 69 | 
            +
            rubygems_version: 2.6.13
         | 
| 70 70 | 
             
            signing_key: 
         | 
| 71 71 | 
             
            specification_version: 4
         | 
| 72 72 | 
             
            summary: CSV Reading and Writing
         |