Skip to content

Commit 1b68213

Browse files
committed
refactor(util/config): polish new config parser
1 parent f7a033b commit 1b68213

File tree

3 files changed

+121
-33
lines changed

3 files changed

+121
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
package com.osfans.trime.util.config
22

3-
import com.charleskorn.kaml.YamlList
4-
import com.charleskorn.kaml.YamlMap
5-
import com.charleskorn.kaml.YamlNode
6-
import com.charleskorn.kaml.YamlNull
7-
import com.charleskorn.kaml.YamlScalar
8-
import com.charleskorn.kaml.yamlList
9-
import com.charleskorn.kaml.yamlMap
10-
import com.charleskorn.kaml.yamlScalar
113
import timber.log.Timber
124

135
/**
@@ -19,65 +11,65 @@ class Config(private val data: ConfigData = ConfigData()) {
1911

2012
fun isNull(path: String): Boolean {
2113
val p = data.traverse(path)
22-
return p == null || p is YamlNull
14+
return p == null || p.type == ConfigItem.ValueType.Null
2315
}
2416

2517
fun isValue(path: String): Boolean {
2618
val p = data.traverse(path)
27-
return p == null || p is YamlScalar
19+
return p == null || p.type == ConfigItem.ValueType.Scalar
2820
}
2921

3022
fun isList(path: String): Boolean {
3123
val p = data.traverse(path)
32-
return p == null || p is YamlList
24+
return p == null || p.type == ConfigItem.ValueType.List
3325
}
3426

3527
fun isMap(path: String): Boolean {
3628
val p = data.traverse(path)
37-
return p == null || p is YamlMap
29+
return p == null || p.type == ConfigItem.ValueType.Map
3830
}
3931

4032
fun getBool(path: String, defValue: Boolean = false): Boolean {
4133
Timber.d("read: $path")
42-
val p = data.traverse(path)?.yamlScalar
43-
return p?.toBoolean() ?: defValue
34+
val p = data.traverse(path)?.configValue
35+
return p?.getBool() ?: defValue
4436
}
4537

4638
fun getInt(path: String, defValue: Int = 0): Int {
4739
Timber.d("read: $path")
48-
val p = data.traverse(path)?.yamlScalar
49-
return p?.toInt() ?: defValue
40+
val p = data.traverse(path)?.configValue
41+
return p?.getInt() ?: defValue
5042
}
5143

5244
fun getFloat(path: String, defValue: Float = 0f): Float {
5345
Timber.d("read: $path")
54-
val p = data.traverse(path)?.yamlScalar
55-
return p?.toFloat() ?: defValue
46+
val p = data.traverse(path)?.configValue
47+
return p?.getFloat() ?: defValue
5648
}
5749

5850
fun getString(path: String, defValue: String = ""): String {
5951
Timber.d("read: $path")
60-
val p = data.traverse(path)?.yamlScalar
61-
return p?.content ?: defValue
52+
val p = data.traverse(path)?.configValue
53+
return p?.getString() ?: defValue
6254
}
6355

64-
fun getNode(path: String): YamlNode? {
56+
fun getItem(path: String): ConfigItem? {
6557
Timber.d("read: $path")
6658
return data.traverse(path)
6759
}
6860

69-
fun getValue(path: String): YamlScalar? {
61+
fun getValue(path: String): ConfigValue? {
7062
Timber.d("read: $path")
71-
return data.traverse(path)?.yamlScalar
63+
return data.traverse(path)?.configValue
7264
}
7365

74-
fun getList(path: String): YamlList? {
66+
fun getList(path: String): ConfigList? {
7567
Timber.d("read: $path")
76-
return data.traverse(path)?.yamlList
68+
return data.traverse(path)?.configList
7769
}
7870

79-
fun getMap(path: String): YamlMap? {
71+
fun getMap(path: String): ConfigMap? {
8072
Timber.d("read: $path")
81-
return data.traverse(path)?.yamlMap
73+
return data.traverse(path)?.configMap
8274
}
8375
}

app/src/main/java/com/osfans/trime/util/config/ConfigData.kt

+22-6
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,32 @@ package com.osfans.trime.util.config
33
import com.charleskorn.kaml.Yaml
44
import com.charleskorn.kaml.YamlConfiguration
55
import com.charleskorn.kaml.YamlException
6+
import com.charleskorn.kaml.YamlList
67
import com.charleskorn.kaml.YamlMap
78
import com.charleskorn.kaml.YamlNode
9+
import com.charleskorn.kaml.YamlNull
10+
import com.charleskorn.kaml.YamlScalar
11+
import com.charleskorn.kaml.yamlList
812
import com.charleskorn.kaml.yamlMap
13+
import com.charleskorn.kaml.yamlScalar
914
import timber.log.Timber
1015
import java.io.File
1116

17+
fun convertFromYaml(node: YamlNode): ConfigItem? {
18+
return when (node) {
19+
is YamlNull -> null
20+
is YamlScalar -> ConfigValue(node.yamlScalar)
21+
is YamlList -> ConfigList(node.yamlList)
22+
is YamlMap -> ConfigMap(node.yamlMap)
23+
else -> null
24+
}
25+
}
26+
1227
/**
1328
* The wrapper of parsed YAML node.
1429
*/
1530
class ConfigData {
16-
var root: YamlNode? = null
31+
var root: ConfigItem? = null
1732

1833
private val yaml = Yaml(
1934
configuration = YamlConfiguration(
@@ -33,24 +48,25 @@ class ConfigData {
3348
.inputStream()
3449
.bufferedReader()
3550
.use { it.readText() }
36-
root = yaml.parseToYamlNode(doc)
51+
val node = yaml.parseToYamlNode(doc)
52+
root = convertFromYaml(node)
3753
} catch (e: YamlException) {
38-
Timber.e("Error parsing YAML: ${e.message}")
54+
Timber.e(e, "Error parsing YAML")
3955
return false
4056
}
4157
return true
4258
}
4359

44-
fun traverse(path: String): YamlNode? {
60+
fun traverse(path: String): ConfigItem? {
4561
Timber.d("traverse: $path")
4662
if (path.isEmpty() || path == "/") return root
4763
val keys = path.trimEnd('/').split('/')
4864
var p = root
4965
for (key in keys) {
50-
if (p == null || p !is YamlMap) {
66+
if (p == null || p !is ConfigMap) {
5167
return null
5268
}
53-
p = p.yamlMap[key]
69+
p = p.configMap[key]
5470
}
5571
return p
5672
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.osfans.trime.util.config
2+
3+
import com.charleskorn.kaml.YamlList
4+
import com.charleskorn.kaml.YamlMap
5+
import com.charleskorn.kaml.YamlNode
6+
import com.charleskorn.kaml.YamlNull
7+
import com.charleskorn.kaml.YamlScalar
8+
import com.charleskorn.kaml.yamlList
9+
import com.charleskorn.kaml.yamlMap
10+
import com.charleskorn.kaml.yamlScalar
11+
12+
/** Config item base class */
13+
open class ConfigItem(val node: YamlNode) {
14+
enum class ValueType {
15+
Null, Scalar, List, Map, Tagged
16+
}
17+
open fun isEmpty() = node is YamlNull
18+
val type get() = when (node) {
19+
is YamlNull -> ValueType.Null
20+
is YamlScalar -> ValueType.Scalar
21+
is YamlList -> ValueType.List
22+
is YamlMap -> ValueType.Map
23+
else -> ValueType.Null
24+
}
25+
26+
val configValue: ConfigValue
27+
get() = this as? ConfigValue ?: error(this, "ConfigValue")
28+
29+
val configList: ConfigList
30+
get() = this as? ConfigList ?: error(this, "ConfigList")
31+
32+
val configMap: ConfigMap
33+
get() = this as? ConfigMap ?: error(this, "ConfigMap")
34+
35+
private fun error(item: ConfigItem, expectedType: String): Nothing {
36+
throw IllegalArgumentException("Expected element to be $expectedType bus is ${item::class.simpleName}")
37+
}
38+
}
39+
40+
/** The wrapper of [YamlScalar] */
41+
class ConfigValue(private val scalar: YamlScalar) : ConfigItem(scalar) {
42+
constructor(item: ConfigItem) : this(item.node.yamlScalar)
43+
44+
fun getString() = scalar.content
45+
fun getInt() = scalar.toInt()
46+
fun getFloat() = scalar.toFloat()
47+
fun getBool() = scalar.toBoolean()
48+
49+
override fun isEmpty() = scalar.content.isEmpty()
50+
}
51+
52+
/** The wrapper of [YamlList] */
53+
class ConfigList(private val list: YamlList) : ConfigItem(list) {
54+
constructor(item: ConfigItem) : this(item.node.yamlList)
55+
56+
val items get() = list.items.map { convertFromYaml(it) }
57+
58+
override fun isEmpty() = list.items.isEmpty()
59+
60+
operator fun get(index: Int) = items[index]
61+
fun getValue(index: Int) = get(index)?.configValue
62+
}
63+
64+
class ConfigMap(private val map: YamlMap) : ConfigItem(map) {
65+
constructor(item: ConfigItem) : this(item.node.yamlMap)
66+
67+
override fun isEmpty() = map.entries.isEmpty()
68+
69+
fun hasKey(key: String) = map.getKey(key) != null
70+
71+
val entries get() = map.entries.entries.associate { (s, n) ->
72+
s.content to convertFromYaml(n)
73+
}
74+
75+
@Suppress("UNCHECKED_CAST")
76+
operator fun <T : ConfigItem> get(key: String): T? =
77+
entries.entries.firstOrNull { it.key == key }?.value as T?
78+
79+
fun getValue(key: String): ConfigValue? = get<ConfigValue>(key)?.configValue
80+
}

0 commit comments

Comments
 (0)