jcouyang/dhall-generic
Dhall generic decoder for Scala
{ "createdAt": "2020-10-12T12:42:53Z", "defaultBranch": "master", "description": "Dhall generic decoder for Scala", "fullName": "jcouyang/dhall-generic", "homepage": "", "language": "Scala", "name": "dhall-generic", "pushedAt": "2024-12-03T19:06:50Z", "stargazersCount": 46, "topics": [ "dhall", "scala" ], "updatedAt": "2025-03-18T12:59:27Z", "url": "https://github.com/jcouyang/dhall-generic"}Dhall Scala Generic
Section titled “Dhall Scala Generic”Load Dhall config directly into Scala case class
libraryDependencies += "us.oyanglul" %% "dhall-generic" % "0.3.+"There is a dhall config
let Shape = <Rectangle: {width: Double, height: Double}| Circle: {radius: Double}>in Shape.Circle {radius = 1.2}And you can parse them into dhall Expr
import org.dhallj.syntax._
val expr = """let Shape = <Rectangle: {width: Double, height: Double}| Circle: {radius: Double}>in Shape.Circle {radius = 1.2}""".parseExprScala 3
Section titled “Scala 3”Supposed that you have some Scala case classes
enum Shape: case Rectangle(width: Double, height: Double) case Circle(radius: Double)to load a dhall expr into Scala case classes, simply just
derives Decoder
import us.oyanglul.dhall.generic.Decoder
enum Shape derives Decoder: // derive will generate decoder inline case Rectangle(width: Double, height: Double) case Circle(radius: Double)as[Shape]
import us.oyanglul.dhall.generic.as
expr.normalize.as[Shape]// => Right(Circle(1.2)): Either[DecodingFailure, Shape]Scala 2
Section titled “Scala 2”Supposed that you have some Scala case classes
sealed trait Shapeobject Shape { case class Rectangle(width: Double, height: Double) extends Shape case class Circle(radius: Double) extends Shape}to load a dhall expr into Scala case classes, simply just
import org.dhallj.codec.syntax._ // for `.as[A]` syntaximport org.dhallj.codec.Decoder._ // Decoders for primity typesimport us.oyanglul.dhall.generic._ // generate generic decoders
expr.normalize.as[Shape]// => Right(Circle(1.2)): Either[DecodingFailure, Shape]Use cases
Section titled “Use cases”Load application config
Section titled “Load application config”It is very simple to replace HOCON application.conf with dhall.
To load src/main/resources/application.dhall from classpath your will need dhall-imports
import org.dhallj.syntax._import org.dhallj.codec.syntax._import us.oyanglul.dhall.generic._import org.dhallj.imports.syntax._
BlazeClientBuilder[IO]!(ExecutionContext.global).resource.use { implicit c => IO.fromEither("classpath:/application.dhall".parseExpr) .flatMap(_.resolveImports[IO]) .flatMap{expr => IO.fromEither(expr.normalize.as[Config])} }Load dhall to sbt libraryDependencies
Section titled “Load dhall to sbt libraryDependencies”This project itself is an example of how to load dhall into build.sbt
It is recursively using [previous version]!(./project/build.sbt#L4) [to load]!(./project/loadDhall.scala) [./build.dhall]!(./build.dhall) to libraryDependencies
libraryDependencies ++= dhall.load.modules.map{case Module(o, n, v) => o %% n % v},Custom Decoder
Section titled “Custom Decoder”Create new decoder from existing decoder
i.e. UUID
Scala 3
Section titled “Scala 3”given (using d: Decoder[String]): Decoder[UUID] = d.map(UUID.fromString)Scala 2
Section titled “Scala 2”implicit val decodeUUID: Decoder[UUID] = decodeString.map(UUID.from)