Before we can even think about parsing CSV data, we need to have access to it somehow. kantan.csv extends most things
that “can be turned into CSV” with useful methods, such as the oft-used asCsvReader
method. Among such things are:
This is done through the CsvSource
type class: any type A
such that there exists a value of type
CsvSource[A]
in the implicit scope will be enriched with
useful methods.
Implementing your own instances of CsvSource
for types that aren’t supported by default is fairly simple.
Reduced to its simplest expression, a CsvSource
is essentially a A => ParseResult[Reader]
- that is, a function
that takes an A
and turns it into a Reader
, with the possibility of safe failure encoded in ParseResult
.
If you can write such a function, you can trivially turn it into a valid instance of CsvSource
- for example,
strings:
import kantan.csv._
import java.io._
implicit val stringSource: CsvSource[String] = CsvSource.from(s => ParseResult(new StringReader(s)))
Most of the time though, it’s easier to turn the type you wish to provide an instance for into a type that already
has an instance. This is achieved either through contramap
(if the transformation is safe and cannot fail) or
econtramap
(if, as with most IO-related things, it can fail). For example:
import kantan.csv._
import java.io._
implicit val stringInput: CsvSource[String] = CsvSource[Reader].contramap(s => new StringReader(s))