From 7ea9d47a48cacb205e37acd862790aa928b169b0 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 25 Jan 2024 17:07:28 +0100 Subject: [PATCH] docs: Add `iron-borer` documentation (#211) --- README.md | 1 + .../io/github/iltotore/iron/BorerSuite.scala | 3 +- .../iltotore/iron/RefinedOpsTypes.scala | 2 +- docs/_docs/modules/borer.md | 105 ++++++++++++++++++ docs/_docs/modules/index.md | 1 + docs/sidebar.yml | 1 + .../Account.scala | 11 +- .../main.scala | 4 +- 8 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 docs/_docs/modules/borer.md rename examples/borerSerialization/src/io/github/iltotore/iron/{formBorer => borerSerialization}/Account.scala (76%) rename examples/borerSerialization/src/io/github/iltotore/iron/{formBorer => borerSerialization}/main.scala (91%) diff --git a/README.md b/README.md index 07802b35..30e874fd 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ ivy"io.github.iltotore::iron:version" | Module | JVM | JS | Native | |-----------------|-----|----|--------| | iron | ✔️ | ✔️ | ✔️ | +| iron-borer | ✔️ | ✔️ | ❌ | | iron-cats | ✔️ | ✔️ | ✔️ | | iron-circe | ✔️ | ✔️ | ✔️ | | iron-ciris | ✔️ | ✔️ | ✔️ | diff --git a/borer/test/src/io/github/iltotore/iron/BorerSuite.scala b/borer/test/src/io/github/iltotore/iron/BorerSuite.scala index 4b4d5a61..0cd35ff9 100644 --- a/borer/test/src/io/github/iltotore/iron/BorerSuite.scala +++ b/borer/test/src/io/github/iltotore/iron/BorerSuite.scala @@ -1,9 +1,8 @@ package io.github.iltotore.iron -import io.github.iltotore.iron.constraint.all.* +import io.bullet.borer.{Encoder, Json} import io.github.iltotore.iron.borer.given import utest.* -import io.bullet.borer.{Encoder, Json} object BorerSuite extends TestSuite: diff --git a/borer/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala b/borer/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala index ac29b8a4..31d9d4ff 100644 --- a/borer/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala +++ b/borer/test/src/io/github/iltotore/iron/RefinedOpsTypes.scala @@ -1,6 +1,6 @@ package io.github.iltotore.iron -import io.github.iltotore.iron.* +import io.github.iltotore.iron.RefinedTypeOps import io.github.iltotore.iron.constraint.numeric.Positive /** diff --git a/docs/_docs/modules/borer.md b/docs/_docs/modules/borer.md new file mode 100644 index 00000000..d47636a8 --- /dev/null +++ b/docs/_docs/modules/borer.md @@ -0,0 +1,105 @@ +--- +title: "Borer Support" +--- + +# Borer Support + +This module provides refined types Encoder/Decoder instances for [borer](https://sirthias.github.io/borer/). + +## Dependency + +SBT: + +```scala +libraryDependencies += "io.github.iltotore" %% "iron-borer" % "version" +``` + +Mill: + +```scala +ivy"io.github.iltotore::iron-borer:version" +``` + +### Example Dependencies + +SBT: + +```scala +libraryDependencies ++= Seq( + "io.bullet" %% "borer-core" % "1.13.0", + "io.bullet" %% "borer-derivation" % "1.13.0" +) +``` + +Mill: + +```scala +ivy"io.bullet::borer-core::1.13.0" +ivy"io.bullet::borer-derivation::1.13.0" +``` + +## How to use + +This example shows how to integrate _iron_ with [borer](https://sirthias.github.io/borer/). + +After having added the above dependencies you enable the integration layer with this import: + +```scala +import io.github.iltotore.iron.borer.given +``` + +With this in place all refined types `T` automatically have _borer_ `Encoder[T]` and `Decoder[T]` +instances available, as long as the respective Encoders and Decoders for the (unrefined) underlying types are already +`given`. + +If a refinement error is triggered during decoding because the decoded value doesn't match the refinement condition(s) +decoding will fail with a `Borer.Error.ValidationFailure`. + + +Here is a simple example (which can also be found [here](https://github.com/Iltotore/iron/tree/main/examples/borerSerialization)): + +```scala +import io.bullet.borer.{Codec, Json} +import io.bullet.borer.derivation.MapBasedCodecs.* +import io.github.iltotore.iron.constraint.all.* +import io.github.iltotore.iron.* +import io.github.iltotore.iron.borer.given // this enables borer <-> iron integration + +type Username = (Alphanumeric & MinLength[3] & MaxLength[10]) DescribedAs + "Username should be alphanumeric and have a length between 3 and 10" + +type Password = (Match["[A-Za-z].*[0-9]|[0-9].*[A-Za-z]"] & MinLength[6] & MaxLength[20]) DescribedAs + "Password must contain at least a letter, a digit and have a length between 6 and 20" + +type Age = Greater[0] DescribedAs + "Age should be strictly positive" + +case class Account( + name: String :| Username, + password: String :| Password, + age: Int :| Age +) derives Codec // relies on the MapBasedCodecs imported above + +val account = Account( + name = "matt", + password = "bar123", + age = 42 +) + +val okValidEncoding = """{"name":"matt","password":"bar123","age":42}""" +val invalidEncoding = """{"name":"matt","password":"bar","age":42}""" + +val encoding = Json.encode(account).toUtf8String +assert(encoding == okValidEncoding) + +val decoding = Json.decode(okValidEncoding.getBytes).to[Account].valueEither +assert(decoding == Right(account)) + +val decoding2 = Json.decode(invalidEncoding.getBytes).to[Account].valueEither +decoding2 match { + case Left(e: Borer.Error.ValidationFailure[_]) => + // "Password must contain at least a letter, a digit and have a length between 6 and 20 (input position 26)" + println(e.getMessage) + case _ => throw new IllegalStateException +} +``` \ No newline at end of file diff --git a/docs/_docs/modules/index.md b/docs/_docs/modules/index.md index 6d63e845..bc49d017 100644 --- a/docs/_docs/modules/index.md +++ b/docs/_docs/modules/index.md @@ -9,6 +9,7 @@ Find documentation about Iron's external modules. These modules are mostly "support"/"interoperability" modules to provide out of the box features to make Iron work seamlessly with other ecosystems. ## Official modules +- [Borer](borer.md): Typeclass instances for refinement types. - [Cats](cats.md): Typeclass instances and accumulative refinement methods. - [Circe](circe.md): Typeclass instances for refinement types. - [Ciris](ciris.md): Typeclass instances for refinement types. diff --git a/docs/sidebar.yml b/docs/sidebar.yml index 4b89789b..02d6c1b8 100644 --- a/docs/sidebar.yml +++ b/docs/sidebar.yml @@ -18,6 +18,7 @@ subsection: directory: modules index: modules/index.md subsection: + - page: modules/borer.md - page: modules/cats.md - page: modules/circe.md - page: modules/ciris.md diff --git a/examples/borerSerialization/src/io/github/iltotore/iron/formBorer/Account.scala b/examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/Account.scala similarity index 76% rename from examples/borerSerialization/src/io/github/iltotore/iron/formBorer/Account.scala rename to examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/Account.scala index 0e0bdcb3..208d503c 100644 --- a/examples/borerSerialization/src/io/github/iltotore/iron/formBorer/Account.scala +++ b/examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/Account.scala @@ -1,9 +1,9 @@ -package io.github.iltotore.iron.formBorer +package io.github.iltotore.iron.borerSerialization import io.bullet.borer.Codec -import io.bullet.borer.derivation.MapBasedCodecs +import io.bullet.borer.derivation.MapBasedCodecs.* import io.github.iltotore.iron.constraint.all.* -import io.github.iltotore.iron.{*, given} +import io.github.iltotore.iron.* import io.github.iltotore.iron.borer.given // this enables borer <-> iron integration type Username = (Alphanumeric & MinLength[3] & MaxLength[10]) DescribedAs @@ -19,7 +19,4 @@ case class Account( name: String :| Username, password: String :| Password, age: Int :| Age -) - -object Account: - given Codec[Account] = MapBasedCodecs.deriveCodec +) derives Codec \ No newline at end of file diff --git a/examples/borerSerialization/src/io/github/iltotore/iron/formBorer/main.scala b/examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/main.scala similarity index 91% rename from examples/borerSerialization/src/io/github/iltotore/iron/formBorer/main.scala rename to examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/main.scala index 10b09561..e5de9953 100644 --- a/examples/borerSerialization/src/io/github/iltotore/iron/formBorer/main.scala +++ b/examples/borerSerialization/src/io/github/iltotore/iron/borerSerialization/main.scala @@ -1,7 +1,7 @@ -package io.github.iltotore.iron.formBorer +package io.github.iltotore.iron.borerSerialization import io.bullet.borer.{Borer, Json} -import io.github.iltotore.iron.{*, given} +import io.github.iltotore.iron.* @main def main: Unit =