Skip to content

Commit

Permalink
feat: Polish Ciris module (#188)
Browse files Browse the repository at this point in the history
  • Loading branch information
Iltotore authored Nov 1, 2023
1 parent 6e69410 commit 0871457
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ ivy"io.github.iltotore::iron:version"
| iron | ✔️ | ✔️ | ✔️ |
| iron-cats | ✔️ | ✔️ | ✔️ |
| iron-circe | ✔️ | ✔️ | ✔️ |
| iron-ciris | ✔️ | ✔️ | ✔️ |
| iron-jsoniter | ✔️ | ✔️ | ✔️ |
| iron-scalacheck | ✔️ | ✔️ ||
| iron-zio | ✔️ | ✔️ ||
Expand Down
1 change: 1 addition & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ object docs extends BaseModule {
def externalMappings = Map(
".*cats.*" -> ("scaladoc3", "https://javadoc.io/doc/org.typelevel/cats-docs_3/latest/"),
".*io.circe.*" -> ("scaladoc2", "https://circe.github.io/circe/api/"),
".*ciris.*" -> ("scaladoc2", "https://cir.is/api/"),
".*com.github.plokhotnyuk.jsoniter_scala.core.*" -> ("scaladoc3", "https://www.javadoc.io/doc/com.github.plokhotnyuk.jsoniter-scala/jsoniter-scala-core_3/latest/"),
".*zio.json.*" -> ("scaladoc3", "https://javadoc.io/doc/dev.zio/zio-json_3/latest/"),
".*zio.prelude.*" -> ("scaladoc3", "https://javadoc.io/doc/dev.zio/zio-prelude-docs_3/latest/"),
Expand Down
22 changes: 17 additions & 5 deletions ciris/src/io.github.iltotore.iron/ciris.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
package io.github.iltotore.iron

import _root_.ciris.ConfigDecoder
import cats.Show

import _root_.ciris.{ConfigDecoder, ConfigError}

object ciris:

inline given [T,A,B](using inline decoder: ConfigDecoder[T,A], inline constraint: _root_.io.github.iltotore.iron.Constraint[A, B], inline show: Show[A]): ConfigDecoder[T, A :| B] =
decoder.mapOption("")(_.refineOption)
/**
* A [[ConfigDecoder]] for refined types. Decodes to the underlying type then checks the constraint.
*
* @param decoder the [[ConfigDecoder]] of the underlying type
* @param constraint the [[Constraint]] implementation to test the decoded value
*/
inline given [In, A, C](using inline decoder: ConfigDecoder[In, A], inline constraint: Constraint[A, C]): ConfigDecoder[In, A :| C] =
decoder.mapEither((_, value) => value.refineEither[C].left.map(ConfigError(_)))

/**
* A [[ConfigDecoder]] for new types. Decodes to the underlying type then checks the constraint.
*
* @param decoder the [[ConfigDecoder]] of the underlying type.
* @param mirror the mirror of the [[RefinedTypeOps.Mirror]]
*/
inline given [In, T](using mirror: RefinedTypeOps.Mirror[T], decoder: ConfigDecoder[In, mirror.IronType]): ConfigDecoder[In, T] =
decoder.asInstanceOf[ConfigDecoder[In, T]]
19 changes: 11 additions & 8 deletions ciris/test/src/io/github/iltotore/iron/CirisSuite.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package io.github.iltotore.iron

import _root_.ciris.ConfigDecoder
import io.github.iltotore.iron.ciris.given
import io.github.iltotore.iron.constraint.numeric.Positive
import utest.*
import ciris.given


object CirisSuite extends TestSuite:
val tests: Tests = Tests {

test("summon String => Int :| Pure") {
summon[ ConfigDecoder[String, Int :| Pure]]
}
test("decoder") {
test("ironType") {
test("success") - assert(summon[ConfigDecoder[String, Int :| Positive]].decode(None, "5") == Right(5))
test("failure") - assert(summon[ConfigDecoder[String, Int :| Positive]].decode(None, "-5").isLeft)
}

test("summon from Int => Int :| Pure") {
summon[ConfigDecoder[Int, Int :| Pure]]
test("newType") {
test("success") - assert(summon[ConfigDecoder[String, Temperature]].decode(None, "5") == Right(Temperature(5)))
test("failure") - assert(summon[ConfigDecoder[String, Temperature]].decode(None, "-5").isLeft)
}
}
}

6 changes: 6 additions & 0 deletions ciris/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.iltotore.iron

import io.github.iltotore.iron.constraint.numeric.Positive

opaque type Temperature = Int :| Positive
object Temperature extends RefinedTypeOps[Int, Positive, Temperature]
59 changes: 59 additions & 0 deletions docs/_docs/modules/ciris.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: "Ciris Support"
---

# Ciris Support

This module provides refined types Encoder/Decoder instances for [Ciris](https://circe.github.io/circe/).

## Dependency

SBT:

```scala
libraryDependencies += "io.github.iltotore" %% "iron-ciris" % "version"
```

Mill:

```scala
ivy"io.github.iltotore::iron-ciris:version"
```

### Following examples' dependencies

SBT:

```scala
libraryDependencies += "is.cir" %% "ciris" % "3.1.0"
```

Mill:

```scala
ivy"is.cir::ciris::3.1.0"
```

## ConfigDecoder instances

Iron provides `ConfigDecoder` instances for refined types:

```scala
import cats.syntax.all.*
import ciris.*

import io.github.iltotore.iron.*
import io.github.iltotore.iron.constraint.all.*
import io.github.iltotore.iron.cats.given
import io.github.iltotore.iron.ciris.given

type Username = String :| (Not[Blank] & MaxLength[32])
type Password = String :| (Not[Blank] & MinLength[9])

case class DatabaseConfig(username: Username, password: Secret[Password])

val databaseConfig: ConfigValue[Effect, DatabaseConfig] = (
env("DB_USERNAME").as[Username],
env("DB_PASSWORD").as[Password].secret
).mapN(DatabaseConfig.apply)
```
1 change: 1 addition & 0 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ subsection:
subsection:
- page: modules/cats.md
- page: modules/circe.md
- page: modules/ciris.md
- page: modules/jsoniter.md
- page: modules/scalacheck.md
- page: modules/zio.md
Expand Down

0 comments on commit 0871457

Please sign in to comment.