diff --git a/build.gradle.kts b/build.gradle.kts index 43ea9882..3395cacc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("scientifik.publish") version toolsVersion apply false } -val dataforgeVersion by extra("0.1.8-dev-1") +val dataforgeVersion by extra("0.1.8-dev-2") val bintrayRepo by extra("dataforge") val githubProject by extra("dataforge-core") diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt index b38b7d95..884c1c26 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt @@ -64,4 +64,5 @@ fun Configurable.setProperty(key: String, meta: Meta?) = setProperty(key, meta?. fun T.configure(meta: Meta): T = this.apply { config.update(meta) } +@DFBuilder inline fun T.configure(action: Config.() -> Unit): T = apply { config.apply(action) } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt index 3aa5b848..768ddbfa 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -173,8 +173,8 @@ interface MetaNode> : Meta { operator fun > M?.get(name: Name): MetaItem? = if( this == null) { null } else { - @Suppress("UNCHECKED_CAST") - (this as Meta).get(name) as MetaItem? + @Suppress("UNCHECKED_CAST", "ReplaceGetOrSet") + (this as Meta).get(name) as MetaItem? // Do not change } operator fun > M?.get(key: String): MetaItem? = this[key.toName()] diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt index bb280734..16fcf40d 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -76,11 +76,9 @@ inline fun MutableMeta<*>.remove(name: Name) = set(name, null) @Suppress("NOTHING_TO_INLINE") inline fun MutableMeta<*>.remove(name: String) = remove(name.toName()) -fun MutableMeta<*>.setValue(name: Name, value: Value) = - set(name, MetaItem.ValueItem(value)) +fun MutableMeta<*>.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value)) -fun MutableMeta<*>.setValue(name: String, value: Value) = - set(name.toName(), MetaItem.ValueItem(value)) +fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value) fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) { when (item) { @@ -98,7 +96,7 @@ fun MutableMeta<*>.setNode(name: Name, node: Meta) = fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node) /** - * Universal set method + * Universal unsafe set method */ operator fun MutableMeta<*>.set(name: Name, value: Any?) { when (value) { @@ -173,4 +171,17 @@ fun > M.append(name: Name, value: Any?) { } } -fun > M.append(name: String, value: Any?) = append(name.toName(), value) \ No newline at end of file +fun > M.append(name: String, value: Any?) = append(name.toName(), value) + +/** + * Apply existing node with given [builder] or create a new element with it. + */ +@DFExperimental +fun > M.edit(name: Name, builder: M.() -> Unit) { + val item = when(val existingItem = get(name)){ + null -> empty().also { set(name, it) } + is MetaItem.NodeItem -> existingItem.node + else -> error("Can't edit value meta item") + } + item.apply(builder) +} \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index 02af4374..a551b313 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -24,19 +24,20 @@ sealed class ItemDescriptor(val config: Config) { */ var info: String? by config.string() - /** - * Additional attributes of an item. For example validation and widget parameters - * - * @return - */ - var attributes by config.node() - /** * True if the item is required * * @return */ abstract var required: Boolean + + + /** + * Additional attributes of an item. For example validation and widget parameters + * + * @return + */ + var attributes by config.node() } /** @@ -166,12 +167,12 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { value(name.toName(), block) } - companion object{ + companion object { val ITEM_KEY = "item".asName() val IS_NODE_KEY = "@isNode".asName() - inline operator fun invoke(block: NodeDescriptor.()->Unit) = NodeDescriptor().apply(block) + inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block) //TODO infer descriptor from spec } @@ -251,9 +252,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * @return */ var allowedValues: List by config.value().transform { - when{ + when { it?.list != null -> it.list - type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False) + type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False) else -> emptyList() } } @@ -264,4 +265,14 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { fun allow(vararg v: Any) { this.allowedValues = v.map { Value.of(it) } } +} + +/** + * Merge two node descriptors into one using first one as primary + */ +operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor { + return NodeDescriptor().apply { + config.update(other.config) + config.update(this@plus.config) + } } \ No newline at end of file