Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
green-nick committed Dec 4, 2019
2 parents 49d919f + f13d8cd commit 55cb5e4
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 77 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -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')
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<T>(
Expand Down Expand Up @@ -28,7 +29,7 @@ internal class DebouncePropertyImpl<T>(
override fun subscribe(onChanged: (T) -> Unit): ListenableSubscription {
listeners += onChanged
onChanged(value)
return SubscriptionImpl(this, onChanged)
return SubscriptionImpl(listeners, onChanged)
}

override fun forceSet(value: T) {
Expand Down Expand Up @@ -59,25 +60,4 @@ internal class DebouncePropertyImpl<T>(
result = 31 * result + _value.hashCode()
return result
}

private class SubscriptionImpl<T>(
private val propertyImpl: DebouncePropertyImpl<T>,
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
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@ operator fun <T> MutableProperty<List<T>>.minusAssign(another: Iterable<T>) {

operator fun <T> Property<List<T>>.get(index: Int): T = value[index]

/**
* Set extensions
*/

@JvmName("addToPropertyOfSet")
operator fun <T> MutableProperty<Set<T>>.plusAssign(element: T) {
value = value + element
}

@JvmName("addToPropertyOfSet")
operator fun <T> MutableProperty<Set<T>>.plusAssign(another: Iterable<T>) {
value = value + another
}

@JvmName("removeFromPropertyOfSet")
operator fun <T> MutableProperty<Set<T>>.minusAssign(element: T) {
value = value - element
}

@JvmName("removeFromPropertyOfSet")
operator fun <T> MutableProperty<Set<T>>.minusAssign(another: Iterable<T>) {
value = value - another
}

/**
* Map extensions
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class FireProperty<T>(initValue: T) : MutableProperty<T> {
onChanged(value)
consumed = true
}
return SubscriptionImpl(this, onChanged)
return FireSubscriptionImpl(this, onChanged)
}

override fun toString() = "Fire property of [$value], consumed: $consumed"
Expand All @@ -43,7 +43,7 @@ internal class FireProperty<T>(initValue: T) : MutableProperty<T> {
return result
}

private class SubscriptionImpl<T>(
private class FireSubscriptionImpl<T>(
private val propertyImpl: FireProperty<T>,
private val action: (T) -> Unit
) : ListenableSubscription {
Expand All @@ -62,4 +62,4 @@ internal class FireProperty<T>(initValue: T) : MutableProperty<T> {
onUnsubscribe = action
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ fun <T> MutableProperty<T?>.reset() {
fun <T> Property<T?>.subscribeNonNull(onChanged: (T) -> Unit): ListenableSubscription =
subscribe { it?.also(onChanged) }

val <T> MutableProperty<T>.memoized: MemoizeProperty<T, MutableProperty<T>>
get() = MemoizePropertyImpl(this)

val <T> DebounceProperty<T>.memoized: MemoizeProperty<T, DebounceProperty<T>>
val <T, P : MutableProperty<T>> P.memoized: MemoizeProperty<T, P>
get() = MemoizePropertyImpl(this)

fun MemoizeProperty<*, *>.first() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<T>(initValue: T) : MutableProperty<T> {
Expand All @@ -16,7 +17,7 @@ internal class PropertyImpl<T>(initValue: T) : MutableProperty<T> {
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]"
Expand All @@ -33,25 +34,4 @@ internal class PropertyImpl<T>(initValue: T) : MutableProperty<T> {
}

override fun hashCode() = value.hashCode()

private class SubscriptionImpl<T>(
private val propertyImpl: PropertyImpl<T>,
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
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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<T>(initValue: T) : MutableProperty<T> {
Expand All @@ -15,7 +16,7 @@ internal class TriggeredProperty<T>(initValue: T) : MutableProperty<T> {
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]"
Expand All @@ -32,25 +33,4 @@ internal class TriggeredProperty<T>(initValue: T) : MutableProperty<T> {
}

override fun hashCode() = value.hashCode()

private class SubscriptionImpl<T>(
private val propertyImpl: TriggeredProperty<T>,
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
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class CompositeMemoize(first: MemoizeProperty<*, *>, vararg memos: MemoizeProper
private val history = mutableListOf<Pair<MemoizeProperty<*, *>, Int>>()
private val initPositions = _memos.map { it.position }

var onUpdate: () -> Unit = {}

val size: Int get() = history.size + 1

var position: Int = 0
Expand Down Expand Up @@ -37,6 +39,7 @@ class CompositeMemoize(first: MemoizeProperty<*, *>, vararg memos: MemoizeProper

history.add(memo to memo.position)
position = size - 1
onUpdate()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.github.greennick.properties.subscriptions

internal class SubscriptionImpl<T>(
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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 55cb5e4

Please sign in to comment.