Node editor for MutableMeta

This commit is contained in:
Alexander Nozik 2020-04-21 19:32:29 +03:00
parent aa52c45c5a
commit 5e8e3014f7
5 changed files with 43 additions and 20 deletions

View File

@ -6,7 +6,7 @@ plugins {
id("scientifik.publish") version toolsVersion apply false 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 bintrayRepo by extra("dataforge")
val githubProject by extra("dataforge-core") val githubProject by extra("dataforge-core")

View File

@ -64,4 +64,5 @@ fun Configurable.setProperty(key: String, meta: Meta?) = setProperty(key, meta?.
fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) } fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
@DFBuilder
inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) } inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }

View File

@ -173,8 +173,8 @@ interface MetaNode<out M : MetaNode<M>> : Meta {
operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) { operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) {
null null
} else { } else {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
(this as Meta).get(name) as MetaItem<M>? (this as Meta).get(name) as MetaItem<M>? // Do not change
} }
operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()] operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]

View File

@ -76,11 +76,9 @@ inline fun MutableMeta<*>.remove(name: Name) = set(name, null)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun MutableMeta<*>.remove(name: String) = remove(name.toName()) inline fun MutableMeta<*>.remove(name: String) = remove(name.toName())
fun MutableMeta<*>.setValue(name: Name, value: Value) = fun MutableMeta<*>.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
set(name, MetaItem.ValueItem(value))
fun MutableMeta<*>.setValue(name: String, value: Value) = fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value)
set(name.toName(), MetaItem.ValueItem(value))
fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) { fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) {
when (item) { when (item) {
@ -98,7 +96,7 @@ fun MutableMeta<*>.setNode(name: Name, node: Meta) =
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node) 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?) { operator fun MutableMeta<*>.set(name: Name, value: Any?) {
when (value) { when (value) {
@ -174,3 +172,16 @@ fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
} }
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value) fun <M : MutableMeta<M>> 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 : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) {
val item = when(val existingItem = get(name)){
null -> empty().also { set(name, it) }
is MetaItem.NodeItem<M> -> existingItem.node
else -> error("Can't edit value meta item")
}
item.apply(builder)
}

View File

@ -24,19 +24,20 @@ sealed class ItemDescriptor(val config: Config) {
*/ */
var info: String? by config.string() 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 * True if the item is required
* *
* @return * @return
*/ */
abstract var required: Boolean 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) value(name.toName(), block)
} }
companion object{ companion object {
val ITEM_KEY = "item".asName() val ITEM_KEY = "item".asName()
val IS_NODE_KEY = "@isNode".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 //TODO infer descriptor from spec
} }
@ -251,7 +252,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
* @return * @return
*/ */
var allowedValues: List<Value> by config.value().transform { var allowedValues: List<Value> by config.value().transform {
when{ when {
it?.list != null -> it.list 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() else -> emptyList()
@ -265,3 +266,13 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
this.allowedValues = v.map { Value.of(it) } 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)
}
}