-
Notifications
You must be signed in to change notification settings - Fork 153
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #456 from umbreak/shapeless_typeable
Added support to generate a Typeable for a refined type
Showing
4 changed files
with
98 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
modules/shapeless/shared/src/main/scala/eu/timepit/refined/shapeless/typeable.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package eu.timepit.refined.shapeless | ||
|
||
import _root_.shapeless.Typeable | ||
import eu.timepit.refined.api.{RefType, Validate} | ||
import scala.util.Right | ||
|
||
package object typeable { | ||
|
||
/** | ||
* `Typeable` instance for refined types. | ||
*/ | ||
implicit def refTypeTypeable[F[_, _], T, P](implicit rt: RefType[F], | ||
V: Validate[T, P], | ||
T: Typeable[T], | ||
P: Typeable[P]): Typeable[F[T, P]] = | ||
new Typeable[F[T, P]] { | ||
override def cast(t: Any): Option[F[T, P]] = | ||
T.cast(t) | ||
.flatMap(casted => | ||
rt.refine[P](casted) match { | ||
case Right(v) => Some(v) | ||
case _ => None | ||
}) | ||
override def describe: String = s"Refined[${T.describe}, ${P.describe}]" | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
.../shapeless/shared/src/test/scala/eu/timepit/refined/shapeless/typeable/TypeableSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package eu.timepit.refined.shapeless.typeable | ||
|
||
import eu.timepit.refined.W | ||
import eu.timepit.refined.api.{Refined, RefinedTypeOps} | ||
import eu.timepit.refined.string.MatchesRegex | ||
import eu.timepit.refined.types.numeric.PosInt | ||
import org.scalacheck.Prop._ | ||
import org.scalacheck.Properties | ||
import shapeless.Typeable | ||
|
||
class TypeableSpec extends Properties("shapeless") { | ||
|
||
property("Typeable cast success") = secure { | ||
val value: PosInt = PosInt.unsafeFrom(5) | ||
typeableCast[PosInt](5) ?= Some(value) | ||
} | ||
|
||
property("Typeable cast fail") = secure { | ||
typeableCast[PosInt](0) ?= None | ||
} | ||
|
||
property("Typeable describe") = secure { | ||
typeableDescribe[PosInt] ?= "Refined[Int, Greater[_0]]" | ||
} | ||
|
||
property("Typeable cast success string regex") = secure { | ||
type Word = String Refined MatchesRegex[W.`"[a-zA-Z]*"`.T] | ||
object Word extends RefinedTypeOps[Word, String] | ||
val value: Word = Word.unsafeFrom("AlloweD") | ||
typeableCast[Word]("AlloweD") ?= Some(value) | ||
} | ||
|
||
property("Typeable cast fail string regex") = secure { | ||
type Word = String Refined MatchesRegex[W.`"[a-zA-Z]*"`.T] | ||
typeableCast[Word]("Not Allowed") ?= None | ||
} | ||
|
||
property("Typeable string regex describe") = secure { | ||
type Word = String Refined MatchesRegex[W.`"[a-zA-Z]*"`.T] | ||
typeableDescribe[Word] ?= """Refined[String, MatchesRegex[String([a-zA-Z]*)]]""" | ||
} | ||
|
||
private def typeableDescribe[T](implicit T: Typeable[T]): String = T.describe | ||
|
||
private def typeableCast[T](value: Any)(implicit T: Typeable[T]): Option[T] = T.cast(value) | ||
|
||
} |