Improve onEach templates.
Add new functions to reference API. Add tests for onEach #KT-8220
This commit is contained in:
@@ -1586,6 +1586,14 @@ public inline fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given [action] on each element and returns the collection itself afterwards.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public inline fun <T, C : Iterable<T>> C.onEach(action: (T) -> Unit): C {
|
||||
return apply { for (element in this) action(element) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element.
|
||||
*/
|
||||
|
||||
@@ -178,6 +178,14 @@ public inline fun <K, V> Map<out K, V>.none(predicate: (Map.Entry<K, V>) -> Bool
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given [action] on each entry and returns the map itself afterwards.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public inline fun <K, V, M : Map<out K, V>> M.onEach(action: (Map.Entry<K, V>) -> Unit): M {
|
||||
return apply { for (element in this) action(element) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an [Iterable] instance that wraps the original map returning its entries when being iterated.
|
||||
*/
|
||||
|
||||
@@ -969,6 +969,17 @@ public inline fun <T> Sequence<T>.none(predicate: (T) -> Boolean): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence which performs the given [action] on each element of the original sequence as they pass though it.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public fun <T> Sequence<T>.onEach(action: (T) -> Unit): Sequence<T> {
|
||||
return map {
|
||||
action(it)
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element.
|
||||
*/
|
||||
|
||||
@@ -1010,6 +1010,14 @@ public inline fun CharSequence.none(predicate: (Char) -> Boolean): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given [action] on each character and returns the char sequence itself afterwards.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public inline fun <S : CharSequence> S.onEach(action: (Char) -> Unit): S {
|
||||
return apply { for (element in this) action(element) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulates value starting with the first character and applying [operation] from left to right to current accumulator value and each character.
|
||||
*/
|
||||
|
||||
@@ -192,6 +192,17 @@ abstract class IterableTests<T : Iterable<String>>(val data: T, val empty: T) {
|
||||
assertEquals(6, count)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onEach() {
|
||||
var count = 0
|
||||
val newData = data.onEach { count += it.length }
|
||||
assertEquals(6, count)
|
||||
assertTrue(data === newData)
|
||||
|
||||
// static types test
|
||||
val list: ArrayList<Int> = arrayListOf(1, 2, 3).onEach { }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun contains() {
|
||||
assertTrue(data.contains("foo"))
|
||||
|
||||
@@ -98,6 +98,19 @@ class MapTest {
|
||||
assertEquals("beverage,beer,location,Mells,name,James", list.joinToString(","))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun onEach() {
|
||||
val map = mutableMapOf("beverage" to "beer", "location" to "Mells")
|
||||
val result = StringBuilder()
|
||||
val newMap = map.onEach { result.append(it.key).append("=").append(it.value).append(";") }
|
||||
assertEquals("beverage=beer;location=Mells;", result.toString())
|
||||
assertTrue(map === newMap)
|
||||
|
||||
// static types test
|
||||
val m: HashMap<String, String> = hashMapOf("a" to "b").onEach { }
|
||||
}
|
||||
|
||||
@Test fun stream() {
|
||||
val map = mapOf("beverage" to "beer", "location" to "Mells", "name" to "James")
|
||||
val named = map.asSequence().filter { it.key == "name" }.single()
|
||||
|
||||
@@ -87,6 +87,22 @@ public class SequenceTest {
|
||||
assertEquals(listOf("f", "ba"), indexed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onEach() {
|
||||
var count = 0
|
||||
val data = sequenceOf("foo", "bar")
|
||||
val newData = data.onEach { count += it.length }
|
||||
assertFalse(data === newData)
|
||||
assertEquals(0, count, "onEach should be executed lazily")
|
||||
|
||||
data.forEach { }
|
||||
assertEquals(0, count, "onEach should be executed only when resulting sequence is iterated")
|
||||
|
||||
val sum = newData.sumBy { it.length }
|
||||
assertEquals(sum, count)
|
||||
}
|
||||
|
||||
|
||||
@Test fun filterAndTakeWhileExtractTheElementsWithinRange() {
|
||||
assertEquals(listOf(144, 233, 377, 610, 987), fibonacci().filter { it > 100 }.takeWhile { it < 1000 }.toList())
|
||||
}
|
||||
|
||||
@@ -753,6 +753,18 @@ class StringTest {
|
||||
assertEquals(data.toString(), sb.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onEach() = withOneCharSequenceArg("abcd") { data ->
|
||||
val result = StringBuilder()
|
||||
val newData = data.onEach { result.append(it + 1) }
|
||||
assertEquals("bcde", result.toString())
|
||||
assertTrue(data === newData)
|
||||
|
||||
// static types test
|
||||
val s: String = "x".onEach { }
|
||||
val sb: StringBuilder = result.onEach { }
|
||||
}
|
||||
|
||||
|
||||
@Test fun filter() {
|
||||
assertEquals("acdca", ("abcdcba").filter { !it.equals('b') })
|
||||
|
||||
@@ -1512,6 +1512,7 @@ public final class kotlin/collections/CollectionsKt {
|
||||
public static final fun mutableListOf ([Ljava/lang/Object;)Ljava/util/List;
|
||||
public static final fun none (Ljava/lang/Iterable;)Z
|
||||
public static final fun none (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z
|
||||
public static final fun onEach (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Ljava/lang/Iterable;
|
||||
public static final fun partition (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Lkotlin/Pair;
|
||||
public static final fun plus (Ljava/lang/Iterable;Ljava/lang/Iterable;)Ljava/util/List;
|
||||
public static final fun plus (Ljava/lang/Iterable;Ljava/lang/Object;)Ljava/util/List;
|
||||
@@ -1647,6 +1648,7 @@ public final class kotlin/collections/MapsKt {
|
||||
public static final fun mutableMapOf ([Lkotlin/Pair;)Ljava/util/Map;
|
||||
public static final fun none (Ljava/util/Map;)Z
|
||||
public static final fun none (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Z
|
||||
public static final fun onEach (Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Ljava/util/Map;
|
||||
public static final fun plus (Ljava/util/Map;Ljava/lang/Iterable;)Ljava/util/Map;
|
||||
public static final fun plus (Ljava/util/Map;Ljava/util/Map;)Ljava/util/Map;
|
||||
public static final fun plus (Ljava/util/Map;Lkotlin/Pair;)Ljava/util/Map;
|
||||
@@ -2056,6 +2058,7 @@ public final class kotlin/sequences/SequencesKt {
|
||||
public static final fun minus (Lkotlin/sequences/Sequence;[Ljava/lang/Object;)Lkotlin/sequences/Sequence;
|
||||
public static final fun none (Lkotlin/sequences/Sequence;)Z
|
||||
public static final fun none (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Z
|
||||
public static final fun onEach (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/sequences/Sequence;
|
||||
public static final fun partition (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function1;)Lkotlin/Pair;
|
||||
public static final fun plus (Lkotlin/sequences/Sequence;Ljava/lang/Iterable;)Lkotlin/sequences/Sequence;
|
||||
public static final fun plus (Lkotlin/sequences/Sequence;Ljava/lang/Object;)Lkotlin/sequences/Sequence;
|
||||
@@ -2404,6 +2407,7 @@ public final class kotlin/text/StringsKt {
|
||||
public static final fun minWith (Ljava/lang/CharSequence;Ljava/util/Comparator;)Ljava/lang/Character;
|
||||
public static final fun none (Ljava/lang/CharSequence;)Z
|
||||
public static final fun none (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Z
|
||||
public static final fun onEach (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)Ljava/lang/CharSequence;
|
||||
public static final fun padEnd (Ljava/lang/CharSequence;IC)Ljava/lang/CharSequence;
|
||||
public static final fun padEnd (Ljava/lang/String;IC)Ljava/lang/String;
|
||||
public static synthetic fun padEnd$default (Ljava/lang/CharSequence;ICILjava/lang/Object;)Ljava/lang/CharSequence;
|
||||
|
||||
@@ -719,27 +719,37 @@ fun aggregates(): List<GenericFunction> {
|
||||
}
|
||||
}
|
||||
|
||||
templates add f("onEach(action: (T) -> Unit)") {
|
||||
inline(true)
|
||||
|
||||
doc { f -> "Performs the given [action] on each ${f.element} and returns the receiver afterwards." }
|
||||
returns("SELF")
|
||||
templates addAll listOf(Iterables, Maps, CharSequences).map { f -> f("onEach(action: (T) -> Unit)") {
|
||||
only(f)
|
||||
since("1.1")
|
||||
inline(true)
|
||||
doc { f -> "Performs the given [action] on each ${f.element} and returns the ${f.collection} itself afterwards." }
|
||||
val collectionType = when(f) {
|
||||
Maps -> "M"
|
||||
CharSequences -> "S"
|
||||
else -> "C"
|
||||
}
|
||||
customReceiver(collectionType)
|
||||
returns(collectionType)
|
||||
typeParam("$collectionType : SELF")
|
||||
|
||||
body {
|
||||
"""
|
||||
return apply { for (element in this) action(element) }
|
||||
"""
|
||||
}
|
||||
include(Maps, CharSequences)
|
||||
}}
|
||||
|
||||
exclude(Iterables)
|
||||
typeParam(Generic) { "I: Iterable<E>" }
|
||||
typeParam(Generic) { "E" }
|
||||
customReceiver(Generic) { "I" }
|
||||
returns(Generic) { "I" }
|
||||
|
||||
doc(Sequences) { f -> "Applies the supplied [action] on each ${f.element} of the Sequence as they pass through it." }
|
||||
inline(false, Sequences)
|
||||
returns(Sequences) { "Sequence<T>" }
|
||||
templates add f("onEach(action: (T) -> Unit)") {
|
||||
only(Sequences)
|
||||
since("1.1")
|
||||
returns("SELF")
|
||||
doc { f ->
|
||||
"""
|
||||
Returns a sequence which performs the given [action] on each ${f.element} of the original sequence as they pass though it.
|
||||
"""
|
||||
}
|
||||
body(Sequences) {
|
||||
"""
|
||||
return map {
|
||||
|
||||
Reference in New Issue
Block a user