Created
October 22, 2018 21:03
-
-
Save robhinds/73c6200b4deffffb4e3bdd2fa2c725f1 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import org.scalatest.{FunSpec, Matchers} | |
import shapeless._ | |
sealed trait Parent { | |
def description: Option[String] | |
def another: Option[String] | |
} | |
case class B(description: Option[String], another: Option[String]) extends Parent | |
case class A(description: Option[String], another: Option[String]) extends Parent | |
sealed trait Updater[T] { | |
def update(target: T, newVal: Option[String]): T | |
} | |
trait GenericUpdater { | |
val p: Path[_] | |
def update[T](target: T, newVal: Option[String])(implicit u: Updater[T]): T = u.update(target, newVal) | |
lazy implicit val cnilUpdater: Updater[CNil] = new Updater[CNil] { | |
override def update(target: CNil, newVal: Option[String]): CNil = target | |
} | |
implicit def genericCoproductUpdater[Head, Tail <: Coproduct]( | |
implicit tailUpdater: Updater[Tail], | |
mkLens: p.Lens[Head, Option[String]]) = new Updater[Head :+: Tail] { | |
override def update(target: Head :+: Tail, newVal: Option[String]) = { | |
target match { | |
case Inl(head) => Inl(mkLens().set(head)(newVal)) | |
case Inr(tail) => Inr(tailUpdater.update(tail, newVal)) | |
} | |
} | |
} | |
implicit def sealedTraitToGenericUpdater[A, Repr <: Coproduct]( | |
implicit generic: Generic.Aux[A, Repr], | |
genericUpdater: Updater[Repr]): Updater[A] = | |
new Updater[A] { | |
override def update(target: A, newVal: Option[String]): A = generic.from( | |
genericUpdater.update(generic.to(target), newVal) | |
) | |
} | |
implicit def caseClassToGenericUpdater[A, Repr <: HList]( | |
implicit generic: Generic.Aux[A, Repr], | |
mkLens: p.Lens[A, Option[String]] | |
): Updater[A] = | |
new Updater[A] { | |
override def update(target: A, newVal: Option[String]): A = mkLens().set(target)(newVal) | |
} | |
} | |
object DescriptionUpdater extends GenericUpdater { | |
override val p = ^.description | |
} | |
object AnotherUpdater extends GenericUpdater { | |
override val p = ^.another | |
} | |
class LensTest extends FunSpec with Matchers { | |
describe("ordering problems with lenses") { | |
it("trying to update the first child class alphabetically") { | |
import DescriptionUpdater._ | |
val parent: Parent = A(Some("not updated"), Some("another")) | |
val result= update(parent, Some("updated")) | |
println(result) | |
result.description shouldBe Some("updated") | |
} | |
it("trying to update the second child class alphabetically") { | |
import DescriptionUpdater._ | |
val parent: Parent = B(Some("not updated"), Some("another")) | |
val result= update(parent, Some("updated")) | |
println(result) | |
result.description shouldBe Some("updated") | |
} | |
it("trying to update a specific case class") { | |
import DescriptionUpdater._ | |
val b: B = B(Some("not updated"), Some("another")) | |
val result= update(b, Some("updated")) | |
println(result) | |
result.description shouldBe Some("updated") | |
} | |
it("trying to update different path") { | |
import AnotherUpdater._ | |
val b: Parent = B(Some("not updated"), Some("another")) | |
val result= update(b, Some("updated another")) | |
println(result) | |
result.another shouldBe Some("updated another") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment