Using TMaps for error handling
| Welcome to Scala version 2.10.4 (OpenJDK 64-Bit Server VM, Java 1.6.0_27). | |
| Type in expressions to have them evaluated. | |
| Type :help for more information. | |
| // Import the Rapture modules we need | |
| scala> import rapture._, uri._, codec._, io._, fs._, core._, csv._ | |
| import rapture._ | |
| import uri._ | |
| import codec._ | |
| import io._ | |
| import fs._ | |
| import core._ | |
| import csv._ | |
| // Import some more configuration context | |
| scala> import csvBackends.simple._, encodings.`UTF-8`._, platform.posix | |
| import csvBackends.simple._ | |
| import encodings.UTF$minus8._ | |
| import platform.adaptive | |
| // We use the `returnOutcome` mode which collects failures, without throwing; like a Scalaz Validation. | |
| scala> import modes.returnOutcome._ | |
| import modes.returnOutcome._ | |
| // We attempt to parse the contents of a URI from a local file | |
| scala> val csv = Csv.parse(uri"file:///home/jpretty/consts.csv") | |
| csv: rapture.core.Outcome[rapture.csv.Csv,rapture.csv.CsvParseException] = | |
| Result(Csv( | |
| "ID","Name","Value" | |
| "1","pi","3.14159" | |
| "2","e","2.718" | |
| )) | |
| // We got a successful `Result`, as the CSV parsed successfully. Note that the return type includes a `CsvParseException`, | |
| // indicating that this was a possible failure. | |
| // As it was successful, we can get the `result` out of the `Outcome`. | |
| scala> val csv2 = csv.result | |
| csv2: rapture.csv.Csv = | |
| Csv( | |
| "ID","Name","Value" | |
| "1","pi","3.14159" | |
| "2","e","2.718" | |
| ) | |
| // We will attempt to extract a `Const` from a row in the CSV file, so we define it as a case class. (Note that an implicit | |
| // extractor for this type will be automatically generated by a macro) | |
| scala> case class Const(id: Int, name: String, value: Double) | |
| defined class Const | |
| // Let's try to read the first line as a `Const`. | |
| scala> val header = csv2.rows.head.as[Const] | |
| header: rapture.core.Outcome[Const,rapture.csv.CsvGetException] = | |
| Problems( | |
| rapture.csv.CsvGetException | |
| type mismatch: Could not read value of type integer in column 0 | |
| type mismatch: Could not read value of type double in column 2 | |
| ) | |
| // This failed because the first line contains headers, so we get a `Problems` type returned. Note that this encapsulates two | |
| // separate problems. If using a different Rapture mode, then usually only the first exception would be reported. | |
| // Note also that, unlike the first `Outcome`, this one is typed on `CsvGetException`. | |
| // Now, let's try the same thing in a single line using for-comprehension style. This is allowed because `Outcome`s have | |
| // `map` and `flatMap` defined on them. | |
| scala> val c = for(csv <- Csv.parse(uri"file:///home/jpretty/consts.csv"); const <- csv.rows.head.as[Const]) yield const | |
| c: rapture.core.Outcome[Const,rapture.csv.CsvParseException with rapture.csv.CsvGetException] = | |
| Problems( | |
| rapture.csv.CsvGetException: | |
| type mismatch: Could not read value of type integer in column 0 | |
| type mismatch: Could not read value of type double in column 2 | |
| ) | |
| // As before, we get the same list of problems, but note that the `Outcome` type is now parameterized on `CsvParseException | |
| // with CsvGetException`; either exception type could be responsible for the failure. | |
| // Are there any `CsvParseException`s? No. | |
| scala> c.problems[CsvParseException] | |
| res0: Vector[rapture.csv.CsvParseException] = Vector() | |
| // Are there any `CsvGetException`s? Yes! | |
| scala> c.problems[CsvGetException] | |
| res1: Vector[rapture.csv.CsvGetException] = Vector(rapture.csv.CsvTypeMismatch: type mismatch: Could not read value of type integer in column 0, rapture.csv.CsvTypeMismatch: type mismatch: Could not read value of type double in column 2) | |
| // Are there any `NullPointerException`s? No - that doesn't even compile! | |
| scala> c.problems[NullPointerException] | |
| <console>:43: error: type arguments [NullPointerException] do not conform to method problems's type parameter bounds [E2 >: rapture.csv.CsvParseException with rapture.csv.CsvGetException] | |
| c.problems[NullPointerException] | |
| ^ | |
| // So, let's report the problems | |
| scala> c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear.") } | |
| <console>:43: warning: match may not be exhaustive. | |
| It would fail on the following inputs: CsvMissingValue(_) | |
| c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear.") } | |
| ^ | |
| Oh dear. | |
| Oh dear. | |
| // This worked, but the compiler reported a warning. It turns out that CsvGetException is a sealed supertrait of two possible | |
| // sorts of failure: `CsvTypeMismatch` and `CsvMissingValue`. To make the warning go away, we need to handle both cases: | |
| scala> c.problems[CsvGetException].foreach { case CsvTypeMismatch(t, c) => println("Oh dear."); case CsvMissingValue(c) => "What?" } | |
| Oh dear. | |
| Oh dear. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment