Skip to content

Commit b1fe6df

Browse files
authored
Merge pull request #5 from yahoo/sal/v070branch
0.7.0 Improvements
2 parents d5a3f13 + 89a4714 commit b1fe6df

File tree

73 files changed

+1536
-601
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1536
-601
lines changed

README.md

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ We originally developed it for ourselves to use in a video playing library at Ya
1717

1818
It's also possible you're the type of person who likes nerdy new software ideas. (Seriously though, who doesn't, amirite?) If that's the case, we guarantee you will find Behavior Graph interesting.
1919

20+
## Can I see an example?
21+
22+
Behavior Graph introduces a handful of new concepts.
23+
These concepts aren't difficult, but you will require some orientation.
24+
25+
* We've created a [short walk-through of a Login form](https://yahoo.github.io/bgdocs/docs/jvm/code-example/) using Behavior Graph.
26+
* You can also take a look at [one of our tutorials](https://yahoo.github.io/bgdocs/docs/jvm/tutorial-1/).
27+
28+
2029
## How does it Work?
2130

22-
As programmers it's natural to partition our software into subtasks. For example, let's consider what happens on a typical login form.
31+
As programmers, it's natural to partition our software into subtasks. For example, let's consider what happens on a typical login form.
2332

2433
1. When a user clicks on the Login button, we want to validate the Email and Password fields.
2534
2. If validation passes, then we want to make a network call to log the user in.
26-
3. Additionally we want to update the UI to provide feedback in case the validation fails, or disable the login button while we are actively logging in.
35+
3. Additionally, we want to update the UI to provide feedback in case the validation fails, or disable the login button while we are actively logging in.
2736

2837
Most programming languages offer __functions__ as the primary tool for creating these subtasks. Conceptually we have three subtasks. So we will create three corresponding functions: `validateFields`, `networkLogin`, and `updateUI`. We will also need an additional `onLoginClick` function to run these tasks. It will look like this:
2938

@@ -65,16 +74,6 @@ This gives us:
6574

6675
Behavior Graph isn't a replacement for functions. (We wrote it with functions, hello!) Instead it gives us higher level abstractions for partitioning our code into subtasks. It lets us say "these two blocks of code are related and here's how". And with that information the computer is able to run things for us. And humans are better able to infer the intent of the code.
6776

68-
## Can I see an example?
69-
70-
__We are updating our Kotlin documentation. Below are links to our Javascript/Typescript port which has a very similar API__
71-
72-
Behavior Graph introduces a handful of new concepts.
73-
These concepts aren't difficult, but you will require some orientation.
74-
75-
* We've created a [short walk-through of a Login form](https://yahoo.github.io/bgdocs/docs/typescript/code-example/) using Behavior Graph.
76-
* You can also take a look at [one of our tutorials](https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-1/).
77-
7877
## Small
7978

8079
Behavior Graph is a small library. It's around 1500 lines of formatted code. It has no dependencies.
@@ -98,21 +97,21 @@ Behavior Graph has been ported to multiple platforms.
9897

9998
## Should I Use it in my Project?
10099

101-
This Kotlin version is not used in production at Yahoo currently. It is a direct port from the original Objective-C. It has excellent test coverage. We are confident it works as intended.
100+
This Kotlin is minimally used at Yahoo currently. It is a direct port from the original Objective-C. It has excellent test coverage. We are confident it works as intended.
102101

103102
But it is also newly open sourced. You won't find blog posts and Stack Overflow answers to your questions. If you are on a team that expects that type of support you should proceed with caution.
104103

105104
## Obtaining Behavior Graph
106105

107-
Currently available only in source form on Github.
106+
Behavior Graph is available in source form on [Github](https://github.com/yahoo/bgkotlin).
108107

109-
## Documentation
108+
It is also available on Maven Central @ [com.yahoo.behaviorgraph/bgjvm](https://search.maven.org/artifact/com.yahoo.behaviorgraph/bgjvm).
110109

111-
__We are updating our Kotlin documentation. Below are links to our Javascript/Typescript port which has a very similar API__
110+
## Documentation
112111

113-
[Go here for the full documentation site](https://yahoo.github.io/bgdocs/docs/typescript/).
112+
[Go here for the full documentation site](https://yahoo.github.io/bgdocs/docs/).
114113

115-
While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking. We recommend you start with the [Getting Started guide](https://yahoo.github.io/bgdocs/docs/typescript/quickstart/) then work through the [Tutorials](https://yahoo.github.io/bgdocs/docs/typescript/tutorials/tutorial-1/).
114+
While there are only a handful of basic concepts in Behavior Graph, it does require a shift in thinking. We recommend you start with the [Getting Started guide](https://yahoo.github.io/bgdocs/docs/jvm/quickstart/) then work through the [Tutorials](https://yahoo.github.io/bgdocs/docs/jvm/tutorial-1/).
116115

117116
## Contact Us
118117

behavior-graph/build.gradle

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ java {
1515
withSourcesJar()
1616
}
1717

18+
tasks.named('jar') {
19+
manifest {
20+
attributes('Automatic-Module-Name': 'behaviorgraph')
21+
}
22+
}
23+
1824
def dokkaJavadocJar = tasks.register("dokkaJavadocJar", org.gradle.jvm.tasks.Jar) {
1925
it.dependsOn(dokkaJavadoc)
2026
it.from(dokkaJavadoc.outputDirectory)
@@ -23,13 +29,29 @@ def dokkaJavadocJar = tasks.register("dokkaJavadocJar", org.gradle.jvm.tasks.Jar
2329
}
2430

2531
publishing {
32+
repositories {
33+
maven {
34+
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
35+
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
36+
url = releasesRepoUrl //version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
37+
credentials {
38+
if (project.hasProperty("ossrhUsername")) {
39+
username = ossrhUsername
40+
password = ossrhPassword
41+
}
42+
}
43+
}
44+
}
2645
publications {
2746
release(MavenPublication) {
2847
from components.java
29-
groupId = 'com.yahoo.behavior-graph'
30-
artifactId = 'bgkotlin'
31-
version = '0.5.0-RC1'
48+
groupId = 'com.yahoo.behaviorgraph'
49+
artifactId = 'bgjvm'
50+
version = '0.7.0'
3251
artifact dokkaJavadocJar
52+
repositories {
53+
54+
}
3355
pom {
3456
name = 'Behavior Graph'
3557
description = 'Behavior Graph lets you build your programs out of small, easily understood pieces in a way that lets the computer do more of the work for you.'
@@ -57,12 +79,14 @@ publishing {
5779
}
5880
}
5981

82+
6083
signing {
61-
sign configurations.archives
62-
sign publishing.publications.release
84+
if (project.hasProperty("signing.keyId")) {
85+
sign configurations.archives
86+
sign publishing.publications.release
87+
}
6388
}
6489

65-
6690
dependencies {
6791
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
6892
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"

behavior-graph/src/main/kotlin/com/yahoo/behaviorgraph/Action.kt renamed to behavior-graph/src/main/kotlin/behaviorgraph/Action.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// Copyright Yahoo 2021
33
//
4-
package com.yahoo.behaviorgraph
4+
package behaviorgraph
55

66
/**
77
* An __Action__ is a block of code which initiates a Behavior Graph [Event].
@@ -18,14 +18,15 @@ internal interface RunnableAction: Action {
1818
fun runAction()
1919
}
2020

21-
internal class GraphAction(val block: () -> Unit, override val debugName: String? = null): RunnableAction {
21+
internal class GraphAction(val thunk: Thunk, override val debugName: String? = null): RunnableAction {
2222
override fun runAction() {
23-
block()
23+
thunk.invoke()
2424
}
2525
}
2626

27-
internal class ExtentAction(val block: (extent: Extent) -> Unit, val extent: Extent, override val debugName: String? = null): RunnableAction {
27+
internal class ExtentAction<T>(val thunk: ExtentThunk<T>, val context: T, override val debugName: String? = null):
28+
RunnableAction {
2829
override fun runAction() {
29-
block(extent)
30+
thunk.invoke(context)
3031
}
31-
}
32+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//
2+
// Copyright Yahoo 2021
3+
//
4+
package behaviorgraph
5+
6+
class AllDemandsMustBeAddedToTheGraphExceptions(s: String, val currentBehavior: Behavior<*>, val untrackedDemand: Resource) : BehaviorGraphException("$s Behavior=$currentBehavior untrackedDemand=$untrackedDemand")

behavior-graph/src/main/kotlin/com/yahoo/behaviorgraph/Behavior.kt renamed to behavior-graph/src/main/kotlin/behaviorgraph/Behavior.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
//
22
// Copyright Yahoo 2021
33
//
4-
package com.yahoo.behaviorgraph
4+
package behaviorgraph
55

66
/**
77
* A behavior is a block of code together with its dependency relationships (links). They are one of the two node types in a behavior graph. You define behaviors using the behavior() factory method of an Extent.
88
*
99
* Behaviors have both static and dynamic links. You provide static links when you create the behavior. Behavior Graph will update dynamic links per special methods on BehaviorBuilder or you can update them directly on a behavior.
1010
* @property extent A behavior always has an [Extent] with which it is created.
1111
*/
12-
class Behavior(
13-
val extent: Extent, demands: List<Demandable>?, supplies: List<Resource>?,
14-
internal var block: (Extent) -> Unit
15-
) : Comparable<Behavior> {
12+
class Behavior<T: Any>(
13+
val extent: Extent<T>, demands: List<Demandable>?, supplies: List<Resource>?,
14+
internal var thunk: ExtentThunk<T>
15+
) : Comparable<Behavior<*>> {
1616
/**
1717
* The current set of all Resources which the behavior demands.
1818
*/
@@ -42,7 +42,7 @@ class Behavior(
4242
this.untrackedSupplies = supplies
4343
}
4444

45-
override fun compareTo(other: Behavior): Int {
45+
override fun compareTo(other: Behavior<*>): Int {
4646
return order.compareTo(other.order)
4747
}
4848

behavior-graph/src/main/kotlin/com/yahoo/behaviorgraph/BehaviorBuilder.kt renamed to behavior-graph/src/main/kotlin/behaviorgraph/BehaviorBuilder.kt

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
package com.yahoo.behaviorgraph
1+
package behaviorgraph
2+
3+
fun interface DemandableLinks<T> {
4+
fun invoke(ctx: T, demands: MutableList<Demandable?>)
5+
}
6+
7+
fun interface SuppliableLinks<T> {
8+
fun invoke(ctx: T, supplies: MutableList<Resource?>)
9+
}
210

311
/**
412
* Provides a fluent API interface for creating a [Behavior].
@@ -14,16 +22,16 @@ package com.yahoo.behaviorgraph
1422
* }
1523
* ```
1624
*/
17-
class BehaviorBuilder<T: Extent>(
18-
internal val extent: T
25+
class BehaviorBuilder<T: Any>(
26+
internal val extent: Extent<T>
1927
) {
2028
private var untrackedDemands: MutableList<Demandable> = mutableListOf()
2129
private var untrackedSupplies: MutableList<Resource> = mutableListOf()
22-
private var dynamicDemandSwitches: Array<out Demandable>? = null
23-
private var dynamicDemandLinks: ((ext: T) -> List<Demandable?>?)? = null
30+
private var dynamicDemandSwitches: List<Demandable>? = null
31+
private var dynamicDemandLinks: DemandableLinks<T>? = null
2432
private var dynamicDemandRelinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior
25-
private var dynamicSupplySwitches: Array<out Demandable>? = null
26-
private var dynamicSupplyLinks: ((ext: T) -> List<Resource?>?)? = null
33+
private var dynamicSupplySwitches: List<Demandable>? = null
34+
private var dynamicSupplyLinks: SuppliableLinks<T>? = null
2735
private var dynamicSupplyRelinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior
2836

2937
/**
@@ -44,38 +52,75 @@ class BehaviorBuilder<T: Extent>(
4452
* Example:
4553
* ```kotlin
4654
* extentInstance.behavior()
47-
* .dynamicDemands(resource1, relinkingOrder = RelinkingOrder.RelinkingOrderSubsequent) { listOf(resource2, resource3) }
55+
* .dynamicDemands(resource1, relinkingOrder = RelinkingOrder.RelinkingOrderSubsequent) { ctx, demands ->
56+
* demands.add(resource2)
57+
* demands.add(resource3)
58+
* }
4859
* .runs { ...
4960
* ```
5061
* @param switches When these resources change, the `links` code block will run to determine which additional demands a behavior should depend on.
5162
* @param relinkingOrder Should the dynamic demands be set before or after the behavior is run. If in doubt choose `RelinkingOrderPrior`
52-
* @param links This anonymous function should return the additional set of demands the behavior will include. The `ext` parameter points to the [Extent] this behaivor is created on.
63+
* @param links This anonymous function passes in an empty list of dynamic demands. You should add any additional demands the behavior will include. The `ctx` parameter points to the context object for the [Extent] this behaivor is created on.
5364
*/
54-
fun dynamicDemands(vararg switches: Demandable, relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior, links: ((ext: T) -> List<Demandable?>?)) = apply {
65+
@JvmOverloads
66+
fun dynamicDemands(
67+
switches: List<Demandable>,
68+
relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior,
69+
links: DemandableLinks<T>
70+
) = apply {
5571
dynamicDemandSwitches = switches
5672
dynamicDemandLinks = links
5773
dynamicDemandRelinkingOrder = relinkingOrder
5874
}
5975

76+
@JvmOverloads
77+
fun dynamicDemands(
78+
vararg switches: Demandable,
79+
relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior,
80+
links: DemandableLinks<T>
81+
) = apply {
82+
dynamicDemandSwitches = switches.asList()
83+
dynamicDemandLinks = links
84+
dynamicDemandRelinkingOrder = relinkingOrder
85+
}
86+
6087
/**
6188
* Optional clause to include a set of supplies which can change based on other resources changing
6289
*
6390
* Example:
6491
* ```kotlin
6592
* extentInstance.behavior()
66-
* .dynamicSupplies(resource1, relinkingOrder = RelinkingOrder.RelinkingOrderSubsequent) { listOf(resource2, resource3) }
93+
* .dynamicSupplies(resource1, relinkingOrder = RelinkingOrder.RelinkingOrderSubsequent) { ctx, supplies ->
94+
* supplies.add(resource2)
95+
* supplies.add(resource3)
96+
* }
6797
* .runs { ...
6898
* ```
6999
*
70100
* @param switches When these resources change, the `links` code block will run to determine which additional supplies a behavior should be responsible for.
71101
* @param relinkingOrder Should the dynamic supplies be set before or after the behavior is run. If in doubt choose `RelinkingOrderPrior` (which is the default).
72-
* @param links This anonymous function should return the additional set of supplies the behavior will include. The `ext` parameter points to the [Extent] this behaivor is created on.
102+
* @param links This anonymous function passes in an empty list of dynamic supplies. You should add any additional supplies the behavior will include. The `ctx` parameter points to the context object for the [Extent] this behaivor is created on.
73103
*/
74-
fun dynamicSupplies(vararg switches: Demandable, relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior, links: ((ext: T) -> List<Resource?>?)) = apply {
104+
@JvmOverloads
105+
fun dynamicSupplies(
106+
switches: List<Demandable>,
107+
relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior,
108+
links: SuppliableLinks<T>
109+
) = apply {
75110
dynamicSupplySwitches = switches
76111
dynamicSupplyLinks = links
77112
dynamicSupplyRelinkingOrder = relinkingOrder
78113
}
114+
@JvmOverloads
115+
fun dynamicSupplies(
116+
vararg switches: Demandable,
117+
relinkingOrder: RelinkingOrder = RelinkingOrder.RelinkingOrderPrior,
118+
links: SuppliableLinks<T>
119+
) = apply {
120+
dynamicSupplySwitches = switches.asList()
121+
dynamicSupplyLinks = links
122+
dynamicSupplyRelinkingOrder = relinkingOrder
123+
}
79124

80125
/**
81126
* Required clause which sets the block of code the behavior will run when one or more of its demands are updated.
@@ -84,7 +129,7 @@ class BehaviorBuilder<T: Extent>(
84129
* @return The behavior that was created. Typically the results are discarded unless you need direct access to the
85130
* behavior later.
86131
*/
87-
fun runs(block: (ext: T) -> Unit): Behavior {
132+
fun runs(thunk: ExtentThunk<T>): Behavior<T> {
88133
var dynamicDemandResource: Resource? = null
89134
if (dynamicDemandSwitches != null) {
90135
dynamicDemandResource = extent.resource("(BG Dynamic Demand Resource)")
@@ -105,7 +150,7 @@ class BehaviorBuilder<T: Extent>(
105150
}
106151
}
107152

108-
val mainBehavior = Behavior(extent, untrackedDemands, untrackedSupplies, block as (Extent) -> Unit)
153+
val mainBehavior = Behavior(extent, untrackedDemands, untrackedSupplies, thunk)
109154

110155
if (dynamicDemandSwitches != null) {
111156
var supplies: List<Resource>? = null
@@ -117,8 +162,9 @@ class BehaviorBuilder<T: Extent>(
117162
demands.add(dynamicDemandResource!!)
118163
}
119164
Behavior(extent, demands, supplies) {
120-
val demandLinks = dynamicDemandLinks!!(it as T)
121-
mainBehavior.setDynamicDemands(demandLinks)
165+
val mutableListOfDemands = mutableListOf<Demandable?>()
166+
dynamicDemandLinks!!.invoke(it, mutableListOfDemands)
167+
mainBehavior.setDynamicDemands(mutableListOfDemands)
122168
}
123169
}
124170

@@ -132,8 +178,9 @@ class BehaviorBuilder<T: Extent>(
132178
demands.add(dynamicSupplyResource!!)
133179
}
134180
Behavior(extent, demands, supplies) {
135-
var supplyLinks = dynamicSupplyLinks!!(it as T)
136-
mainBehavior.setDynamicSupplies(supplyLinks)
181+
val mutableListOfSupplies = mutableListOf<Resource?>()
182+
dynamicSupplyLinks!!.invoke(it, mutableListOfSupplies)
183+
mainBehavior.setDynamicSupplies(mutableListOfSupplies)
137184
}
138185
}
139186

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//
2+
// Copyright Yahoo 2021
3+
//
4+
package behaviorgraph
5+
6+
class BehaviorDependencyCycleDetectedException(s: String, val behavior: Behavior<*>, val cycle: List<Resource>) : BehaviorGraphException("$s Behavior=$behavior")
7+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// Copyright Yahoo 2021
33
//
4-
package com.yahoo.behaviorgraph.exception
4+
package behaviorgraph
55

66
open class BehaviorGraphException : RuntimeException {
77
constructor(message: String, ex: Exception?): super(message, ex)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package behaviorgraph
2+
3+
class ChildLifetimeCannotBeParent(val child: Extent<*>): BehaviorGraphException("Child lifetime cannot be a transitive parent.")

behavior-graph/src/main/kotlin/com/yahoo/behaviorgraph/DateProvider.kt renamed to behavior-graph/src/main/kotlin/behaviorgraph/DateProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.yahoo.behaviorgraph
1+
package behaviorgraph
22

33
/**
44
* A Graph [Event] saves the current time when it runs.

0 commit comments

Comments
 (0)