Skip to content
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

add Var.prism/subType methods without seed and rename *Optic methods #360

Merged
merged 2 commits into from
Nov 17, 2023
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
28 changes: 22 additions & 6 deletions reactive/src/main/scala/colibri/reactive/Reactive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,34 @@ trait Var[A] extends VarState[A] with Rx[A] {
final def lens[B](read: A => B)(write: (A, B) => A)(implicit owner: NowOwner): Var[B] =
transformVar(_.contramap(write(now(), _)))(_.map(read))

final def prism[A2](f: A2 => A)(g: A => Option[A2])(seed: => A2): Var[A2] =
final def prismSeed[A2](f: A2 => A)(g: A => Option[A2])(seed: => A2): Var[A2] =
transformVar(_.contramap(f))(rx => Rx.observableSync(rx.observable.mapFilter(g).prependEval(seed)))

final def subType[A2 <: A: ClassTag](seed: => A2): Var[A2] = prism[A2]((x: A2) => x) {
final def prism[A2](f: A2 => A)(g: A => Option[A2]): Rx[Option[Var[A2]]] =
this.scan(Option.empty[Var[A2]]) { (prevVar, value) =>
(prevVar, g(value)) match {
case (variable@Some(_), Some(_)) => variable
case (None, Some(result)) => Some(prismSeed(f)(g)(result))
case (_, None) => None
}
}

final def subTypeSeed[A2 <: A: ClassTag](seed: => A2): Var[A2] = prismSeed[A2]((x: A2) => x) {
case a: A2 => Some(a)
case _ => None
}(seed)

final def imapO[B](optic: Iso[A, B]): Var[B] = imap(optic.reverseGet(_))(optic.get(_))
final def lensO[B](optic: Lens[A, B]): Var[B] = lens(optic.get(_))((base, zoomed) => optic.replace(zoomed)(base))
final def prismO[B](optic: Prism[A, B])(seed: => B): Var[B] =
prism(optic.reverseGet(_))(optic.getOption(_))(seed)
final def subType[A2 <: A: ClassTag]: Rx[Option[Var[A2]]] = prism[A2]((x: A2) => x) {
case a: A2 => Some(a)
case _ => None
}

final def imapOptic[B](optic: Iso[A, B]): Var[B] = imap(optic.reverseGet(_))(optic.get(_))
final def lensOptic[B](optic: Lens[A, B]): Var[B] = lens(optic.get(_))((base, zoomed) => optic.replace(zoomed)(base))
final def prismSeedOptic[B](optic: Prism[A, B])(seed: => B): Var[B] =
prismSeed(optic.reverseGet(_))(optic.getOption(_))(seed)
final def prismOptic[B](optic: Prism[A, B]): Rx[Option[Var[B]]] =
prism(optic.reverseGet(_))(optic.getOption(_))
}

object Var {
Expand Down
30 changes: 26 additions & 4 deletions reactive/src/test/scala/colibri/ReactiveSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ class ReactiveSpec extends AsyncFlatSpec with Matchers {
case class Employee(name: String, company: Company)

val employee = Var(Employee("jules", Company("wules", 7)))
val zipcode = employee.lensO(GenLens[Employee](_.company.zipcode))
val zipcode = employee.lensOptic(GenLens[Employee](_.company.zipcode))

zipcode.unsafeSubscribe()

Expand All @@ -882,42 +882,64 @@ class ReactiveSpec extends AsyncFlatSpec with Matchers {
val eventVar: Var[Event] = Var[Event](EventA(0))
val eventNotVar: Var[Event] = Var[Event](EventB(""))

val eventAVar = eventVar.prismO(GenPrism[Event, EventA])(null)
val eventAVar2 = eventVar.subType[EventA](null)
val eventNotAVar = eventNotVar.prismO(GenPrism[Event, EventA])(null)
val eventAVar = eventVar.prismSeedOptic(GenPrism[Event, EventA])(null)
val eventAVar2 = eventVar.subTypeSeed[EventA](null)
val eventNotAVar = eventNotVar.prismSeedOptic(GenPrism[Event, EventA])(null)
val eventAVarRx = eventVar.prismOptic(GenPrism[Event, EventA])
val eventAVarRx2 = eventVar.subType[EventA]

eventAVar.unsafeSubscribe()
eventAVar2.unsafeSubscribe()
eventNotAVar.unsafeSubscribe()
eventAVarRx.unsafeSubscribe()
eventAVarRx2.unsafeSubscribe()

eventVar.nowIfSubscribed() shouldBe EventA(0)
eventAVar.nowIfSubscribed() shouldBe EventA(0)
eventAVar2.nowIfSubscribed() shouldBe EventA(0)
eventNotAVar.nowIfSubscribed() shouldBe null
eventAVarRx.nowIfSubscribed().get.now() shouldBe EventA(0)
eventAVarRx2.nowIfSubscribed().get.now() shouldBe EventA(0)

val prevEventAVarRx = eventAVarRx.nowIfSubscribed().get
val prevEventAVarRx2 = eventAVarRx2.nowIfSubscribed().get
eventAVar.set(EventA(1))

eventVar.nowIfSubscribed() shouldBe EventA(1)
eventAVar.nowIfSubscribed() shouldBe EventA(1)
eventAVar2.nowIfSubscribed() shouldBe EventA(1)
eventNotAVar.nowIfSubscribed() shouldBe null
eventAVarRx.nowIfSubscribed().get.now() shouldBe EventA(1)
eventAVarRx.nowIfSubscribed().get shouldBe prevEventAVarRx
eventAVarRx2.nowIfSubscribed().get.now() shouldBe EventA(1)
eventAVarRx2.nowIfSubscribed().get shouldBe prevEventAVarRx2

eventVar.set(EventB("he"))

eventVar.nowIfSubscribed() shouldBe EventB("he")
eventAVar.nowIfSubscribed() shouldBe EventA(1)
eventAVar2.nowIfSubscribed() shouldBe EventA(1)
eventNotAVar.nowIfSubscribed() shouldBe null
eventAVarRx.nowIfSubscribed() shouldBe None
eventAVarRx2.nowIfSubscribed() shouldBe None

eventAVar.set(EventA(2))

eventVar.nowIfSubscribed() shouldBe EventA(2)
eventAVar.nowIfSubscribed() shouldBe EventA(2)
eventAVar2.nowIfSubscribed() shouldBe EventA(2)
eventNotAVar.nowIfSubscribed() shouldBe null
eventAVarRx.nowIfSubscribed().get.now() shouldBe EventA(2)
eventAVarRx2.nowIfSubscribed().get.now() shouldBe EventA(2)

eventVar.set(EventA(3))

eventVar.nowIfSubscribed() shouldBe EventA(3)
eventAVar.nowIfSubscribed() shouldBe EventA(3)
eventAVar2.nowIfSubscribed() shouldBe EventA(3)
eventNotAVar.nowIfSubscribed() shouldBe null
eventAVarRx.nowIfSubscribed().get.now() shouldBe EventA(3)
eventAVarRx2.nowIfSubscribed().get.now() shouldBe EventA(3)
}

it should "map and now()" in {
Expand Down