Skip to content

Commit

Permalink
Merge pull request #8 from yahoo/sal/debugstrings
Browse files Browse the repository at this point in the history
Usability fixes and fix reflection on Android
  • Loading branch information
slevin authored Sep 18, 2024
2 parents b1fe6df + 3ffd257 commit fc0e6a3
Show file tree
Hide file tree
Showing 13 changed files with 128 additions and 10 deletions.
2 changes: 1 addition & 1 deletion behavior-graph/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ publishing {
from components.java
groupId = 'com.yahoo.behaviorgraph'
artifactId = 'bgjvm'
version = '0.7.0'
version = '0.8.0'
artifact dokkaJavadocJar
repositories {

Expand Down
15 changes: 14 additions & 1 deletion behavior-graph/src/main/kotlin/behaviorgraph/Behavior.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,20 @@ class Behavior<T: Any>(
}

override fun toString(): String {
return "Behavior()"
var rows = mutableListOf<String>("Behavior")
supplies?.forEachIndexed { index, resource ->
if (index == 0) {
rows.add(" Supplies:")
}
rows.add(" " + resource.toString())
}
demands?.forEachIndexed { index, resource ->
if (index == 0) {
rows.add(" Demands:")
}
rows.add(" " + resource.toString())
}
return rows.joinToString("\n")
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ class BehaviorBuilder<T: Any>(
dynamicSupplyRelinkingOrder = relinkingOrder
}

/**
* Alternate form of `runs` for Kotlin because `.run()` is a builtin scope function
* and is easily confused with Behavior Graph's `.runs()`.
*/
fun performs(thunk: ExtentThunk<T>): Behavior<T> = runs(thunk)

/**
* Required clause which sets the block of code the behavior will run when one or more of its demands are updated.
* The `ext` parameter passed in when the behavior is run is the [Extent] instance this behavior was created on.
Expand Down
10 changes: 9 additions & 1 deletion behavior-graph/src/main/kotlin/behaviorgraph/EventLoopState.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
package behaviorgraph

internal data class EventLoopState(val action: RunnableAction, val actionUpdates: MutableList<Resource> = mutableListOf(), var currentSideEffect: SideEffect? = null, var phase: EventLoopPhase = EventLoopPhase.Queued)
internal data class EventLoopState(val action: RunnableAction, val actionUpdates: MutableList<Resource> = mutableListOf(), var currentSideEffect: SideEffect? = null, var phase: EventLoopPhase = EventLoopPhase.Queued) {
override fun toString(): String {
var rows = mutableListOf<String>("Action")
actionUpdates?.forEach { resource ->
rows.add(" " + resource.toString())
}
return rows.joinToString("\n")
}
}
20 changes: 15 additions & 5 deletions behavior-graph/src/main/kotlin/behaviorgraph/Extent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ open class Extent<ExtentContext: Any> @JvmOverloads constructor(val graph: Graph
val didAdd: State<Boolean> = State(this, false)

init {
didAdd.debugName = "_didAdd_"
didAddBehavior = behavior().supplies(didAdd).runs { this.didAdd.update(true) }
}

Expand Down Expand Up @@ -148,17 +149,21 @@ open class Extent<ExtentContext: Any> @JvmOverloads constructor(val graph: Graph
private fun nameResources() {
// context object or this extent if none
val focus: Any = context ?: this
focus.javaClass.declaredFields.forEach { field ->
// iterate through each field and see if its a resource subclass
if ((Resource::class.java as Class).isAssignableFrom(field.type)) {
// sometimes fields aren't accessible to reflection, try enabling that
if (field.trySetAccessible()) {
try {
focus.javaClass.declaredFields.forEach { field ->
// iterate through each field and see if its a resource subclass
if ((Resource::class.java as Class).isAssignableFrom(field.type)) {
// sometimes fields aren't accessible to reflection, try enabling that
field.isAccessible = true // throws error if not possible
val resource = field.get(focus) as Resource
if (resource.debugName == null) {
resource.debugName = field.name
}
}
}
} catch (ex: Exception) {
// throws error if we cannot make fields accessible for security reasons
// catching the error is fine here, it just means we won't get debug names
}
}

Expand Down Expand Up @@ -227,4 +232,9 @@ open class Extent<ExtentContext: Any> @JvmOverloads constructor(val graph: Graph
val action = ExtentAction(thunk, (context ?: this) as ExtentContext, debugName)
graph.actionHelper(action)
}

override fun toString(): String {
return graph.toString()
}

}
17 changes: 17 additions & 0 deletions behavior-graph/src/main/kotlin/behaviorgraph/Graph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -693,4 +693,21 @@ class Graph @JvmOverloads constructor(private val dateProvider: DateProvider? =
}
extent.addedToGraphWhen = null
}

override fun toString(): String {
return buildString {
if (currentEvent != null) {
append(String.format("Current Event: %d\n", currentEvent!!.sequence))
} else {
append("No current event")
}
if (eventLoopState != null) {
append(eventLoopState!!.toString())
append("\n")
}
if (currentBehavior != null) {
append(currentBehavior!!.toString())
}
}
}
}
4 changes: 4 additions & 0 deletions behavior-graph/src/main/kotlin/behaviorgraph/Moment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ class Moment @JvmOverloads constructor(extent: Extent<*>, debugName: String? = n
_happened = false
}

override fun toString(): String {
return String.format("%s (m) == %s (%s)", debugName ?: "resource", if (_happened) "Updated" else "Not Updated", event?.sequence)
}

}
4 changes: 4 additions & 0 deletions behavior-graph/src/main/kotlin/behaviorgraph/Resource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ open class Resource @JvmOverloads constructor(val extent: Extent<*>, var debugNa
throw BehaviorGraphException("Cannot access the value or event of a resource inside a behavior unless it is supplied or demanded.")
}
}

override fun toString(): String {
return String.format("%s (r)", debugName ?: "resource")
}
}
4 changes: 4 additions & 0 deletions behavior-graph/src/main/kotlin/behaviorgraph/State.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ class State<T> @JvmOverloads constructor(extent: Extent<*>, initialState: T, deb
priorStateDuringEvent = null
}

override fun toString(): String {
return String.format("%s (s) == %s (%s)", debugName ?: "resource", currentState.value, currentState.event.sequence)
}

private data class StateHistory<T>(val value: T, val event: Event)
}

Expand Down
15 changes: 15 additions & 0 deletions behavior-graph/src/main/kotlin/behaviorgraph/TypedMoment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ class TypedMoment<T> @JvmOverloads constructor(extent: Extent<*>, debugName: Str
return this._happenedValue!!
}

/**
* Optional version value() property which may be more convenient.
* Returns T if justUpdated is true, null otherwise
* Be careful: It is possible that T is also an optional type itself
* So this typedMoment could be called with .update(null).
* In that case justUpdated will be true but justUpdatedValue would be null.
*/
@get:JvmName("justUpdatedValue")
val justUpdatedValue: T?
get() = _happenedValue

/**
* If this Moment has ever been update what was the last Event it was updated.
* A behavior must demand this resource to access this property.
Expand Down Expand Up @@ -66,6 +77,10 @@ class TypedMoment<T> @JvmOverloads constructor(extent: Extent<*>, debugName: Str
_happened = false
}

override fun toString(): String {
return String.format("%s (tm) == %s (%s)", debugName ?: "resource", if (_happened) _happenedValue else "NA", event?.sequence)
}

/**
* Is there a current event and was this Moment resource updated during this event.
* A behavior must demand this resource to access this property.
Expand Down
37 changes: 37 additions & 0 deletions behavior-graph/src/test/kotlin/behaviorgraph/MomentTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,43 @@ class MomentTest : AbstractBehaviorGraphTest() {
assertTrue(didRun)
}

@Test
fun `updatedValue returns optional wrapped value`() {
// In some cases justUpdatedValue may be easier to work with
// than checking for justUpdated and getting the value
// however kotlin collapses the nulls, so there's no notion of
// unwrapping as you might find in
val mr1: TypedMoment<String> = ext.typedMoment()
val mr2: TypedMoment<String?> = ext.typedMoment()

g.action {
g.sideEffect {
// mr1 was not just updated, so justUpdatedValue is null
assertNull(mr1.justUpdatedValue)
var run = false
}
}

g.action {
mr1.update("hello")
mr2.update(null)

g.sideEffect {
// mr1 was updated and it's value was hello so justUpdatedValue is hello
assertEquals("hello", mr1.justUpdatedValue)
// mr2 was also just updated, but with a value of null
assertTrue(mr2.justUpdated)
// however justUpdatedValue is null, so ?.let pattern will not run
var run = false
mr2.justUpdatedValue?.let {
run = true
assertNull(it)
}
assertFalse(run)
}
}
}

//checks below
@Test
fun `check happen requires graph`() {
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {
}
dependencies {
// Build system
classpath 'com.android.tools.build:gradle:4.2.2'
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$kotlin_version"
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Mon Aug 23 11:41:29 PDT 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

0 comments on commit fc0e6a3

Please sign in to comment.