Skip to content

Commit

Permalink
add Var.prism/subType methods without seed and rename *Optic methods
Browse files Browse the repository at this point in the history
  • Loading branch information
cornerman committed Nov 17, 2023
1 parent fe2912e commit c5dfa9c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 10 deletions.
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

0 comments on commit c5dfa9c

Please sign in to comment.