commonMain.jetbrains.datalore.plot.config.OptionsAccessor.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lets-plot-common Show documentation
Show all versions of lets-plot-common Show documentation
Lets-Plot JVM package without rendering part
/*
* Copyright (c) 2019. JetBrains s.r.o.
* Use of this source code is governed by the MIT license that can be found in the LICENSE file.
*/
package jetbrains.datalore.plot.config
import jetbrains.datalore.base.gcommon.collect.ClosedRange
import jetbrains.datalore.base.values.Color
import jetbrains.datalore.plot.base.Aes
import jetbrains.datalore.plot.base.render.point.PointShape
import jetbrains.datalore.plot.config.aes.AesOptionConversion
import kotlin.jvm.JvmOverloads
open class OptionsAccessor(
private val options: Map,
private val defaultOptions: Map = emptyMap()
) {
val mergedOptions: Map
get() = defaultOptions + options
val isEmpty: Boolean
get() = options.isEmpty() && defaultOptions.isEmpty()
fun update(key: String, value: Any) {
@Suppress("UNCHECKED_CAST")
(options as MutableMap)[key] = value
}
protected fun update(otherOptions: Map) {
(options as MutableMap).putAll(otherOptions)
}
fun has(option: String): Boolean {
return hasOwn(option) || defaultOptions[option] != null
}
fun hasOwn(option: String): Boolean {
return options[option] != null
}
operator fun get(option: String): Any? {
return if (hasOwn(option)) {
options[option]
} else {
defaultOptions[option]
}
}
fun getSafe(option: String): Any {
return get(option) ?: throw IllegalStateException("Option `$option` not found.")
}
fun getString(option: String): String? {
return get(option)?.toString()
}
fun getStringSafe(option: String): String {
return getString(option)
?: throw IllegalArgumentException("Can't get string value: option '$option' is not present.")
}
fun getList(option: String): List<*> {
val v = get(option) ?: return ArrayList()
require(v is List<*>) { "Not a List: $option: ${v::class.simpleName}" }
return v
}
fun getDoubleList(option: String): List {
val list = getNumList(option)
return list.map { it.toDouble() }
}
fun getNumPair(option: String): Pair {
val list = getNumList(option) { it is Number }
@Suppress("UNCHECKED_CAST")
return pickTwo(option, list) as Pair
}
fun getNumQPair(option: String): Pair {
val list = getNumList(option) { it == null || it is Number }
return pickTwo(option, list)
}
fun getNumPairDef(option: String, def: Pair): Pair {
return if (has(option)) {
getNumPair(option)
} else {
def
}
}
fun getNumQPairDef(option: String, def: Pair): Pair {
return if (has(option)) {
getNumQPair(option)
} else {
def
}
}
private fun pickTwo(option: String, list: List): Pair {
require(list.size >= 2) { "$option requires a list of 2 but was ${list.size}" }
return Pair(list[0], list[1])
}
@Suppress("UNCHECKED_CAST")
fun getNumList(option: String): List = getNumList(option) { it is Number } as List
fun getNumQList(option: String): List = getNumList(option) { it == null || it is Number }
private fun getNumber(option: String): Number? {
val v = get(option) ?: return null
require(v is Number) { "Parameter '$option' expected to be a Number, but was ${v::class.simpleName}" }
return v;
}
private fun getNumList(option: String, predicate: (Any?) -> Boolean): List {
val list = getList(option)
requireAll(list, predicate) { "$option requires a list of numbers but not numeric encountered: $it" }
@Suppress("UNCHECKED_CAST")
return list as List
}
fun getAsList(option: String): List {
val v = get(option) ?: emptyList()
return if (v is List<*>) {
v
} else {
listOf(v)
}
}
fun getAsStringList(option: String): List {
// val v = get(option) ?: emptyList()
// return if (v is List<*>) {
// v.filterNotNull().map { it.toString() }
// } else {
// listOf(v.toString())
// }
return getAsList(option).filterNotNull().map { it.toString() }
}
fun getStringList(option: String): List {
val list = getList(option)
requireAll(list, { it is String }) { "$option requires a list of strings but not string encountered: $it" }
@Suppress("UNCHECKED_CAST")
return list as List
}
internal fun getRange(option: String): ClosedRange {
require(has(option)) { "'Range' value is expected in form: [min, max]" }
val range = getRangeOrNull(option)
requireNotNull(range) { "'range' value is expected in form: [min, max] but was: ${get(option)}" }
return range
}
fun getRangeOrNull(option: String): ClosedRange? {
val pair = get(option)
if ((pair is List<*> && pair.size == 2 && pair.all { it is Number }) != true) {
return null
}
val lower = (pair.first() as Number).toDouble()
val upper = (pair.last() as Number).toDouble()
return try {
ClosedRange(lower, upper)
} catch (ex: Throwable) {
null
}
}
fun getMap(option: String): Map {
val v = get(option) ?: return emptyMap()
require(v is Map<*, *>) { "Not a Map: " + option + ": " + v::class.simpleName }
@Suppress("UNCHECKED_CAST")
return v as Map
}
@JvmOverloads
fun getBoolean(option: String, def: Boolean = false): Boolean {
val v = get(option)
return v as? Boolean ?: def
}
fun getDouble(option: String): Double? {
return getNumber(option)?.toDouble()
}
fun getInteger(option: String): Int? {
return getNumber(option)?.toInt()
}
fun getLong(option: String): Long? {
return getNumber(option)?.toLong()
}
fun getDoubleDef(option: String, def: Double): Double {
return getDouble(option) ?: def
}
fun getIntegerDef(option: String, def: Int): Int {
return getInteger(option) ?: def
}
fun getLongDef(option: String, def: Long): Long {
return getLong(option) ?: def
}
private fun getValueOrNull(option: String, mapper: (Any?) -> T?): T? {
val v = get(option) ?: return null
return mapper(v)
}
fun getColor(option: String): Color? {
return getValue(Aes.COLOR, option)
}
fun getShape(option: String): PointShape? {
return getValue(Aes.SHAPE, option)
}
protected fun getValue(aes: Aes, option: String): T? {
val v = get(option) ?: return null
return AesOptionConversion.apply(aes, v)
}
companion object {
fun over(map: Map): OptionsAccessor {
return OptionsAccessor(map)
}
private fun requireAll(items: Iterable, predicate: (T) -> Boolean, lazy: (T) -> Any) {
items.filterNot { predicate(it) }.firstOrNull()?.let { require(false) { lazy(it) } }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy