Skip to content

Commit

Permalink
add: Deprecation to .refine, introduce .refineUnsafe instead (#204)
Browse files Browse the repository at this point in the history
Fixes #203
  • Loading branch information
matwojcik authored Jan 8, 2024
1 parent 1b5abea commit 3c8f4ec
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ log(1.0) //Automatically verified at compile time.
log(-1.0) //Compile-time error: Should be strictly positive

val runtimeValue: Double = ???
log(runtimeValue.refine) //Explicitly refine your external values at runtime.
log(runtimeValue.refineUnsafe) //Explicitly refine your external values at runtime.

runtimeValue.refineEither.map(log) //Use monadic style for functional validation
runtimeValue.refineEither[Positive].map(log) //More explicitly
Expand Down
2 changes: 1 addition & 1 deletion docs/_docs/modules/cats.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ import io.github.iltotore.iron.constraint.all.*
//}
import io.github.iltotore.iron.cats.given

val name1: String :| Alphanumeric = "Martin".refine
val name1: String :| Alphanumeric = "Martin".refineUnsafe
val name2: String :| Alphanumeric = "George"
val age1: Int :| Greater[0] = 60

Expand Down
2 changes: 1 addition & 1 deletion docs/_docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ case class User(age: Int :| Positive)
```scala sc-compile-with:BetterUser.scala
User(1) //Compiles
User(-1) //Does not compile
User(-1.refine) //Compiles but fails at runtime. Useful for runtime checks such as form validation.
User(-1.refineUnsafe) //Compiles but fails at runtime. Useful for runtime checks such as form validation.
//See also `refineOption` and `refineEither`
```

Expand Down
2 changes: 1 addition & 1 deletion docs/_docs/reference/refinement.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ You can imperatively refine a value at runtime (much like an assertion) using th

```scala
val runtimeString: String = ???
val username: String :| Alphanumeric = runtimeString.refine //or more explicitly, refine[LowerCase].
val username: String :| Alphanumeric = runtimeString.refineUnsafe //or more explicitly, refineUnsafe[LowerCase].
```

The `refine` extension method tests the constraint at runtime, throwing an `IllegalArgumentException` if the value
Expand Down
16 changes: 14 additions & 2 deletions main/src/io/github/iltotore/iron/conversion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,22 @@ extension [A, C1](value: A :| C1)
* @param constraint the new constraint to test.
* @return this value refined with `C1 & C2`.
* @throws an [[IllegalArgumentException]] if the constraint is not satisfied.
* @see [[refine]].
* @see [[refineUnsafe]].
*/
@deprecated("Use refineFurtherUnsafe instead. refineFurther will be removed in 3.0")
inline def refineFurther[C2](using inline constraint: Constraint[A, C2]): A :| (C1 & C2) =
(value: A).refine[C2].assumeFurther[C1]
refineFurtherUnsafe[C2]

/**
* Refine the given value again at runtime.
*
* @param constraint the new constraint to test.
* @return this value refined with `C1 & C2`.
* @throws an [[IllegalArgumentException]] if the constraint is not satisfied.
* @see [[refineUnsafe]].
*/
inline def refineFurtherUnsafe[C2](using inline constraint: Constraint[A, C2]): A :| (C1 & C2) =
(value: A).refineUnsafe[C2].assumeFurther[C1]

/**
* Refine the given value again at runtime, resulting in an [[Either]].
Expand Down
22 changes: 17 additions & 5 deletions main/src/io/github/iltotore/iron/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ object IronType:
* @tparam A the refined type.
* @tparam C the constraint applied to the type.
* @return the given value typed as [[IronType]].
* @note this does not check if the constraint is satisfied. Use [[package.refine]] to refine a value at runtime.
* @see [[package.autoRefine]], [[package.refine]], [[package.refineEither]], [[package.refineOption]]
* @note this does not check if the constraint is satisfied. Use [[package.refineUnsafe]] to refine a value at runtime.
* @see [[package.autoRefine]], [[package.refineUnsafe]], [[package.refineEither]], [[package.refineOption]]
*/
inline def apply[A, C](value: A): IronType[A, C] = value

Expand All @@ -52,7 +52,7 @@ extension [A](value: A)
*
* @param constraint the constraint to test with the value to refine.
* @return a constrained value, without performing constraint checks.
* @see [[autoRefine]], [[refine]].
* @see [[autoRefine]], [[refineUnsafe]].
*/
inline def assume[B]: A :| B = value

Expand All @@ -64,7 +64,19 @@ extension [A](value: A)
* @throws an [[IllegalArgumentException]] if the constraint is not satisfied.
* @see [[autoRefine]], [[refineEither]], [[refineOption]].
*/
@deprecated("Use refineUnsafe instead. refine will be removed in 3.0.0")
inline def refine[B](using inline constraint: Constraint[A, B]): A :| B =
refineUnsafe[B]

/**
* Refine the given value at runtime.
*
* @param constraint the constraint to test with the value to refine.
* @return this value as [[IronType]].
* @throws an [[IllegalArgumentException]] if the constraint is not satisfied.
* @see [[autoRefine]], [[refineEither]], [[refineOption]].
*/
inline def refineUnsafe[B](using inline constraint: Constraint[A, B]): A :| B =
if constraint.test(value) then value
else throw IllegalArgumentException(constraint.message)

Expand All @@ -73,7 +85,7 @@ extension [A](value: A)
*
* @param constraint the constraint to test with the value to refine.
* @return a [[Right]] containing this value as [[IronType]] or a [[Left]] containing the constraint message.
* @see [[autoRefine]], [[refine]], [[refineOption]].
* @see [[autoRefine]], [[refineUnsafe]], [[refineOption]].
*/
inline def refineEither[B](using inline constraint: Constraint[A, B]): Either[String, A :| B] =
Either.cond(constraint.test(value), value, constraint.message)
Expand All @@ -83,7 +95,7 @@ extension [A](value: A)
*
* @param constraint the constraint to test with the value to refine.
* @return an Option containing this value as [[IronType]] or [[None]].
* @see [[autoRefine]], [[refine]], [[refineEither]].
* @see [[autoRefine]], [[refineUnsafe]], [[refineEither]].
*/
inline def refineOption[B](using inline constraint: Constraint[A, B]): Option[A :| B] =
Option.when(constraint.test(value))(value)

0 comments on commit 3c8f4ec

Please sign in to comment.