Skip to content

Code for SCALA-350 #1339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,14 @@ lazy val tapir = (project in file("scala-libraries-standalone/tapir"))
scalaVersion := scala3Version
)

lazy val refined = (project in file("scala-libraries-standalone/refined"))
.settings(
name := "refined",
scalaVersion := scalaV,
libraryDependencies += "eu.timepit" %% "refined" % "0.11.1",
libraryDependencies ++= scalaTestDeps
)

val spireVersion = "0.18.0"
val kafkaVersion = "7.6.1-ce"
val pureconfigVersion = "0.17.6"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.baeldung.refined

import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
import eu.timepit.refined.string._
import eu.timepit.refined.collection._
import eu.timepit.refined.char._
import eu.timepit.refined.boolean._
import eu.timepit.refined.api.Validate

object RefinedIntro {
// val oddNumber: Refined[Int, Odd] = 8
// val oddNumber: Int Refined Odd = 8

val age: Int Refined Less[35] = 30
val ageInterval: Int Refined Interval.Closed[30, 35] = 35
val age2: Int Refined GreaterEqual[35] = 35
val ageInput: Int = 36
val ageCheck = refineV[GreaterEqual[35]](ageInput)

val myDigit: Char Refined Digit = '8'
val myLetter: Char Refined Letter = 'H'

val myName: String Refined StartsWith["S"] = "Sandra"
val myName2: String Refined EndsWith["t"] = "Herbert"
// val myName3: String Refined StartsWith["s"] = "Sandra"
// val myAddr: String Refined IPv6 = "127.0.0.1"

type myRegex = MatchesRegex["""[A-Za-z0-9]+"""]
val accessCode: String Refined myRegex = "DC13h"

type myIntRegex = myRegex And ValidInt
val accessCode2: String Refined myIntRegex = "97426"
// val accessCode3: String Refined myIntRegex = "9742B"

val fruits = List("Banana", "Orange", "Lemon", "Guava")
val contains = refineV[Contains["Berry"]](fruits)
val forall = refineV[Forall[Trimmed]](fruits)
val last = refineV[Last[Uuid]](fruits)
val size = refineV[Size[Less[5]]](fruits)

case class Person(name: String, height: Double)
case class Tall()
case class Average()
case class Short()

implicit val tallValidate: Validate.Plain[Person, Tall] =
Validate.fromPredicate(
p => p.height >= 6.0,
p => s"(${p.name} is tall)",
Tall()
)

implicit val averageValidate: Validate.Plain[Person, Average] =
Validate.fromPredicate(
p => p.height >= 5.0 && p.height < 6.0,
p => s"(${p.name} is average)",
Average()
)

implicit val shortValidate: Validate.Plain[Person, Short] =
Validate.fromPredicate(
p => p.height < 5.0,
p => s"(${p.name} is short)",
Short()
)

val tall = refineV[Tall](Person("Herbert", 5.5))
val average = refineV[Average](Person("Herbert", 5.5))
}

object Hello extends App {
import RefinedIntro._
println(refineV[Short](Person("Herbert", 4.0)))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.baeldung.refined

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
import eu.timepit.refined.string._
import eu.timepit.refined.collection._
import eu.timepit.refined.char._
import eu.timepit.refined.boolean._
import eu.timepit.refined.api.Validate
import scala.util.{Right, Left}

class RefinedUnitTest extends AnyFlatSpec with Matchers {
import RefinedIntro.{size => sizeTest, _}

"Int checks" should "pass with refined types" in {
assert(refineV[Odd](8) == Left("Predicate (8 % 2 == 0) did not fail."))
age shouldBe an[Int Refined Less[35]]
ageInterval shouldBe an[Int Refined Interval.Closed[30, 35]]
age2 shouldBe an[Int Refined GreaterEqual[35]]
ageInput shouldBe an[Int]
ageCheck shouldBe an[Either[String, Refined[Int, GreaterEqual[35]]]]
}

"Char checks" should "pass for refined types" in {
assert(myDigit.isInstanceOf[Char Refined Digit])
assert(myLetter.isInstanceOf[Char Refined Letter])
}

"String checks" should "pass for refined types" in {
assert(
refineV[StartsWith["s"]]("Sandra") == Left(
"Predicate failed: \"Sandra\".startsWith(\"s\")."
)
)
assert(
refineV[IPv6]("127.0.0.1") == Left(
"Predicate failed: 127.0.0.1 is a valid IPv6."
)
)
assert(myName.isInstanceOf[String Refined StartsWith["S"]])
assert(myName2.isInstanceOf[String Refined EndsWith["t"]])
}

"Regex checks" should "pass for refined types" in {
assert(
refineV[myIntRegex]("9742B") == Left(
"Right predicate of (\"9742B\".matches(\"[A-Za-z0-9]+\") && isValidValidInt(\"9742B\")) failed: ValidInt predicate failed: For input string: \"9742B\""
)
)
assert(accessCode.isInstanceOf[String Refined myRegex])

assert(accessCode2.isInstanceOf[String Refined myIntRegex])
}

"collection checks" should "pass for refined types" in {
assert(
forall
.isInstanceOf[Either[String, Refined[List[String], Forall[Trimmed]]]]
)
assert(last.isInstanceOf[Either[String, Refined[List[String], Last[Uuid]]]])
assert(
sizeTest
.isInstanceOf[Either[String, Refined[List[String], Size[Less[5]]]]]
)
}

"Person checks" should "pass for custom refined types" in {
assert(tall.isInstanceOf[Either[String, Refined[Person, Tall]]])
assert(average.isInstanceOf[Either[String, Refined[Person, Average]]])
}
}