From 88d1342da2671e9d6c9f02fbcd7886e18663b8b5 Mon Sep 17 00:00:00 2001 From: green-nick Date: Tue, 12 Nov 2019 16:35:03 +0200 Subject: [PATCH 1/5] - update Kotlin version; - add Jitpack CI badge to README; --- README.md | 2 ++ build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e41e32..1d5e10f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ [![](https://jitpack.io/v/green-nick/properties.svg)](https://jitpack.io/#green-nick/properties) +[![](https://jitci.com/gh/green-nick/properties/svg)](https://jitci.com/gh/green-nick/properties) + # Properties Small, lightweight library that allows to use observable properties. Written in pure Kotlin, without third-party dependencies, Kotlin oriented. diff --git a/build.gradle b/build.gradle index 07efa0e..9f95d02 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.3.21' + id 'org.jetbrains.kotlin.jvm' version '1.3.50' id('maven') } From a689d2dae31a58a2b440611ac4d767f76759f874 Mon Sep 17 00:00:00 2001 From: greennick Date: Tue, 26 Nov 2019 11:21:56 +0200 Subject: [PATCH 2/5] - add extensions for Properties holds Set; --- .../properties/generic/CollectionsExt.kt | 24 ++++++++++ .../generic/CollectionExtensionsTests.kt | 44 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/main/java/com/github/greennick/properties/generic/CollectionsExt.kt b/src/main/java/com/github/greennick/properties/generic/CollectionsExt.kt index ce55f27..a59b6c9 100644 --- a/src/main/java/com/github/greennick/properties/generic/CollectionsExt.kt +++ b/src/main/java/com/github/greennick/properties/generic/CollectionsExt.kt @@ -36,6 +36,30 @@ operator fun MutableProperty>.minusAssign(another: Iterable) { operator fun Property>.get(index: Int): T = value[index] +/** + * Set extensions + */ + +@JvmName("addToPropertyOfSet") +operator fun MutableProperty>.plusAssign(element: T) { + value = value + element +} + +@JvmName("addToPropertyOfSet") +operator fun MutableProperty>.plusAssign(another: Iterable) { + value = value + another +} + +@JvmName("removeFromPropertyOfSet") +operator fun MutableProperty>.minusAssign(element: T) { + value = value - element +} + +@JvmName("removeFromPropertyOfSet") +operator fun MutableProperty>.minusAssign(another: Iterable) { + value = value - another +} + /** * Map extensions */ diff --git a/src/test/java/com/github/greennick/properties/generic/CollectionExtensionsTests.kt b/src/test/java/com/github/greennick/properties/generic/CollectionExtensionsTests.kt index c09e0e2..16d5bdf 100644 --- a/src/test/java/com/github/greennick/properties/generic/CollectionExtensionsTests.kt +++ b/src/test/java/com/github/greennick/properties/generic/CollectionExtensionsTests.kt @@ -99,6 +99,50 @@ class CollectionExtensionsTests { assert(strings[0] == property[0]) } + @Test + fun `plusAssign adds new element to property of Set`() { + val strings = setOf("Hello", "Dratuti", "Aloha") + val property = propertyOf(strings) + val another = "Guten tag" + + property += another + + assert(another in property) + } + + @Test + fun `plusAssign adds new elements to property of Set`() { + val strings = setOf("Hello", "Dratuti", "Aloha") + val property = propertyOf(strings) + val another = listOf("Guten tag", "Privit") + + property += another + + assert(another in property) + } + + @Test + fun `minusAssign removes exist element from property of Set`() { + val strings = setOf("Hello", "Dratuti", "Aloha") + val property = propertyOf(strings) + val removed = strings.first() + + property -= removed + + assert(removed !in property) + } + + @Test + fun `minusAssign removes exist elements from property of Set`() { + val strings = setOf("Hello", "Dratuti", "Aloha") + val property = propertyOf(strings) + val removed = setOf("Hello", "Dratuti") + + property -= removed + + assert(removed !in property) + } + @Test fun `plusAssign adds new entry to map property`() { val entries = mapOf(0 to "Hello") From 5cb45517645ed74ac0152d784730485d48fcb96f Mon Sep 17 00:00:00 2001 From: greennick Date: Tue, 26 Nov 2019 11:28:33 +0200 Subject: [PATCH 3/5] - generic extension for init memoized property; --- .../com/github/greennick/properties/generic/PropertiesExt.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/github/greennick/properties/generic/PropertiesExt.kt b/src/main/java/com/github/greennick/properties/generic/PropertiesExt.kt index 3fc0df0..4be7418 100644 --- a/src/main/java/com/github/greennick/properties/generic/PropertiesExt.kt +++ b/src/main/java/com/github/greennick/properties/generic/PropertiesExt.kt @@ -19,10 +19,7 @@ fun MutableProperty.reset() { fun Property.subscribeNonNull(onChanged: (T) -> Unit): ListenableSubscription = subscribe { it?.also(onChanged) } -val MutableProperty.memoized: MemoizeProperty> - get() = MemoizePropertyImpl(this) - -val DebounceProperty.memoized: MemoizeProperty> +val > P.memoized: MemoizeProperty get() = MemoizePropertyImpl(this) fun MemoizeProperty<*, *>.first() { From 59c4918aa8690813db54b2c91f9b92dc59bf82ad Mon Sep 17 00:00:00 2001 From: greennick Date: Tue, 26 Nov 2019 11:38:59 +0200 Subject: [PATCH 4/5] - make generic Subscription holder; --- .../debounce/DebouncePropertyImpl.kt | 26 +++---------------- .../properties/generic/FireProperty.kt | 6 ++--- .../properties/generic/PropertyImpl.kt | 26 +++---------------- .../properties/generic/TriggeredProperty.kt | 26 +++---------------- .../subscriptions/SubscriptionImpl.kt | 22 ++++++++++++++++ 5 files changed, 34 insertions(+), 72 deletions(-) create mode 100644 src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt diff --git a/src/main/java/com/github/greennick/properties/debounce/DebouncePropertyImpl.kt b/src/main/java/com/github/greennick/properties/debounce/DebouncePropertyImpl.kt index de86312..fe071c0 100644 --- a/src/main/java/com/github/greennick/properties/debounce/DebouncePropertyImpl.kt +++ b/src/main/java/com/github/greennick/properties/debounce/DebouncePropertyImpl.kt @@ -1,6 +1,7 @@ package com.github.greennick.properties.debounce import com.github.greennick.properties.subscriptions.ListenableSubscription +import com.github.greennick.properties.subscriptions.SubscriptionImpl import java.util.concurrent.CopyOnWriteArraySet internal class DebouncePropertyImpl( @@ -28,7 +29,7 @@ internal class DebouncePropertyImpl( override fun subscribe(onChanged: (T) -> Unit): ListenableSubscription { listeners += onChanged onChanged(value) - return SubscriptionImpl(this, onChanged) + return SubscriptionImpl(listeners, onChanged) } override fun forceSet(value: T) { @@ -59,25 +60,4 @@ internal class DebouncePropertyImpl( result = 31 * result + _value.hashCode() return result } - - private class SubscriptionImpl( - private val propertyImpl: DebouncePropertyImpl, - private val action: (T) -> Unit - ) : ListenableSubscription { - private var onUnsubscribe: (() -> Unit)? = null - - override val subscribed get() = action in propertyImpl.listeners - - override fun unsubscribe() { - if (!subscribed) return - - if (propertyImpl.listeners.remove(action)) { - onUnsubscribe?.invoke() - } - } - - override fun onUnsubscribe(action: () -> Unit) { - onUnsubscribe = action - } - } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/greennick/properties/generic/FireProperty.kt b/src/main/java/com/github/greennick/properties/generic/FireProperty.kt index c4bef12..8137f8e 100644 --- a/src/main/java/com/github/greennick/properties/generic/FireProperty.kt +++ b/src/main/java/com/github/greennick/properties/generic/FireProperty.kt @@ -20,7 +20,7 @@ internal class FireProperty(initValue: T) : MutableProperty { onChanged(value) consumed = true } - return SubscriptionImpl(this, onChanged) + return FireSubscriptionImpl(this, onChanged) } override fun toString() = "Fire property of [$value], consumed: $consumed" @@ -43,7 +43,7 @@ internal class FireProperty(initValue: T) : MutableProperty { return result } - private class SubscriptionImpl( + private class FireSubscriptionImpl( private val propertyImpl: FireProperty, private val action: (T) -> Unit ) : ListenableSubscription { @@ -62,4 +62,4 @@ internal class FireProperty(initValue: T) : MutableProperty { onUnsubscribe = action } } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/greennick/properties/generic/PropertyImpl.kt b/src/main/java/com/github/greennick/properties/generic/PropertyImpl.kt index 4d85d40..2ac396e 100644 --- a/src/main/java/com/github/greennick/properties/generic/PropertyImpl.kt +++ b/src/main/java/com/github/greennick/properties/generic/PropertyImpl.kt @@ -1,6 +1,7 @@ package com.github.greennick.properties.generic import com.github.greennick.properties.subscriptions.ListenableSubscription +import com.github.greennick.properties.subscriptions.SubscriptionImpl import java.util.concurrent.CopyOnWriteArraySet internal class PropertyImpl(initValue: T) : MutableProperty { @@ -16,7 +17,7 @@ internal class PropertyImpl(initValue: T) : MutableProperty { override fun subscribe(onChanged: (T) -> Unit): ListenableSubscription { listeners += onChanged onChanged(value) - return SubscriptionImpl(this, onChanged) + return SubscriptionImpl(listeners, onChanged) } override fun toString() = "Property of [$value]" @@ -33,25 +34,4 @@ internal class PropertyImpl(initValue: T) : MutableProperty { } override fun hashCode() = value.hashCode() - - private class SubscriptionImpl( - private val propertyImpl: PropertyImpl, - private val action: (T) -> Unit - ) : ListenableSubscription { - private var onUnsubscribe: (() -> Unit)? = null - - override val subscribed get() = action in propertyImpl.listeners - - override fun unsubscribe() { - if (!subscribed) return - - if (propertyImpl.listeners.remove(action)) { - onUnsubscribe?.invoke() - } - } - - override fun onUnsubscribe(action: () -> Unit) { - onUnsubscribe = action - } - } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/greennick/properties/generic/TriggeredProperty.kt b/src/main/java/com/github/greennick/properties/generic/TriggeredProperty.kt index 8620f78..addf5f9 100644 --- a/src/main/java/com/github/greennick/properties/generic/TriggeredProperty.kt +++ b/src/main/java/com/github/greennick/properties/generic/TriggeredProperty.kt @@ -1,6 +1,7 @@ package com.github.greennick.properties.generic import com.github.greennick.properties.subscriptions.ListenableSubscription +import com.github.greennick.properties.subscriptions.SubscriptionImpl import java.util.concurrent.CopyOnWriteArraySet internal class TriggeredProperty(initValue: T) : MutableProperty { @@ -15,7 +16,7 @@ internal class TriggeredProperty(initValue: T) : MutableProperty { override fun subscribe(onChanged: (T) -> Unit): ListenableSubscription { listeners += onChanged onChanged(value) - return SubscriptionImpl(this, onChanged) + return SubscriptionImpl(listeners, onChanged) } override fun toString() = "Trigger property of [$value]" @@ -32,25 +33,4 @@ internal class TriggeredProperty(initValue: T) : MutableProperty { } override fun hashCode() = value.hashCode() - - private class SubscriptionImpl( - private val propertyImpl: TriggeredProperty, - private val action: (T) -> Unit - ) : ListenableSubscription { - private var onUnsubscribe: (() -> Unit)? = null - - override val subscribed get() = action in propertyImpl.listeners - - override fun unsubscribe() { - if (!subscribed) return - - if (propertyImpl.listeners.remove(action)) { - onUnsubscribe?.invoke() - } - } - - override fun onUnsubscribe(action: () -> Unit) { - onUnsubscribe = action - } - } -} \ No newline at end of file +} diff --git a/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt b/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt new file mode 100644 index 0000000..e5ff6cc --- /dev/null +++ b/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt @@ -0,0 +1,22 @@ +package com.github.greennick.properties.subscriptions + +class SubscriptionImpl( + private val listeners: MutableCollection<(T) -> Unit>, + private val action: (T) -> Unit +): ListenableSubscription { + private var onUnsubscribe: (() -> Unit)? = null + + override val subscribed get() = action in listeners + + override fun unsubscribe() { + if (!subscribed) return + + if (listeners.remove(action)) { + onUnsubscribe?.invoke() + } + } + + override fun onUnsubscribe(action: () -> Unit) { + onUnsubscribe = action + } +} From f13d8cd0a62b546ab76250f2277907ed58983d1f Mon Sep 17 00:00:00 2001 From: greennick Date: Wed, 4 Dec 2019 18:10:30 +0200 Subject: [PATCH 5/5] - add updates listener for CompositeMemoize; - hide SubscriptionImpl class; --- .../properties/memoize/CompositeMemoize.kt | 3 +++ .../subscriptions/SubscriptionImpl.kt | 2 +- .../memoize/CompositeMemoizePropertyTest.kt | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/greennick/properties/memoize/CompositeMemoize.kt b/src/main/java/com/github/greennick/properties/memoize/CompositeMemoize.kt index 46a4de0..2baf63d 100644 --- a/src/main/java/com/github/greennick/properties/memoize/CompositeMemoize.kt +++ b/src/main/java/com/github/greennick/properties/memoize/CompositeMemoize.kt @@ -6,6 +6,8 @@ class CompositeMemoize(first: MemoizeProperty<*, *>, vararg memos: MemoizeProper private val history = mutableListOf, Int>>() private val initPositions = _memos.map { it.position } + var onUpdate: () -> Unit = {} + val size: Int get() = history.size + 1 var position: Int = 0 @@ -37,6 +39,7 @@ class CompositeMemoize(first: MemoizeProperty<*, *>, vararg memos: MemoizeProper history.add(memo to memo.position) position = size - 1 + onUpdate() } } } diff --git a/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt b/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt index e5ff6cc..e3f2959 100644 --- a/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt +++ b/src/main/java/com/github/greennick/properties/subscriptions/SubscriptionImpl.kt @@ -1,6 +1,6 @@ package com.github.greennick.properties.subscriptions -class SubscriptionImpl( +internal class SubscriptionImpl( private val listeners: MutableCollection<(T) -> Unit>, private val action: (T) -> Unit ): ListenableSubscription { diff --git a/src/test/java/com/github/greennick/properties/memoize/CompositeMemoizePropertyTest.kt b/src/test/java/com/github/greennick/properties/memoize/CompositeMemoizePropertyTest.kt index 329aba3..6f7c655 100644 --- a/src/test/java/com/github/greennick/properties/memoize/CompositeMemoizePropertyTest.kt +++ b/src/test/java/com/github/greennick/properties/memoize/CompositeMemoizePropertyTest.kt @@ -1,11 +1,30 @@ package com.github.greennick.properties.memoize +import com.github.greennick.properties.firePropertyOf import com.github.greennick.properties.generic.memoized import com.github.greennick.properties.propertyOf +import com.github.greennick.properties.triggerPropertyOf import org.junit.Test class CompositeMemoizePropertyTest { + @Test + fun `composite sends updates`() { + val prop1 = propertyOf("zero").memoized + val prop2 = firePropertyOf(20).memoized + val prop3 = triggerPropertyOf(30L).memoized + + val composite = CompositeMemoize(prop1, prop2, prop3) + var called = false + composite.onUpdate = { called = true } + assert(!called) + + prop1.value = "hero" + prop2.value = 53 + + assert(called) + } + @Test fun `composite represents single property changes`() { val prop = propertyOf("zero").memoized