Skip to content

Instantly share code, notes, and snippets.

@CJSmith-0141
Created February 10, 2025 02:01
Show Gist options
  • Select an option

  • Save CJSmith-0141/c7cf1fa06408be51f39de1e9e2f95eeb to your computer and use it in GitHub Desktop.

Select an option

Save CJSmith-0141/c7cf1fa06408be51f39de1e9e2f95eeb to your computer and use it in GitHub Desktop.
Quick example using Iron with an optional refined type

If you have scala-cli installed, you can run the file like a script. Just download it and run chmod +x iron.scala && ./iron.scala

#!/usr/bin/env -S scala-cli shebang -S 3
//> using toolkit typelevel:default
//> using dep io.github.iltotore::iron:2.6.0
//> using dep io.github.iltotore::iron-cats:2.6.0
//> using dep io.github.iltotore::iron-circe:2.6.0
import cats.*
import cats.data.EitherNec
import cats.data.NonEmptyChain
import cats.effect.*
import cats.effect.std.Console
import cats.syntax.all.*
import io.circe.*
import io.circe.derivation.*
import io.circe.syntax.*
import io.github.iltotore.iron.*
import io.github.iltotore.iron.cats.*
import io.github.iltotore.iron.circe.given
import io.github.iltotore.iron.constraint.all.*
given Configuration = Configuration.default.withSnakeCaseMemberNames
type ValidName = DescribedAs[Head[Letter] & MinLength[1], "a name is required, must start with a letter"]
type ValidTitle = DescribedAs[Head[Letter] & MinLength[1], "the title cannot be blank, must start with a letter"]
case class Person(name: String :| ValidName, title: Option[String :| ValidTitle]) derives ConfiguredCodec
object Person:
def create(name: String, title: Option[String]): EitherNec[String, Person] =
(name.refineNec[ValidName], title.traverse(_.refineNec[ValidTitle])).parMapN(Person.apply)
object EitherNecIOOps:
extension [E: Show, A](nec: EitherNec[E, A])
def liftToIO: IO[A] = nec.leftMap(c => IllegalArgumentException(c.show)).liftTo[IO]
type NecStringThrow <: IllegalArgumentException
object NecStringThrow:
def apply(c: NonEmptyChain[String]): NecStringThrow =
new IllegalArgumentException(c.show).asInstanceOf[NecStringThrow]
object app extends IOApp.Simple:
import EitherNecIOOps.*
override def run: IO[Unit] = for
_ <- Console[IO].println("enter name")
n <- Console[IO].readLine
_ <- Console[IO].println("enter title (leave blank for no title)")
t <- Console[IO].readLine
tV = if (t.isEmpty()) then None else Some(t)
person <- Person.create(n, tV).liftToIO
_ <- IO.println(person)
_ <- IO.println(person.asJson.spaces2)
yield ExitCode.Success
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment