Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/AnonR/smanonr..../opt/alt/ruby27/share/ruby
File: csv.rb
# encoding: US-ASCII
[0] Fix | Delete
# frozen_string_literal: true
[1] Fix | Delete
# = csv.rb -- CSV Reading and Writing
[2] Fix | Delete
#
[3] Fix | Delete
# Created by James Edward Gray II on 2005-10-31.
[4] Fix | Delete
#
[5] Fix | Delete
# See CSV for documentation.
[6] Fix | Delete
#
[7] Fix | Delete
# == Description
[8] Fix | Delete
#
[9] Fix | Delete
# Welcome to the new and improved CSV.
[10] Fix | Delete
#
[11] Fix | Delete
# This version of the CSV library began its life as FasterCSV. FasterCSV was
[12] Fix | Delete
# intended as a replacement to Ruby's then standard CSV library. It was
[13] Fix | Delete
# designed to address concerns users of that library had and it had three
[14] Fix | Delete
# primary goals:
[15] Fix | Delete
#
[16] Fix | Delete
# 1. Be significantly faster than CSV while remaining a pure Ruby library.
[17] Fix | Delete
# 2. Use a smaller and easier to maintain code base. (FasterCSV eventually
[18] Fix | Delete
# grew larger, was also but considerably richer in features. The parsing
[19] Fix | Delete
# core remains quite small.)
[20] Fix | Delete
# 3. Improve on the CSV interface.
[21] Fix | Delete
#
[22] Fix | Delete
# Obviously, the last one is subjective. I did try to defer to the original
[23] Fix | Delete
# interface whenever I didn't have a compelling reason to change it though, so
[24] Fix | Delete
# hopefully this won't be too radically different.
[25] Fix | Delete
#
[26] Fix | Delete
# We must have met our goals because FasterCSV was renamed to CSV and replaced
[27] Fix | Delete
# the original library as of Ruby 1.9. If you are migrating code from 1.8 or
[28] Fix | Delete
# earlier, you may have to change your code to comply with the new interface.
[29] Fix | Delete
#
[30] Fix | Delete
# == What's the Different From the Old CSV?
[31] Fix | Delete
#
[32] Fix | Delete
# I'm sure I'll miss something, but I'll try to mention most of the major
[33] Fix | Delete
# differences I am aware of, to help others quickly get up to speed:
[34] Fix | Delete
#
[35] Fix | Delete
# === CSV Parsing
[36] Fix | Delete
#
[37] Fix | Delete
# * This parser is m17n aware. See CSV for full details.
[38] Fix | Delete
# * This library has a stricter parser and will throw MalformedCSVErrors on
[39] Fix | Delete
# problematic data.
[40] Fix | Delete
# * This library has a less liberal idea of a line ending than CSV. What you
[41] Fix | Delete
# set as the <tt>:row_sep</tt> is law. It can auto-detect your line endings
[42] Fix | Delete
# though.
[43] Fix | Delete
# * The old library returned empty lines as <tt>[nil]</tt>. This library calls
[44] Fix | Delete
# them <tt>[]</tt>.
[45] Fix | Delete
# * This library has a much faster parser.
[46] Fix | Delete
#
[47] Fix | Delete
# === Interface
[48] Fix | Delete
#
[49] Fix | Delete
# * CSV now uses Hash-style parameters to set options.
[50] Fix | Delete
# * CSV no longer has generate_row() or parse_row().
[51] Fix | Delete
# * The old CSV's Reader and Writer classes have been dropped.
[52] Fix | Delete
# * CSV::open() is now more like Ruby's open().
[53] Fix | Delete
# * CSV objects now support most standard IO methods.
[54] Fix | Delete
# * CSV now has a new() method used to wrap objects like String and IO for
[55] Fix | Delete
# reading and writing.
[56] Fix | Delete
# * CSV::generate() is different from the old method.
[57] Fix | Delete
# * CSV no longer supports partial reads. It works line-by-line.
[58] Fix | Delete
# * CSV no longer allows the instance methods to override the separators for
[59] Fix | Delete
# performance reasons. They must be set in the constructor.
[60] Fix | Delete
#
[61] Fix | Delete
# If you use this library and find yourself missing any functionality I have
[62] Fix | Delete
# trimmed, please {let me know}[mailto:james@grayproductions.net].
[63] Fix | Delete
#
[64] Fix | Delete
# == Documentation
[65] Fix | Delete
#
[66] Fix | Delete
# See CSV for documentation.
[67] Fix | Delete
#
[68] Fix | Delete
# == What is CSV, really?
[69] Fix | Delete
#
[70] Fix | Delete
# CSV maintains a pretty strict definition of CSV taken directly from
[71] Fix | Delete
# {the RFC}[http://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
[72] Fix | Delete
# place and that is to make using this library easier. CSV will parse all valid
[73] Fix | Delete
# CSV.
[74] Fix | Delete
#
[75] Fix | Delete
# What you don't want to do is to feed CSV invalid data. Because of the way the
[76] Fix | Delete
# CSV format works, it's common for a parser to need to read until the end of
[77] Fix | Delete
# the file to be sure a field is invalid. This consumes a lot of time and memory.
[78] Fix | Delete
#
[79] Fix | Delete
# Luckily, when working with invalid CSV, Ruby's built-in methods will almost
[80] Fix | Delete
# always be superior in every way. For example, parsing non-quoted fields is as
[81] Fix | Delete
# easy as:
[82] Fix | Delete
#
[83] Fix | Delete
# data.split(",")
[84] Fix | Delete
#
[85] Fix | Delete
# == Questions and/or Comments
[86] Fix | Delete
#
[87] Fix | Delete
# Feel free to email {James Edward Gray II}[mailto:james@grayproductions.net]
[88] Fix | Delete
# with any questions.
[89] Fix | Delete
[90] Fix | Delete
require "forwardable"
[91] Fix | Delete
require "English"
[92] Fix | Delete
require "date"
[93] Fix | Delete
require "stringio"
[94] Fix | Delete
[95] Fix | Delete
require_relative "csv/fields_converter"
[96] Fix | Delete
require_relative "csv/match_p"
[97] Fix | Delete
require_relative "csv/parser"
[98] Fix | Delete
require_relative "csv/row"
[99] Fix | Delete
require_relative "csv/table"
[100] Fix | Delete
require_relative "csv/writer"
[101] Fix | Delete
[102] Fix | Delete
using CSV::MatchP if CSV.const_defined?(:MatchP)
[103] Fix | Delete
[104] Fix | Delete
#
[105] Fix | Delete
# This class provides a complete interface to CSV files and data. It offers
[106] Fix | Delete
# tools to enable you to read and write to and from Strings or IO objects, as
[107] Fix | Delete
# needed.
[108] Fix | Delete
#
[109] Fix | Delete
# The most generic interface of the library is:
[110] Fix | Delete
#
[111] Fix | Delete
# csv = CSV.new(string_or_io, **options)
[112] Fix | Delete
#
[113] Fix | Delete
# # Reading: IO object should be open for read
[114] Fix | Delete
# csv.read # => array of rows
[115] Fix | Delete
# # or
[116] Fix | Delete
# csv.each do |row|
[117] Fix | Delete
# # ...
[118] Fix | Delete
# end
[119] Fix | Delete
# # or
[120] Fix | Delete
# row = csv.shift
[121] Fix | Delete
#
[122] Fix | Delete
# # Writing: IO object should be open for write
[123] Fix | Delete
# csv << row
[124] Fix | Delete
#
[125] Fix | Delete
# There are several specialized class methods for one-statement reading or writing,
[126] Fix | Delete
# described in the Specialized Methods section.
[127] Fix | Delete
#
[128] Fix | Delete
# If a String is passed into ::new, it is internally wrapped into a StringIO object.
[129] Fix | Delete
#
[130] Fix | Delete
# +options+ can be used for specifying the particular CSV flavor (column
[131] Fix | Delete
# separators, row separators, value quoting and so on), and for data conversion,
[132] Fix | Delete
# see Data Conversion section for the description of the latter.
[133] Fix | Delete
#
[134] Fix | Delete
# == Specialized Methods
[135] Fix | Delete
#
[136] Fix | Delete
# === Reading
[137] Fix | Delete
#
[138] Fix | Delete
# # From a file: all at once
[139] Fix | Delete
# arr_of_rows = CSV.read("path/to/file.csv", **options)
[140] Fix | Delete
# # iterator-style:
[141] Fix | Delete
# CSV.foreach("path/to/file.csv", **options) do |row|
[142] Fix | Delete
# # ...
[143] Fix | Delete
# end
[144] Fix | Delete
#
[145] Fix | Delete
# # From a string
[146] Fix | Delete
# arr_of_rows = CSV.parse("CSV,data,String", **options)
[147] Fix | Delete
# # or
[148] Fix | Delete
# CSV.parse("CSV,data,String", **options) do |row|
[149] Fix | Delete
# # ...
[150] Fix | Delete
# end
[151] Fix | Delete
#
[152] Fix | Delete
# === Writing
[153] Fix | Delete
#
[154] Fix | Delete
# # To a file
[155] Fix | Delete
# CSV.open("path/to/file.csv", "wb") do |csv|
[156] Fix | Delete
# csv << ["row", "of", "CSV", "data"]
[157] Fix | Delete
# csv << ["another", "row"]
[158] Fix | Delete
# # ...
[159] Fix | Delete
# end
[160] Fix | Delete
#
[161] Fix | Delete
# # To a String
[162] Fix | Delete
# csv_string = CSV.generate do |csv|
[163] Fix | Delete
# csv << ["row", "of", "CSV", "data"]
[164] Fix | Delete
# csv << ["another", "row"]
[165] Fix | Delete
# # ...
[166] Fix | Delete
# end
[167] Fix | Delete
#
[168] Fix | Delete
# === Shortcuts
[169] Fix | Delete
#
[170] Fix | Delete
# # Core extensions for converting one line
[171] Fix | Delete
# csv_string = ["CSV", "data"].to_csv # to CSV
[172] Fix | Delete
# csv_array = "CSV,String".parse_csv # from CSV
[173] Fix | Delete
#
[174] Fix | Delete
# # CSV() method
[175] Fix | Delete
# CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
[176] Fix | Delete
# CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
[177] Fix | Delete
# CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
[178] Fix | Delete
# CSV($stdin) { |csv_in| csv_in.each { |row| p row } } # from $stdin
[179] Fix | Delete
#
[180] Fix | Delete
# == Data Conversion
[181] Fix | Delete
#
[182] Fix | Delete
# === CSV with headers
[183] Fix | Delete
#
[184] Fix | Delete
# CSV allows to specify column names of CSV file, whether they are in data, or
[185] Fix | Delete
# provided separately. If headers are specified, reading methods return an instance
[186] Fix | Delete
# of CSV::Table, consisting of CSV::Row.
[187] Fix | Delete
#
[188] Fix | Delete
# # Headers are part of data
[189] Fix | Delete
# data = CSV.parse(<<~ROWS, headers: true)
[190] Fix | Delete
# Name,Department,Salary
[191] Fix | Delete
# Bob,Engineering,1000
[192] Fix | Delete
# Jane,Sales,2000
[193] Fix | Delete
# John,Management,5000
[194] Fix | Delete
# ROWS
[195] Fix | Delete
#
[196] Fix | Delete
# data.class #=> CSV::Table
[197] Fix | Delete
# data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
[198] Fix | Delete
# data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
[199] Fix | Delete
#
[200] Fix | Delete
# # Headers provided by developer
[201] Fix | Delete
# data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
[202] Fix | Delete
# data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
[203] Fix | Delete
#
[204] Fix | Delete
# === Typed data reading
[205] Fix | Delete
#
[206] Fix | Delete
# CSV allows to provide a set of data _converters_ e.g. transformations to try on input
[207] Fix | Delete
# data. Converter could be a symbol from CSV::Converters constant's keys, or lambda.
[208] Fix | Delete
#
[209] Fix | Delete
# # Without any converters:
[210] Fix | Delete
# CSV.parse('Bob,2018-03-01,100')
[211] Fix | Delete
# #=> [["Bob", "2018-03-01", "100"]]
[212] Fix | Delete
#
[213] Fix | Delete
# # With built-in converters:
[214] Fix | Delete
# CSV.parse('Bob,2018-03-01,100', converters: %i[numeric date])
[215] Fix | Delete
# #=> [["Bob", #<Date: 2018-03-01>, 100]]
[216] Fix | Delete
#
[217] Fix | Delete
# # With custom converters:
[218] Fix | Delete
# CSV.parse('Bob,2018-03-01,100', converters: [->(v) { Time.parse(v) rescue v }])
[219] Fix | Delete
# #=> [["Bob", 2018-03-01 00:00:00 +0200, "100"]]
[220] Fix | Delete
#
[221] Fix | Delete
# == CSV and Character Encodings (M17n or Multilingualization)
[222] Fix | Delete
#
[223] Fix | Delete
# This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
[224] Fix | Delete
# or String object being read from or written to. Your data is never transcoded
[225] Fix | Delete
# (unless you ask Ruby to transcode it for you) and will literally be parsed in
[226] Fix | Delete
# the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the
[227] Fix | Delete
# Encoding of your data. This is accomplished by transcoding the parser itself
[228] Fix | Delete
# into your Encoding.
[229] Fix | Delete
#
[230] Fix | Delete
# Some transcoding must take place, of course, to accomplish this multiencoding
[231] Fix | Delete
# support. For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and
[232] Fix | Delete
# <tt>:quote_char</tt> must be transcoded to match your data. Hopefully this
[233] Fix | Delete
# makes the entire process feel transparent, since CSV's defaults should just
[234] Fix | Delete
# magically work for your data. However, you can set these values manually in
[235] Fix | Delete
# the target Encoding to avoid the translation.
[236] Fix | Delete
#
[237] Fix | Delete
# It's also important to note that while all of CSV's core parser is now
[238] Fix | Delete
# Encoding agnostic, some features are not. For example, the built-in
[239] Fix | Delete
# converters will try to transcode data to UTF-8 before making conversions.
[240] Fix | Delete
# Again, you can provide custom converters that are aware of your Encodings to
[241] Fix | Delete
# avoid this translation. It's just too hard for me to support native
[242] Fix | Delete
# conversions in all of Ruby's Encodings.
[243] Fix | Delete
#
[244] Fix | Delete
# Anyway, the practical side of this is simple: make sure IO and String objects
[245] Fix | Delete
# passed into CSV have the proper Encoding set and everything should just work.
[246] Fix | Delete
# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(),
[247] Fix | Delete
# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding.
[248] Fix | Delete
#
[249] Fix | Delete
# One minor exception comes when generating CSV into a String with an Encoding
[250] Fix | Delete
# that is not ASCII compatible. There's no existing data for CSV to use to
[251] Fix | Delete
# prepare itself and thus you will probably need to manually specify the desired
[252] Fix | Delete
# Encoding for most of those cases. It will try to guess using the fields in a
[253] Fix | Delete
# row of output though, when using CSV::generate_line() or Array#to_csv().
[254] Fix | Delete
#
[255] Fix | Delete
# I try to point out any other Encoding issues in the documentation of methods
[256] Fix | Delete
# as they come up.
[257] Fix | Delete
#
[258] Fix | Delete
# This has been tested to the best of my ability with all non-"dummy" Encodings
[259] Fix | Delete
# Ruby ships with. However, it is brave new code and may have some bugs.
[260] Fix | Delete
# Please feel free to {report}[mailto:james@grayproductions.net] any issues you
[261] Fix | Delete
# find with it.
[262] Fix | Delete
#
[263] Fix | Delete
class CSV
[264] Fix | Delete
[265] Fix | Delete
# The error thrown when the parser encounters illegal CSV formatting.
[266] Fix | Delete
class MalformedCSVError < RuntimeError
[267] Fix | Delete
attr_reader :line_number
[268] Fix | Delete
alias_method :lineno, :line_number
[269] Fix | Delete
def initialize(message, line_number)
[270] Fix | Delete
@line_number = line_number
[271] Fix | Delete
super("#{message} in line #{line_number}.")
[272] Fix | Delete
end
[273] Fix | Delete
end
[274] Fix | Delete
[275] Fix | Delete
#
[276] Fix | Delete
# A FieldInfo Struct contains details about a field's position in the data
[277] Fix | Delete
# source it was read from. CSV will pass this Struct to some blocks that make
[278] Fix | Delete
# decisions based on field structure. See CSV.convert_fields() for an
[279] Fix | Delete
# example.
[280] Fix | Delete
#
[281] Fix | Delete
# <b><tt>index</tt></b>:: The zero-based index of the field in its row.
[282] Fix | Delete
# <b><tt>line</tt></b>:: The line of the data source this row is from.
[283] Fix | Delete
# <b><tt>header</tt></b>:: The header for the column, when available.
[284] Fix | Delete
#
[285] Fix | Delete
FieldInfo = Struct.new(:index, :line, :header)
[286] Fix | Delete
[287] Fix | Delete
# A Regexp used to find and convert some common Date formats.
[288] Fix | Delete
DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} |
[289] Fix | Delete
\d{4}-\d{2}-\d{2} )\z /x
[290] Fix | Delete
# A Regexp used to find and convert some common DateTime formats.
[291] Fix | Delete
DateTimeMatcher =
[292] Fix | Delete
/ \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} |
[293] Fix | Delete
\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} |
[294] Fix | Delete
# ISO-8601
[295] Fix | Delete
\d{4}-\d{2}-\d{2}
[296] Fix | Delete
(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?(?:[+-]\d{2}(?::\d{2})|Z)?)?)?
[297] Fix | Delete
)\z /x
[298] Fix | Delete
[299] Fix | Delete
# The encoding used by all converters.
[300] Fix | Delete
ConverterEncoding = Encoding.find("UTF-8")
[301] Fix | Delete
[302] Fix | Delete
#
[303] Fix | Delete
# This Hash holds the built-in converters of CSV that can be accessed by name.
[304] Fix | Delete
# You can select Converters with CSV.convert() or through the +options+ Hash
[305] Fix | Delete
# passed to CSV::new().
[306] Fix | Delete
#
[307] Fix | Delete
# <b><tt>:integer</tt></b>:: Converts any field Integer() accepts.
[308] Fix | Delete
# <b><tt>:float</tt></b>:: Converts any field Float() accepts.
[309] Fix | Delete
# <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
[310] Fix | Delete
# and <tt>:float</tt>.
[311] Fix | Delete
# <b><tt>:date</tt></b>:: Converts any field Date::parse() accepts.
[312] Fix | Delete
# <b><tt>:date_time</tt></b>:: Converts any field DateTime::parse() accepts.
[313] Fix | Delete
# <b><tt>:all</tt></b>:: All built-in converters. A combination of
[314] Fix | Delete
# <tt>:date_time</tt> and <tt>:numeric</tt>.
[315] Fix | Delete
#
[316] Fix | Delete
# All built-in converters transcode field data to UTF-8 before attempting a
[317] Fix | Delete
# conversion. If your data cannot be transcoded to UTF-8 the conversion will
[318] Fix | Delete
# fail and the field will remain unchanged.
[319] Fix | Delete
#
[320] Fix | Delete
# This Hash is intentionally left unfrozen and users should feel free to add
[321] Fix | Delete
# values to it that can be accessed by all CSV objects.
[322] Fix | Delete
#
[323] Fix | Delete
# To add a combo field, the value should be an Array of names. Combo fields
[324] Fix | Delete
# can be nested with other combo fields.
[325] Fix | Delete
#
[326] Fix | Delete
Converters = {
[327] Fix | Delete
integer: lambda { |f|
[328] Fix | Delete
Integer(f.encode(ConverterEncoding)) rescue f
[329] Fix | Delete
},
[330] Fix | Delete
float: lambda { |f|
[331] Fix | Delete
Float(f.encode(ConverterEncoding)) rescue f
[332] Fix | Delete
},
[333] Fix | Delete
numeric: [:integer, :float],
[334] Fix | Delete
date: lambda { |f|
[335] Fix | Delete
begin
[336] Fix | Delete
e = f.encode(ConverterEncoding)
[337] Fix | Delete
e.match?(DateMatcher) ? Date.parse(e) : f
[338] Fix | Delete
rescue # encoding conversion or date parse errors
[339] Fix | Delete
f
[340] Fix | Delete
end
[341] Fix | Delete
},
[342] Fix | Delete
date_time: lambda { |f|
[343] Fix | Delete
begin
[344] Fix | Delete
e = f.encode(ConverterEncoding)
[345] Fix | Delete
e.match?(DateTimeMatcher) ? DateTime.parse(e) : f
[346] Fix | Delete
rescue # encoding conversion or date parse errors
[347] Fix | Delete
f
[348] Fix | Delete
end
[349] Fix | Delete
},
[350] Fix | Delete
all: [:date_time, :numeric],
[351] Fix | Delete
}
[352] Fix | Delete
[353] Fix | Delete
#
[354] Fix | Delete
# This Hash holds the built-in header converters of CSV that can be accessed
[355] Fix | Delete
# by name. You can select HeaderConverters with CSV.header_convert() or
[356] Fix | Delete
# through the +options+ Hash passed to CSV::new().
[357] Fix | Delete
#
[358] Fix | Delete
# <b><tt>:downcase</tt></b>:: Calls downcase() on the header String.
[359] Fix | Delete
# <b><tt>:symbol</tt></b>:: Leading/trailing spaces are dropped, string is
[360] Fix | Delete
# downcased, remaining spaces are replaced with
[361] Fix | Delete
# underscores, non-word characters are dropped,
[362] Fix | Delete
# and finally to_sym() is called.
[363] Fix | Delete
#
[364] Fix | Delete
# All built-in header converters transcode header data to UTF-8 before
[365] Fix | Delete
# attempting a conversion. If your data cannot be transcoded to UTF-8 the
[366] Fix | Delete
# conversion will fail and the header will remain unchanged.
[367] Fix | Delete
#
[368] Fix | Delete
# This Hash is intentionally left unfrozen and users should feel free to add
[369] Fix | Delete
# values to it that can be accessed by all CSV objects.
[370] Fix | Delete
#
[371] Fix | Delete
# To add a combo field, the value should be an Array of names. Combo fields
[372] Fix | Delete
# can be nested with other combo fields.
[373] Fix | Delete
#
[374] Fix | Delete
HeaderConverters = {
[375] Fix | Delete
downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
[376] Fix | Delete
symbol: lambda { |h|
[377] Fix | Delete
h.encode(ConverterEncoding).downcase.gsub(/[^\s\w]+/, "").strip.
[378] Fix | Delete
gsub(/\s+/, "_").to_sym
[379] Fix | Delete
}
[380] Fix | Delete
}
[381] Fix | Delete
[382] Fix | Delete
#
[383] Fix | Delete
# The options used when no overrides are given by calling code. They are:
[384] Fix | Delete
#
[385] Fix | Delete
# <b><tt>:col_sep</tt></b>:: <tt>","</tt>
[386] Fix | Delete
# <b><tt>:row_sep</tt></b>:: <tt>:auto</tt>
[387] Fix | Delete
# <b><tt>:quote_char</tt></b>:: <tt>'"'</tt>
[388] Fix | Delete
# <b><tt>:field_size_limit</tt></b>:: +nil+
[389] Fix | Delete
# <b><tt>:converters</tt></b>:: +nil+
[390] Fix | Delete
# <b><tt>:unconverted_fields</tt></b>:: +nil+
[391] Fix | Delete
# <b><tt>:headers</tt></b>:: +false+
[392] Fix | Delete
# <b><tt>:return_headers</tt></b>:: +false+
[393] Fix | Delete
# <b><tt>:header_converters</tt></b>:: +nil+
[394] Fix | Delete
# <b><tt>:skip_blanks</tt></b>:: +false+
[395] Fix | Delete
# <b><tt>:force_quotes</tt></b>:: +false+
[396] Fix | Delete
# <b><tt>:skip_lines</tt></b>:: +nil+
[397] Fix | Delete
# <b><tt>:liberal_parsing</tt></b>:: +false+
[398] Fix | Delete
# <b><tt>:quote_empty</tt></b>:: +true+
[399] Fix | Delete
#
[400] Fix | Delete
DEFAULT_OPTIONS = {
[401] Fix | Delete
col_sep: ",",
[402] Fix | Delete
row_sep: :auto,
[403] Fix | Delete
quote_char: '"',
[404] Fix | Delete
field_size_limit: nil,
[405] Fix | Delete
converters: nil,
[406] Fix | Delete
unconverted_fields: nil,
[407] Fix | Delete
headers: false,
[408] Fix | Delete
return_headers: false,
[409] Fix | Delete
header_converters: nil,
[410] Fix | Delete
skip_blanks: false,
[411] Fix | Delete
force_quotes: false,
[412] Fix | Delete
skip_lines: nil,
[413] Fix | Delete
liberal_parsing: false,
[414] Fix | Delete
quote_empty: true,
[415] Fix | Delete
}.freeze
[416] Fix | Delete
[417] Fix | Delete
class << self
[418] Fix | Delete
#
[419] Fix | Delete
# This method will return a CSV instance, just like CSV::new(), but the
[420] Fix | Delete
# instance will be cached and returned for all future calls to this method for
[421] Fix | Delete
# the same +data+ object (tested by Object#object_id()) with the same
[422] Fix | Delete
# +options+.
[423] Fix | Delete
#
[424] Fix | Delete
# If a block is given, the instance is passed to the block and the return
[425] Fix | Delete
# value becomes the return value of the block.
[426] Fix | Delete
#
[427] Fix | Delete
def instance(data = $stdout, **options)
[428] Fix | Delete
# create a _signature_ for this method call, data object and options
[429] Fix | Delete
sig = [data.object_id] +
[430] Fix | Delete
options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
[431] Fix | Delete
[432] Fix | Delete
# fetch or create the instance for this signature
[433] Fix | Delete
@@instances ||= Hash.new
[434] Fix | Delete
instance = (@@instances[sig] ||= new(data, **options))
[435] Fix | Delete
[436] Fix | Delete
if block_given?
[437] Fix | Delete
yield instance # run block, if given, returning result
[438] Fix | Delete
else
[439] Fix | Delete
instance # or return the instance
[440] Fix | Delete
end
[441] Fix | Delete
end
[442] Fix | Delete
[443] Fix | Delete
#
[444] Fix | Delete
# :call-seq:
[445] Fix | Delete
# filter( **options ) { |row| ... }
[446] Fix | Delete
# filter( input, **options ) { |row| ... }
[447] Fix | Delete
# filter( input, output, **options ) { |row| ... }
[448] Fix | Delete
#
[449] Fix | Delete
# This method is a convenience for building Unix-like filters for CSV data.
[450] Fix | Delete
# Each row is yielded to the provided block which can alter it as needed.
[451] Fix | Delete
# After the block returns, the row is appended to +output+ altered or not.
[452] Fix | Delete
#
[453] Fix | Delete
# The +input+ and +output+ arguments can be anything CSV::new() accepts
[454] Fix | Delete
# (generally String or IO objects). If not given, they default to
[455] Fix | Delete
# <tt>ARGF</tt> and <tt>$stdout</tt>.
[456] Fix | Delete
#
[457] Fix | Delete
# The +options+ parameter is also filtered down to CSV::new() after some
[458] Fix | Delete
# clever key parsing. Any key beginning with <tt>:in_</tt> or
[459] Fix | Delete
# <tt>:input_</tt> will have that leading identifier stripped and will only
[460] Fix | Delete
# be used in the +options+ Hash for the +input+ object. Keys starting with
[461] Fix | Delete
# <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
[462] Fix | Delete
# are assigned to both objects.
[463] Fix | Delete
#
[464] Fix | Delete
# The <tt>:output_row_sep</tt> +option+ defaults to
[465] Fix | Delete
# <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
[466] Fix | Delete
#
[467] Fix | Delete
def filter(input=nil, output=nil, **options)
[468] Fix | Delete
# parse options for input, output, or both
[469] Fix | Delete
in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
[470] Fix | Delete
options.each do |key, value|
[471] Fix | Delete
case key.to_s
[472] Fix | Delete
when /\Ain(?:put)?_(.+)\Z/
[473] Fix | Delete
in_options[$1.to_sym] = value
[474] Fix | Delete
when /\Aout(?:put)?_(.+)\Z/
[475] Fix | Delete
out_options[$1.to_sym] = value
[476] Fix | Delete
else
[477] Fix | Delete
in_options[key] = value
[478] Fix | Delete
out_options[key] = value
[479] Fix | Delete
end
[480] Fix | Delete
end
[481] Fix | Delete
# build input and output wrappers
[482] Fix | Delete
input = new(input || ARGF, **in_options)
[483] Fix | Delete
output = new(output || $stdout, **out_options)
[484] Fix | Delete
[485] Fix | Delete
# read, yield, write
[486] Fix | Delete
input.each do |row|
[487] Fix | Delete
yield row
[488] Fix | Delete
output << row
[489] Fix | Delete
end
[490] Fix | Delete
end
[491] Fix | Delete
[492] Fix | Delete
#
[493] Fix | Delete
# This method is intended as the primary interface for reading CSV files. You
[494] Fix | Delete
# pass a +path+ and any +options+ you wish to set for the read. Each row of
[495] Fix | Delete
# file will be passed to the provided +block+ in turn.
[496] Fix | Delete
#
[497] Fix | Delete
# The +options+ parameter can be anything CSV::new() understands. This method
[498] Fix | Delete
# also understands an additional <tt>:encoding</tt> parameter that you can use
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function