Created
August 25, 2020 07:43
-
-
Save otobrglez/c989c2f1d93f1b97aa6806449eaf1942 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.opalab.experimental | |
import java.io.File | |
import cats.data.NonEmptyChain | |
import cats.implicits._ | |
import io.circe.syntax._ | |
import scala.io.Source | |
import scala.util.Using | |
object ErrorApp extends App { | |
/** | |
* The functions reads "File" and returns String or Exception (Throwable). | |
* Internally function also handles resource allocation and releasing. | |
* Response is String; however it could also be a stream or similar structure. | |
*/ | |
val read: File => Either[Throwable, String] = | |
file => Using(Source.fromFile(file))(_.mkString.strip).toEither | |
/** | |
* Function reads file withing users "home directory" (i.e. "~") and | |
* returns either content as a String or Throwable. | |
*/ | |
val fromHome: String => Either[Throwable, String] = | |
s => System.getProperty("user.home").some.map(_ + s) | |
.map(new File(_)).foldMap(read) | |
/** | |
* Function reads "username" that is located in a file called ".user-name", | |
* that is located inside users home directory. If something goes wrong | |
* internally the method returns String "Anonymous" instead of username. | |
* | |
* Note: This is bad practice as it overshadows critical path. | |
*/ | |
val username: String = | |
fromHome("/.user-name").fold(_ => "Anonymous", (s: String) => s) | |
/** | |
* Function combines two streams and validates them. | |
* It is possible to do this in parallel and/or retry | |
* or even proceed in case of exceptions. | |
*/ | |
def readUserStreams: Either[NonEmptyChain[Throwable], List[String]] = | |
( | |
fromHome("/.user-stream-new").toValidatedNec, | |
fromHome("/.user-stream-old").toValidatedNec) | |
.mapN((a: String, b: String) => List(a, b)) | |
.toEither | |
/** | |
* The "app" function that combines high-level logic, | |
* rendering to JSON and output. | |
* | |
* Note: See how here only "happy path" is handled. | |
*/ | |
val app = for { | |
streams <- readUserStreams | |
} yield Map("username" -> username).asJson.deepMerge( | |
Map("stream" -> streams).asJson).noSpaces | |
/** | |
* This is the so called "end-of-the-world" where the "run" | |
* is actually evaluated and outputs to command line. | |
*/ | |
app match { | |
case Right(value) => | |
System.out.println(value) | |
System.exit(0) | |
case Left(error) => | |
System.err.println(error.map(_.getMessage).mkString_("\n")) | |
System.exit(1) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment