+ # Load from the specified stream.
+ #
+ # Parameters:
+ #
+ # * `stream`: Input stream.
+ # * `has_header`: Is the first record the header? - defaults to true
+ # * `skip_empty`: Do we skip the empty lines? - defaults to true
+ fun load_from(stream: Reader, has_header: nullable Bool, skip_empty: nullable Bool) do
+ if has_header == null then has_header = true
+ if skip_empty == null then skip_empty = true
+ var reader = new CsvReader(stream)
+ reader.separator = separator
+ reader.eol = eol
+ reader.delimiter = delimiter
+ reader.skip_empty = skip_empty
+ end
+end
+
+# Appends CSV records to a file.
+#
+# By default, uses the format recommended by RFC 4180 (see `rfc4180`).
+#
+# Note: If a record contains only an empty cell, its representation is
+# undistinguishable from an empty line. This is because the empty values are
+# always written unescaped in order to avoid them to be interpreted as escaped
+# delimiters by some parsers.
+#
+# ~~~nit
+# var out = new StringWriter
+# var writer = new CsvWriter(out)
+# writer.write_elements(1, 2.0, "foo\nbar")
+# writer.write_line([""])
+# assert out.to_s == """1,2.0,"foo\nbar"\n\n"""
+# ~~~
+class CsvWriter
+ super CsvStream
+
+ # The output stream.
+ var ostream: Writer
+
+ # Write several lines to a stream
+ fun write_lines(lines: Array[Array[Object]]) do for i in lines do write_line i
+
+ # Append the elements in `els` as a record.
+ #
+ # The representation of each cell is determined by `to_s`.
+ fun write_elements(els: Object...) do
+ var os = ostream
+ var esc = delimiter
+ var sep = separator
+ var eol = eol
+ for i in [0 .. els.length - 1[ do
+ os.write(els[i].to_s.escape_to_csv(sep, esc, eol))
+ os.write_char(sep)