Skip to content

Commit

Permalink
docs: Add iron-borer documentation (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
sirthias authored Jan 25, 2024
1 parent d1ed618 commit 7ea9d47
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ivy"io.github.iltotore::iron:version"
| Module | JVM | JS | Native |
|-----------------|-----|----|--------|
| iron | ✔️ | ✔️ | ✔️ |
| iron-borer | ✔️ | ✔️ ||
| iron-cats | ✔️ | ✔️ | ✔️ |
| iron-circe | ✔️ | ✔️ | ✔️ |
| iron-ciris | ✔️ | ✔️ | ✔️ |
Expand Down
3 changes: 1 addition & 2 deletions borer/test/src/io/github/iltotore/iron/BorerSuite.scala
Original file line number Diff line number Diff line change
@@ -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:

Expand Down
Original file line number Diff line number Diff line change
@@ -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

/**
Expand Down
105 changes: 105 additions & 0 deletions docs/_docs/modules/borer.md
Original file line number Diff line number Diff line change
@@ -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
}
```
1 change: 1 addition & 0 deletions docs/_docs/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -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 =

Expand Down

0 comments on commit 7ea9d47

Please sign in to comment.