Last active
December 30, 2020 18:17
-
-
Save libetl/1e446d60da00d1af74a2303918496f1c to your computer and use it in GitHub Desktop.
Router
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.toilelibre.libe | |
import java.lang.reflect.Method | |
import kotlin.math.pow | |
import kotlin.reflect.KFunction | |
import kotlin.reflect.full.companionObject | |
import kotlin.reflect.full.companionObjectInstance | |
import kotlin.reflect.full.declaredFunctions | |
import kotlin.reflect.full.memberProperties | |
open class Router constructor(tableInput: String) { | |
val machineReadable = tableInput | |
.trimIndent() | |
.let { | |
"โโฆโโ โฃโฌโโฉโโโชโโฌโโโผโคโโดโโญโฎโฐโฏโโผโ".split("").fold(it) { acc, s -> | |
if (s.isEmpty()) acc else acc.replace(s[0], ' ') | |
} | |
} | |
.let { | |
"โโ".split("").fold(it) { acc, s -> | |
if (s.isEmpty()) acc else acc.replace(s[0], 'โ') | |
} | |
} | |
.replace(Regex("\n\\s*", RegexOption.MULTILINE), "\n") | |
.trim() | |
.split("\n") | |
.joinToString("\n") { row -> | |
if (row.matches(Regex(".*โ\\s*$"))) | |
row.replace(Regex("^\\s*โ"), "") | |
.replace(Regex("โ\\s*$"), "") | |
else row | |
} | |
private val map: Map<List<List<String>>, String> = machineReadable | |
.substringAfter('\n') | |
.split('\n').map { row -> | |
row.substringBeforeLast('โ').split('โ').map { | |
it.split('|').map { it.trim() } | |
} to row.substringAfterLast('โ').trim() | |
}.toMap() | |
val stripesNames: List<String> = machineReadable | |
.substringBefore('\n').split('โ').map { it.trim() } | |
private val argsCount: Int = map.keys.first().size + 1 | |
inline fun <reified T> kotlinValueOf(): KFunction<*>? = | |
T::class.declaredFunctions.firstOrNull { | |
it.name == "valueOf" && | |
it.parameters.map { it.type } == listOf(String::class) | |
} | |
inline fun <reified T> javaValueOf(): Method? = | |
T::class.java.declaredMethods.firstOrNull { | |
it.name == "valueOf" && | |
it.parameters.map { it.type } == listOf(String::class.java) | |
} | |
inline fun <reified T> companionObjectOf(bestValueFor: String) = | |
T::class.companionObject!!.memberProperties.find { it.name == bestValueFor }!! | |
.call(T::class.companionObjectInstance) as T | |
fun bestValueFor(params: List<Any?>) = | |
map.entries.maxByOrNull { entry -> | |
params.mapIndexed { argNumber, param -> | |
val match = 10.toDouble().pow(argsCount - argNumber.toDouble()).toLong() | |
when { | |
param.toString() in entry.key[argNumber] -> match | |
entry.key[argNumber].all { it.startsWith("!") } && | |
param.toString() !in entry.key[argNumber].map { it.substring(1) } -> match | |
entry.key[argNumber].all { it.isEmpty() } -> 0 | |
else -> -1 | |
} | |
} | |
// uncomment the line below to debug (by looking at the highest value in the logs) | |
// .also { println(entry.toString() + " " + if(it.all{ it >= 0 }) it.sum() else -1) } | |
.takeIf { it.all { it >= 0 } }?.sum() ?: -1 | |
}!!.value | |
fun asList(params: Map<String, String>) = | |
params.entries.sortedBy { stripesNames.indexOf(it.key) }.map { it.value } | |
inline fun <reified T> `๐`(vararg params: Any) = `๐`<T>(params.toList()) | |
inline infix fun <reified T> `๐`(params: Map<String, String>) = | |
`๐`<T>(asList(params)) | |
inline infix fun <reified T> `๐`(params: List<*>) = | |
bestValueFor(params).let { | |
it.takeIf { T::class == String::class } as T? | |
?: kotlinValueOf<T>()?.call(it) as T? | |
?: javaValueOf<T>()?.invoke(null, it) as T? | |
?: companionObjectOf(it) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.toilelibre.libe | |
import org.junit.Test | |
import org.toilelibre.libe.RouterTest.Decision.* | |
import java.security.KeyFactory | |
import java.security.KeyStore | |
import kotlin.test.assertEquals | |
class RouterTest { | |
@Test | |
fun noTable() { | |
assertEquals("", Router("").`๐`("")) | |
} | |
@Test | |
fun onlyHeader() { | |
val header = | |
"""day of the week | time of the day | message | |
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโ | |
""" | |
Router(header).`๐`<String>() | |
} | |
@Test | |
fun withTexts() { | |
val messages = Router(""" | |
day of the week | time of the day | message | |
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโ | |
Monday โ morning โ Good luck | |
โ morning โ Good morning | |
โ afternoon โ Good afternoon | |
โ evening โ Good evening | |
โ night โ Good night | |
Friday โ evening โ Have a good weekend | |
Saturday โ night โ Have fun | |
""") | |
assertEquals("Good luck", | |
messages.`๐`("Monday", "morning")) | |
assertEquals("Good morning", | |
messages.`๐`("Wednesday", "morning")) | |
assertEquals("Good evening", | |
messages.`๐`("Saturday", "evening")) | |
} | |
enum class Decision { | |
PASS, REJECT | |
} | |
@Test | |
fun withEnums() { | |
val exams = Router(""" | |
Maths | Physics | English | Sports | Decision | |
โโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโผโโโโโโโโโ | |
โ โ โ โ $REJECT | |
$REJECT โ โ โ โ $REJECT | |
โ $REJECT โ $PASS โ $PASS โ $PASS | |
$PASS โ $PASS โ โ โ $PASS | |
""") | |
assertEquals(REJECT, | |
exams.`๐`(REJECT, null, null, null)) | |
assertEquals(REJECT, | |
exams.`๐`(REJECT, PASS, PASS, PASS)) | |
assertEquals(PASS, | |
exams.`๐`(PASS, REJECT, PASS, PASS)) | |
assertEquals(REJECT, | |
exams.`๐`(null, null, null, null)) | |
} | |
companion object { | |
val RSA = KeyFactory.getInstance("RSA")!! | |
val JKS = KeyStore.getInstance("JKS")!! | |
val PKCS12 = KeyStore.getInstance("PKCS12")!! | |
} | |
@Test | |
fun useCompanionObject() { | |
val router = Router(""" | |
arch โ hasJava โ has.NET โ choose | |
โโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโ | |
โ โ โ RSA | |
โ yes โ โ JKS | |
win โ โ โ PKCS12 | |
win|linux โ โ yes โ PKCS12 | |
""") | |
assertEquals(RSA, | |
router.route<RouterTest, KeyFactory>("linux", "no", "no")) | |
assertEquals(PKCS12, | |
router.route<RouterTest, KeyStore>("linux", "no", "yes")) | |
assertEquals(PKCS12, | |
router.route<RouterTest, KeyStore>("win", "no", "yes")) | |
assertEquals(PKCS12, | |
router.route<RouterTest, KeyStore>("win", "yes", "no")) | |
assertEquals(JKS, | |
router.route<RouterTest, KeyStore>("linux", "yes", "no")) | |
} | |
@Test | |
fun returningBoolean() { | |
val router = Router( | |
""" | |
Left โ Right โ XOr | |
โโโโโโโโโผโโโโโโโโโโผโโโโโโ | |
false โ false โ false | |
false โ true โ true | |
true โ false โ true | |
true โ true โ false | |
""" | |
) | |
val result: Boolean = router.`๐`(false, true) | |
expectThat(result).isTrue() | |
} | |
@Test | |
fun returningNumber() { | |
val router = Router( | |
""" | |
Country โ Colors | |
โโโโโโโโโโโโโโโผโโโโโโโโโ | |
France โ 3 | |
Russia โ 3 | |
Austria โ 2 | |
South Africa โ 6 | |
โ -1 | |
""" | |
) | |
val france: Int = router `๐` listOf("France") | |
val ireland: Int = router `๐` listOf("Ireland") | |
expectThat(france).isEqualTo(3) | |
expectThat(ireland).isEqualTo(-1) | |
} | |
@Test | |
fun worksInAnyStripesOrder() { | |
val router = Router( | |
""" | |
arg1 โ arg2 โ arg3 โ arg4 โ arg5 โ arg6 โ value | |
โโโโโโโผโโโโโโโโผโโโโโโโโผโโโโโโโผโโโโโโโโผโโโโโโโโผโโโโโโโโโโโโโโโโโ | |
one โ two โ three โ four โ five โ six โ true | |
โ โ โ โ โ โ false | |
""" | |
) | |
val shouldBeTrue: Boolean = router `๐` mapOf( | |
"arg3" to "three", | |
"arg5" to "five", | |
"arg2" to "two", | |
"arg4" to "four", | |
"arg1" to "one" | |
) | |
expectThat(shouldBeTrue).isTrue() | |
} | |
@Test | |
fun separatorsCanBeAdded() { | |
val router = Router( | |
""" | |
Country โ Continent | |
โโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโ | |
UnitedStates โ NorthAmerica | |
Canada โ NorthAmerica | |
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ | |
China โ Asia | |
Singapore โ Asia | |
India โ Asia | |
Laos โ Asia | |
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ | |
Austria โ Europe | |
France โ Europe | |
โโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโ | |
""" | |
) | |
expectThat(router.`๐`<String>("UnitedStates")) | |
.isEqualTo("NorthAmerica") | |
expectThat(router.`๐`<String>("Canada")) | |
.isEqualTo("NorthAmerica") | |
expectThat(router.`๐`<String>("China")) | |
.isEqualTo("Asia") | |
expectThat(router.`๐`<String>("Singapore")) | |
.isEqualTo("Asia") | |
expectThat(router.`๐`<String>("India")) | |
.isEqualTo("Asia") | |
expectThat(router.`๐`<String>("Laos")) | |
.isEqualTo("Asia") | |
expectThat(router.`๐`<String>("Austria")) | |
.isEqualTo("Europe") | |
expectThat(router.`๐`<String>("France")) | |
.isEqualTo("Europe") | |
} | |
@Test | |
fun tableWithBorders() { | |
val router = Router( | |
""" | |
โญโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฎ | |
โ Number โ Pluralization โ | |
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโโค | |
โ 0 โ None โ | |
โ 1 โ One โ | |
โ 2 โ A couple โ | |
โ 3 โ Three โ | |
โ 4|5|6 โ A few โ | |
โ โ Many โ | |
โฐโโโโโโโโโโโดโโโโโโโโโโโโโโโโโฏ | |
""" | |
) | |
expectThat( | |
router.`๐`<String>(0) | |
).isEqualTo("None") | |
expectThat( | |
router.`๐`<String>(3) | |
).isEqualTo("Three") | |
expectThat( | |
router.`๐`<String>(5) | |
).isEqualTo("A few") | |
expectThat( | |
router.`๐`<String>(8) | |
).isEqualTo("Many") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment