Skip to content

Instantly share code, notes, and snippets.

@libetl
Last active December 30, 2020 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save libetl/1e446d60da00d1af74a2303918496f1c to your computer and use it in GitHub Desktop.
Save libetl/1e446d60da00d1af74a2303918496f1c to your computer and use it in GitHub Desktop.
Router
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)
}
}
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