Skip to content

Commit

Permalink
Cleanup duplicated code with stdlib (#14)
Browse files Browse the repository at this point in the history
* clean duplicated code

* make detekt happy

* update license year

* update dependencies versions
  • Loading branch information
LukasForst authored Jan 9, 2022
1 parent 9241e5e commit d7385a0
Show file tree
Hide file tree
Showing 16 changed files with 176 additions and 100 deletions.
19 changes: 14 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ on:
pull_request:

jobs:
code-smell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: 'Qodana Scan'
uses: JetBrains/[email protected]
with:
linter: jetbrains/qodana-jvm

test:
runs-on: ${{ matrix.os }}
name: Build & Test - Java ${{ matrix.java }} on ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
java: [ 8, 11, 16 ]
os: [ windows-latest, ubuntu-latest ]
java: [ 8, 11, 17 ]

steps:
- uses: actions/checkout@v2
Expand All @@ -23,8 +32,8 @@ jobs:
- name: Build lib
run: ./gradlew assemble

- name: Run tests
run: ./gradlew test --info

- name: Check styling using Detekt
run: ./gradlew detekt --info

- name: Run tests
run: ./gradlew test --info
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ jobs:
- name: Build lib
run: ./gradlew assemble

- name: Run tests
run: ./gradlew test --info

- name: Check styling using Detekt
run: ./gradlew detekt --info

- name: Run tests
run: ./gradlew test --info

publish:
needs: [ test ]
name: Build and publish library
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 Lukas Forst
Copyright (c) 2022 Lukas Forst

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
63 changes: 40 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Katlib

![CI test](https://github.com/LukasForst/katlib/workflows/CI%20test/badge.svg)
[![Release pipeline](https://github.com/LukasForst/katlib/actions/workflows/release.yml/badge.svg)](https://github.com/LukasForst/katlib/actions/workflows/release.yml)
[![Documentation](https://img.shields.io/badge/docs-online-brightgreeb)](https://katlib.forst.pw/)
[![Documentation](https://img.shields.io/badge/docs-online-brightgreeb)](https://katlib.forst.dev/)

Successor of [Ktoolz](https://github.com/blindspot-ai/ktoolz).

Collection of Kotlin extension functions and utilities. This library does not have any dependency.

## Using Katlib

Katlib is available on the Maven Central.
Then to import Katlib to Gradle project use:
Katlib is available on the Maven Central. Then to import Katlib to Gradle project use:

```Kotlin
implementation("pw.forst", "katlib", "some-latest-version")
implementation("pw.forst", "katlib", "2.1.0")
```

Or with Groovy DSL

```groovy
implementation 'pw.forst:katlib:some-latest-version'
implementation 'pw.forst:katlib:2.1.0'
```

To import Katlib to Maven project use:
Expand All @@ -29,35 +29,40 @@ To import Katlib to Maven project use:
<dependency>
<groupId>pw.forst</groupId>
<artifactId>katlib</artifactId>
<version>some-latest-version</version>
<version>2.1.0</version>
</dependency>
```

## Documentation

Available online - [katlib.forst.pw](https://katlib.forst.pw/)
Available online - [katlib.forst.dev](https://katlib.forst.dev/)

## Contribution

Feel free to submig PR with your faviourite extension functions and other cool utilities!
Feel free to submit PR with your favourite extension functions and other cool utilities!

## Examples

The library contains a lot of useful (as well as useless) extensions and functions that were gathered during my (and my colleges) Kotlin
career. Please see [tests](src/test/kotlin/pw/forst/katlib) folder for all possible functions and how to use them. Full documentation can be
found [here](https://katlib.forst.pw/).
found [here](https://katlib.forst.dev/).

Please note that some functions seems like duplicates of the standard library - usually it is not like that as they provide similar
functionality on different interface. For example there's `List.random` but not `Iterable.random` - random on `Iterable` is then implemented
in this library. Some functions are also essentially type aliases (for example `equalsIgnoreCase`) for standard library as I was having hard
time finding correct name.

However, in some cases there might be duplicates, as development of this library started in 2018 and a lot of functions came to standard
library in Kotlin 1.4. - so if you find some duplicates, let me know or create PR that deprecates them in the code.

Following functions are the most popular ones.

#### [Iterable Extensions](src/main/kotlin/pw/forst/katlib/IterableExtensions.kt)

* `Iterable<E>.getRandomElement` - returns the random element from the iterable
* `Iterable<T>.reduction` - reduce producing list, useful for cumulative sums
* `Iterable<T>.sumByLong` - sums iterable by long value with selector (*deprecated since Kotlin 1.4.0*)
* `Iterable<E>.random` - returns the random element from the iterable
* `Iterable<T>.reduction` - reduce producing list allowing you to set initial value, useful for cumulative sums
* `Iterable<List<Int>>.sumByIndexes` - sums all Lists of integers into single one by indexes
* `Iterable<List<Double>>.sumDoublesByIndexes` - same as previous but with doubles
* `Iterable<T>.maxValueBy` - returns the largest value of given iterable by provided selector
* `Iterable<T>.minValueBy` - same as previous, but smallest value
* `Iterable<T>.mapToSet` - creates set from iterable, transforms with given function
* `Iterable<T>.dominantValueBy` - returns the most frequently occurring value of the given function
* `Iterable<T1>.cartesianProduct` - cartesian product between all the elements from two iterables
Expand Down Expand Up @@ -135,68 +140,80 @@ implementation("com.fasterxml.jackson.module", "jackson-module-kotlin", jacksonV
```kotlin
val obj: MyDataClass? = parseJson<MyDataClass>(myJson)
```

* `createJson` - creates JSON from given object
* `createPrettyJson` - creates JSON with pretty print
* `createJsonBytes` - creates JSON in bytes from given object
* `prettyPrintJson` - returns pretty printed JSON value as string

#### [Boolean Extensions](src/main/kotlin/pw/forst/katlib/BooleanExtensions.kt)

`whenTrue` and `whenFalse` - useful extensions mainly used for logging when the oneliners are used.

```kotlin
fun someFunctionIndicatingSuccess(): Boolean =
fun someFunctionIndicatingSuccess(): Boolean =
someComputationReturningBoolean()
.whenFalse {
logger.warning { "someComputationReturningBoolean returned false! Computation probably failed" }
}
.whenFalse {
logger.warning { "someComputationReturningBoolean returned false! Computation probably failed" }
}
```

#### [String Extensions](src/main/kotlin/pw/forst/katlib/StringExtensions.kt)

* `startsWithLetter` - returns true fi string starts with latin letter a-z or A-Z
* `restrictLengthWithEllipsis` - shortens the string to given max length, appends ellipsis

```kotlin
assertEquals("ABCD…", "ABCDEFHG".restrictLengthWithEllipsis(5, "..."))
```

* `toUuid` - converts string to UUID

#### [Instant Extensions](src/main/kotlin/pw/forst/katlib/InstantExtensions.kt)

* `durationToInMilli` - returns absolute difference between two `Instant` values in milliseconds

#### [Crypto Extensions](src/main/kotlin/pw/forst/katlib/CryptoExtensions.kt)
* `hashWith256` - produces `SHA-256` of given string/file/bytes.

* `hashWithSha256` - produces `SHA-256` of given string/file/bytes
* `computeMd5` - computes MD5 from given byte array, returns base64 encoded data

#### [Miscellaneous Extensions](src/main/kotlin/pw/forst/katlib/OtherExtensions.kt)

* `Optional<T>.orNull(): T?` - from optional to Kotlin optional
* `T.whenNull` - executes block when `this` is null, useful for logging

```kotlin
fun someFunction(): String? =
produceOptionalString()
.whenNull { logger.warn { "produceOptionalString returned null value!" } }
```

* `T.asList` - from `this creates one element list
* `ClosedRange<T>.intersects` - intersection between ranges
* `T.with` - bundles two objects to list
* `validate` - executes invalid block if validating block returns false, useful for validation

```kotlin
validate(
{ someText.startsWith("something") && someText.endsWith("else") },
{ someText.startsWith("something") && someText.endsWith("else") },
{ throw IllegalStateException() }
)
```

* `Pair<A?, B?>.propagateNull(): Pair<A, B>?` - if left or right is null, returns null, otherwise pair
* `T.applyIf` - applies given block only if should apply block returns true

```kotlin
byteBuffer.applyIf(shouldReadInt) { getInt() }
```

* `isUUID` - returns true if given string is UUID
* `iSURL` - returns true if give string is URL (with some limitations, see docs)
* `isUuid` - returns true if given string is UUID
* `isUrl` - returns true if give string is URL (with some limitations, see docs)
* `getEnv` - shortcut for `System.getenv`
* `newLine` - shortcut for `System.lineSeparator`
* `ByteArray.toUuid` - Read ByteArray as two longs and combine the to UUID

#### [Services](src/main/kotlin/pw/forst/katlib/Services.kt)

* `TimeProvider` - Interface providing access to current time via `now` method, very useful when mocking
* `TemporalProvider` - Interface providing access to current time via `now` method, very useful when mocking
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"

id("net.nemerosa.versioning") version "2.15.1"
id("org.jetbrains.dokka") version "1.6.0"
id("org.jetbrains.dokka") version "1.6.10"
id("io.gitlab.arturbosch.detekt") version "1.19.0"
}

Expand All @@ -23,7 +23,7 @@ repositories {
}

dependencies {
val jacksonVersion = "2.13.0"
val jacksonVersion = "2.13.1"
compileOnly("com.fasterxml.jackson.core", "jackson-databind", jacksonVersion)
compileOnly("com.fasterxml.jackson.module", "jackson-module-kotlin", jacksonVersion)
compileOnly(kotlin("reflect"))
Expand All @@ -32,7 +32,7 @@ dependencies {
testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit5"))
testImplementation(kotlin("stdlib-jdk8"))
testImplementation("io.mockk", "mockk", "1.12.1") // mock framework
testImplementation("io.mockk", "mockk", "1.12.2") // mock framework
testImplementation("ch.qos.logback", "logback-classic", "1.2.9") // logging framework for the tests

val junitVersion = "5.8.1"
Expand Down
37 changes: 29 additions & 8 deletions src/main/kotlin/pw/forst/katlib/CryptoExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,40 @@ import java.util.Base64
/**
* Creates SHA256 hash of the given text.
*/
fun hashWith256(textToHash: String): String = hashWith256(textToHash.toByteArray(Charsets.UTF_8))
fun hashWithSha256(textToHash: String): String = hashWithSha256(textToHash.toByteArray(Charsets.UTF_8))

/**
* Creates SHA256 hash of the given file.
*/
fun hashWith256(fileToHash: File): String = hashWith256(fileToHash.readBytes())
fun hashWithSha256(fileToHash: File): String = hashWithSha256(fileToHash.readBytes())

/**
* Creates SHA256 hash of the given byte array.
*/
fun hashWith256(bytes: ByteArray): String {
val hashedArray = MessageDigest
.getInstance("SHA-256")
.digest(bytes)
return Base64.getEncoder().encodeToString(hashedArray)
}
fun hashWithSha256(bytes: ByteArray): String = MessageDigest
.getInstance("SHA-256")
.digest(bytes)
.toBase64()

/**
* Returns base64 encoded SHA256 of given byte array.
*/
fun ByteArray.sha256(): String = hashWithSha256(this)

/**
* Computes MD5 from given byte array, returns base64 encoded data.
*/
fun computeMd5(bytes: ByteArray): String = MessageDigest.getInstance("MD5")
.apply { update(bytes, 0, bytes.size) }
.digest()
.toBase64()

/**
* Returns base64 string MD5 of given byte array.
*/
fun ByteArray.md5(): String = computeMd5(this)

/**
* Returns base64 string representation of given byte array.
*/
fun ByteArray.toBase64(): String = Base64.getEncoder().encodeToString(this)
6 changes: 5 additions & 1 deletion src/main/kotlin/pw/forst/katlib/DateExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ import kotlin.streams.toList

/**
* Returns list of days from [this] date to [to] date (both inclusive).
*
* `datesUntil` has exclusive bound.
*/
fun LocalDate.getDateRangeTo(to: LocalDate): List<LocalDate> = this.getDateRangeToAsStream(to).toList()


/**
* Returns stream of days from [this] date to [to] date (both inclusive).
*
* `datesUntil` has exclusive bound.
*/
fun LocalDate.getDateRangeToAsStream(to: LocalDate): Stream<LocalDate> =
Stream
Expand All @@ -36,7 +41,6 @@ fun LocalDate.getInvertedDateRangeToAsStream(to: LocalDate): Stream<LocalDate> =
.iterate(this) { d -> d.minusDays(1) }
.limit(to.until(this, ChronoUnit.DAYS) + 1)


/**
* Returns week of year for [this].
*
Expand Down
Loading

0 comments on commit d7385a0

Please sign in to comment.