Skip to content

Commit

Permalink
New reactify integration module for FRP + persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
darkfrog26 committed Aug 16, 2023
1 parent 4498f8d commit a546683
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ jobs:

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p util/target target .js/target core/native/target documentation/target core/js/target core/jvm/target .jvm/target .native/target io/js/target io/jvm/target bench/target project/target
run: mkdir -p util/target target reactify/jvm/target .js/target core/native/target documentation/target reactify/native/target reactify/js/target core/js/target core/jvm/target .jvm/target .native/target io/js/target io/jvm/target bench/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar util/target target .js/target core/native/target documentation/target core/js/target core/jvm/target .jvm/target .native/target io/js/target io/jvm/target bench/target project/target
run: tar cf targets.tar util/target target reactify/jvm/target .js/target core/native/target documentation/target reactify/native/target reactify/js/target core/js/target core/jvm/target .jvm/target .native/target io/js/target io/jvm/target bench/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down
26 changes: 25 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ ThisBuild / developers := List(tlGitHubDev("darkfrog26", "Matt Hicks"))
// Dependency versions
val collectionCompatVersion: String = "2.11.0"

val reactifyVersion: String = "4.1.0"

val scalaTestVersion: String = "3.2.16"

val scalaCheckVersion: String = "3.2.14.0"
Expand All @@ -52,7 +54,16 @@ val jsoniterJavaVersion: String = "0.9.23"
val circeVersion: String = "0.14.2"
val uPickleVersion: String = "2.0.0"

lazy val root = tlCrossRootProject.aggregate(core.js, core.jvm, core.native, io.js, io.jvm)
lazy val root = tlCrossRootProject.aggregate(
core.js,
core.jvm,
core.native,
io.js,
io.jvm,
reactify.js,
reactify.jvm,
reactify.native
)

lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Full)
Expand Down Expand Up @@ -104,6 +115,19 @@ lazy val io = crossProject(JSPlatform, JVMPlatform)
)
.dependsOn(core)

lazy val reactify = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Full)
.settings(
name := "fabric-reactify",
mimaPreviousArtifacts := Set.empty,
libraryDependencies ++= Seq(
"com.outr" %%% "reactify" % reactifyVersion,
"org.scalatest" %%% "scalatest" % scalaTestVersion % Test,
"org.scalatestplus" %% "scalacheck-1-16" % scalaCheckVersion % Test
)
)
.dependsOn(core)

lazy val bench = project
.in(file("bench"))
.enablePlugins(JmhPlugin)
Expand Down
61 changes: 61 additions & 0 deletions reactify/shared/src/main/scala/fabric/react/ReactParent.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2021 Typelevel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package fabric.react

import fabric.{obj, Json}
import fabric.rw._
import reactify._

trait ReactParent {
private val _json: Var[Json] = Var(load().getOrElse(obj()))
private val list: Var[List[RWVar[_]]] = Var(Nil)

def json: Val[Json] = _json

protected def modify(f: Json => Json): Unit = synchronized {
val modified = f(json())
_json @= modified
}

protected def reactive[T: RW](name: String, default: => T): Var[T] = synchronized {
val rwv = RWVar[T](name, () => default)
list @= rwv :: list()
rwv.v
}

protected def load(): Option[Json]

case class RWVar[T](name: String, default: () => T)(implicit rw: RW[T]) {
val v: Var[T] = Var(load())

v.attachAndFire { value =>
modify { json =>
json.merge(obj(name -> value.asJson))
}
}

protected def load(): T = json().get(name) match {
case Some(j) => j.as[T]
case None => default()
}
}
}
65 changes: 65 additions & 0 deletions reactify/shared/src/test/scala/spec/ReactParentSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2021 Typelevel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package spec

import fabric._
import fabric.react.ReactParent
import reactify._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec

class ReactParentSpec extends AnyWordSpec with Matchers {
"ReactParent" should {
"properly handle initialization of Person" in {
Person.name() should be("John Doe")
Person.age() should be(21)
Person.json() should be(
obj(
"name" -> "John Doe",
"age" -> 21
)
)
}
"change the name and age" in {
Person.name @= "Jane Doe"
Person.age @= 20
Person.json() should be(
obj(
"name" -> "Jane Doe",
"age" -> 20
)
)
}
}
}

object Person extends ReactParent {
val name: Var[String] = reactive[String]("name", "")
val age: Var[Int] = reactive[Int]("age", 0)

override protected def load(): Option[Json] = Some(
obj(
"name" -> "John Doe",
"age" -> 21
)
)
}

0 comments on commit a546683

Please sign in to comment.