Split ItemDescriptor to builder and read-only descriptor
This commit is contained in:
parent
1a983665f8
commit
2352f1cff1
@ -5,6 +5,7 @@
|
||||
- LogManager plugin
|
||||
- dataforge-context API dependency on SLF4j
|
||||
- Context `withEnv` and `fetch` methods to manipulate plugins without changing plugins after creation.
|
||||
- Split `ItemDescriptor` into builder and read-only part
|
||||
|
||||
### Changed
|
||||
- Kotlin-logging moved from common to JVM and JS. Replaced by console for native.
|
||||
|
@ -4,7 +4,7 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
group = "space.kscience"
|
||||
version = "0.4.0-dev-7"
|
||||
version = "0.4.0-dev-8"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
@ -22,5 +22,8 @@ ksciencePublish {
|
||||
}
|
||||
|
||||
apiValidation {
|
||||
if(project.version.toString().contains("dev")) {
|
||||
validationDisabled = true
|
||||
}
|
||||
nonPublicMarkers.add("space.kscience.dataforge.misc.DFExperimental")
|
||||
}
|
@ -8,6 +8,7 @@ import space.kscience.dataforge.meta.transformations.nullableItemToObject
|
||||
import space.kscience.dataforge.meta.transformations.nullableObjectToMetaItem
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
|
||||
@DFExperimental
|
||||
public class ConfigProperty<T : Any>(
|
||||
@ -24,7 +25,7 @@ public class ConfigProperty<T : Any>(
|
||||
|
||||
override fun onChange(owner: Any?, callback: (T?) -> Unit) {
|
||||
config.onChange(owner) { name, oldItem, newItem ->
|
||||
if (name == this.name && oldItem != newItem) callback(converter.nullableItemToObject(newItem))
|
||||
if (name.startsWith(this.name) && oldItem != newItem) callback(converter.nullableItemToObject(newItem))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.dataforge.properties
|
||||
|
||||
import space.kscience.dataforge.meta.ItemPropertyProvider
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
import space.kscience.dataforge.names.toName
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
|
||||
@ -16,7 +17,7 @@ public fun <P : ItemPropertyProvider, T : Any> P.property(property: KMutableProp
|
||||
|
||||
override fun onChange(owner: Any?, callback: (T?) -> Unit) {
|
||||
this@property.onChange(this) { name, oldItem, newItem ->
|
||||
if (name == property.name.toName() && oldItem != newItem) {
|
||||
if (name.startsWith(property.name.toName()) && oldItem != newItem) {
|
||||
callback(property.get(this@property))
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,12 @@ public fun Meta.toConfig(): Config = Config().also { builder ->
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this config, optionally applying the given [block].
|
||||
* The listeners of the original Config are not retained.
|
||||
*/
|
||||
public inline fun Config.copy(block: Config.() -> Unit = {}): Config = toConfig().apply(block)
|
||||
|
||||
/**
|
||||
* Return this [Meta] as [Config] if it is [Config] and create a new copy otherwise
|
||||
*/
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.dataforge.meta
|
||||
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.startsWith
|
||||
import space.kscience.dataforge.names.toName
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@ -34,7 +35,7 @@ public fun <O : ObservableItemProvider, T> O.useProperty(
|
||||
//Pass initial value.
|
||||
callBack(property.get(this))
|
||||
onChange(owner) { name, oldItem, newItem ->
|
||||
if (name == property.name.toName() && oldItem != newItem) {
|
||||
if (name.startsWith(property.name.toName()) && oldItem != newItem) {
|
||||
callBack(property.get(this))
|
||||
}
|
||||
}
|
||||
|
@ -3,28 +3,26 @@ package space.kscience.dataforge.meta.descriptors
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.misc.DFBuilder
|
||||
import space.kscience.dataforge.names.*
|
||||
import space.kscience.dataforge.values.*
|
||||
|
||||
/**
|
||||
* A common parent for [ValueDescriptor] and [NodeDescriptor]. Describes a single [TypedMetaItem] or a group of same-name-siblings.
|
||||
*/
|
||||
@DFBuilder
|
||||
public sealed class ItemDescriptor(final override val config: Config) : Configurable {
|
||||
public sealed interface ItemDescriptor: MetaRepr {
|
||||
|
||||
/**
|
||||
* True if same name siblings with this name are allowed
|
||||
*/
|
||||
public var multiple: Boolean by config.boolean(false)
|
||||
public val multiple: Boolean
|
||||
|
||||
/**
|
||||
* The item description text
|
||||
*/
|
||||
public var info: String? by config.string()
|
||||
public val info: String?
|
||||
|
||||
/**
|
||||
* True if the item is required
|
||||
*/
|
||||
public abstract var required: Boolean
|
||||
public val required: Boolean
|
||||
|
||||
|
||||
/**
|
||||
@ -32,14 +30,56 @@ public sealed class ItemDescriptor(final override val config: Config) : Configur
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public var attributes: Config? by config.node()
|
||||
public val attributes: Meta?
|
||||
|
||||
/**
|
||||
* An index field by which this node is identified in case of same name siblings construct
|
||||
*/
|
||||
public var indexKey: String by config.string(DEFAULT_INDEX_KEY)
|
||||
public val indexKey: String
|
||||
|
||||
public abstract fun copy(): ItemDescriptor
|
||||
public companion object {
|
||||
public const val DEFAULT_INDEX_KEY: String = "@index"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The builder for [ItemDescriptor]
|
||||
*/
|
||||
@DFBuilder
|
||||
public sealed class ItemDescriptorBuilder(final override val config: Config) : Configurable, ItemDescriptor {
|
||||
|
||||
/**
|
||||
* True if same name siblings with this name are allowed
|
||||
*/
|
||||
override var multiple: Boolean by config.boolean(false)
|
||||
|
||||
/**
|
||||
* The item description text
|
||||
*/
|
||||
override var info: String? by config.string()
|
||||
|
||||
/**
|
||||
* True if the item is required
|
||||
*/
|
||||
abstract override var required: Boolean
|
||||
|
||||
|
||||
/**
|
||||
* Additional attributes of an item. For example validation and widget parameters
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var attributes: Config? by config.node()
|
||||
|
||||
/**
|
||||
* An index field by which this node is identified in case of same name siblings construct
|
||||
*/
|
||||
override var indexKey: String by config.string(DEFAULT_INDEX_KEY)
|
||||
|
||||
public abstract fun build(): ItemDescriptor
|
||||
|
||||
override fun toMeta(): Meta = config
|
||||
|
||||
public companion object {
|
||||
public const val DEFAULT_INDEX_KEY: String = "@index"
|
||||
@ -49,7 +89,7 @@ public sealed class ItemDescriptor(final override val config: Config) : Configur
|
||||
/**
|
||||
* Configure attributes of the descriptor, creating an attributes node if needed.
|
||||
*/
|
||||
public inline fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
||||
public inline fun ItemDescriptorBuilder.attributes(block: Config.() -> Unit) {
|
||||
(attributes ?: Config().also { this.attributes = it }).apply(block)
|
||||
}
|
||||
|
||||
@ -66,140 +106,6 @@ public fun ItemDescriptor.validateItem(item: MetaItem?): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptor for meta node. Could contain additional information for viewing
|
||||
* and editing.
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
public class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
init {
|
||||
config[IS_NODE_KEY] = true
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the node is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var required: Boolean by config.boolean { default == null }
|
||||
|
||||
/**
|
||||
* The default for this node. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public var default: Config? by config.node()
|
||||
|
||||
/**
|
||||
* The map of children item descriptors (both nodes and values)
|
||||
*/
|
||||
public val items: Map<String, ItemDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.associate { (name, item) ->
|
||||
if (name == null) error("Child item index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
if (node[IS_NODE_KEY].boolean == true) {
|
||||
name to NodeDescriptor(node as Config)
|
||||
} else {
|
||||
name to ValueDescriptor(node as Config)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The map of children node descriptors
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public val nodes: Map<String, NodeDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||
it.value.node[IS_NODE_KEY].boolean == true
|
||||
}.associate { (name, item) ->
|
||||
if (name == null) error("Child node index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
name to NodeDescriptor(node as Config)
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of children value descriptors
|
||||
*/
|
||||
public val values: Map<String, ValueDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||
it.value.node[IS_NODE_KEY].boolean != true
|
||||
}.associate { (name, item) ->
|
||||
if (name == null) error("Child value index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
name to ValueDescriptor(node as Config)
|
||||
}
|
||||
|
||||
private fun buildNode(name: Name): NodeDescriptor {
|
||||
return when (name.length) {
|
||||
0 -> this
|
||||
1 -> {
|
||||
val token = NameToken(ITEM_KEY.toString(), name.toString())
|
||||
val config: Config = config[token].node ?: Config().also {
|
||||
it[IS_NODE_KEY] = true
|
||||
config[token] = it
|
||||
}
|
||||
NodeDescriptor(config)
|
||||
}
|
||||
else -> buildNode(name.firstOrNull()?.asName()!!).buildNode(name.cutFirst())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a child item descriptor for this node
|
||||
*/
|
||||
private fun newItem(key: String, descriptor: ItemDescriptor) {
|
||||
if (items.keys.contains(key)) error("The key $key already exists in descriptor")
|
||||
val token = ITEM_KEY.withIndex(key)
|
||||
config[token] = descriptor.config
|
||||
}
|
||||
|
||||
public fun item(name: Name, descriptor: ItemDescriptor) {
|
||||
buildNode(name.cutLast()).newItem(name.lastOrNull().toString(), descriptor)
|
||||
}
|
||||
|
||||
public fun item(name: String, descriptor: ItemDescriptor) {
|
||||
item(name.toName(), descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure a child node descriptor
|
||||
*/
|
||||
public fun node(name: Name, block: NodeDescriptor.() -> Unit) {
|
||||
item(name, NodeDescriptor().apply(block))
|
||||
}
|
||||
|
||||
public fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
||||
node(name.toName(), block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure child value descriptor
|
||||
*/
|
||||
public fun value(name: Name, block: ValueDescriptor.() -> Unit) {
|
||||
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
||||
item(name, ValueDescriptor().apply(block))
|
||||
}
|
||||
|
||||
public fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
||||
value(name.toName(), block)
|
||||
}
|
||||
|
||||
override fun copy(): NodeDescriptor = NodeDescriptor(config.toConfig())
|
||||
|
||||
public companion object {
|
||||
|
||||
internal val ITEM_KEY: Name = "item".asName()
|
||||
internal val IS_NODE_KEY: Name = "@isNode".asName()
|
||||
|
||||
//TODO infer descriptor from spec
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun NodeDescriptor(block: NodeDescriptor.() -> Unit): NodeDescriptor =
|
||||
NodeDescriptor().apply(block)
|
||||
|
||||
/**
|
||||
* Get a descriptor item associated with given name or null if item for given name not provided
|
||||
*/
|
||||
@ -213,93 +119,3 @@ public operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
||||
|
||||
public operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
|
||||
|
||||
/**
|
||||
* A descriptor for meta value
|
||||
*
|
||||
* Descriptor can have non-atomic path. It is resolved when descriptor is added to the node
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
public class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||
|
||||
/**
|
||||
* True if the value is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var required: Boolean by config.boolean { default == null }
|
||||
|
||||
/**
|
||||
* The default for this value. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public var default: Value? by config.value()
|
||||
|
||||
public fun default(v: Any) {
|
||||
this.default = Value.of(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of allowed ValueTypes. Empty if any value type allowed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public var type: List<ValueType>? by config.listValue { ValueType.valueOf(it.string) }
|
||||
|
||||
public fun type(vararg t: ValueType) {
|
||||
this.type = listOf(*t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given value is allowed for here. The type should be allowed and
|
||||
* if it is value should be within allowed values
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public fun isAllowedValue(value: Value): Boolean {
|
||||
return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
||||
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of allowed values with descriptions. If empty than any value is
|
||||
* allowed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public var allowedValues: List<Value> by config.item().convert(
|
||||
reader = {
|
||||
val value = it.value
|
||||
when {
|
||||
value?.list != null -> value.list
|
||||
type?.let { type -> type.size == 1 && type[0] === ValueType.BOOLEAN } ?: false -> listOf(True, False)
|
||||
else -> emptyList()
|
||||
}
|
||||
},
|
||||
writer = {
|
||||
MetaItemValue(it.asValue())
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Allow given list of value and forbid others
|
||||
*/
|
||||
public fun allow(vararg v: Any) {
|
||||
this.allowedValues = v.map { Value.of(it) }
|
||||
}
|
||||
|
||||
override fun copy(): ValueDescriptor = ValueDescriptor(config.toConfig())
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two node descriptors into one using first one as primary
|
||||
*/
|
||||
public operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
|
||||
return NodeDescriptor().apply {
|
||||
config.update(other.config)
|
||||
config.update(this@plus.config)
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
package space.kscience.dataforge.meta.descriptors
|
||||
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.misc.DFBuilder
|
||||
import space.kscience.dataforge.names.*
|
||||
|
||||
|
||||
/**
|
||||
* Descriptor for meta node. Could contain additional information for viewing
|
||||
* and editing.
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
public sealed interface NodeDescriptor: ItemDescriptor {
|
||||
/**
|
||||
* True if the node is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val required: Boolean
|
||||
|
||||
/**
|
||||
* The default for this node. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val default: Config?
|
||||
|
||||
/**
|
||||
* The map of children item descriptors (both nodes and values)
|
||||
*/
|
||||
public val items: Map<String, ItemDescriptor>
|
||||
|
||||
/**
|
||||
* The map of children node descriptors
|
||||
*/
|
||||
public val nodes: Map<String, NodeDescriptor>
|
||||
|
||||
/**
|
||||
* The list of children value descriptors
|
||||
*/
|
||||
public val values: Map<String, ValueDescriptor>
|
||||
|
||||
public companion object {
|
||||
|
||||
internal val ITEM_KEY: Name = "item".asName()
|
||||
internal val IS_NODE_KEY: Name = "@isNode".asName()
|
||||
|
||||
//TODO infer descriptor from spec
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@DFBuilder
|
||||
public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBuilder(config), NodeDescriptor {
|
||||
init {
|
||||
config[IS_NODE_KEY] = true
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the node is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var required: Boolean by config.boolean { default == null }
|
||||
|
||||
/**
|
||||
* The default for this node. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var default: Config? by config.node()
|
||||
|
||||
/**
|
||||
* The map of children item descriptors (both nodes and values)
|
||||
*/
|
||||
override val items: Map<String, ItemDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.associate { (name, item) ->
|
||||
if (name == null) error("Child item index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
if (node[IS_NODE_KEY].boolean == true) {
|
||||
name to NodeDescriptorBuilder(node as Config)
|
||||
} else {
|
||||
name to ValueDescriptorBuilder(node as Config)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The map of children node descriptors
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val nodes: Map<String, NodeDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||
it.value.node[IS_NODE_KEY].boolean == true
|
||||
}.associate { (name, item) ->
|
||||
if (name == null) error("Child node index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
name to NodeDescriptorBuilder(node as Config)
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of children value descriptors
|
||||
*/
|
||||
override val values: Map<String, ValueDescriptor>
|
||||
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||
it.value.node[IS_NODE_KEY].boolean != true
|
||||
}.associate { (name, item) ->
|
||||
if (name == null) error("Child value index should not be null")
|
||||
val node = item.node ?: error("Node descriptor must be a node")
|
||||
name to ValueDescriptorBuilder(node as Config)
|
||||
}
|
||||
|
||||
private fun buildNode(name: Name): NodeDescriptorBuilder {
|
||||
return when (name.length) {
|
||||
0 -> this
|
||||
1 -> {
|
||||
val token = NameToken(ITEM_KEY.toString(), name.toString())
|
||||
val config: Config = config[token].node ?: Config().also {
|
||||
it[IS_NODE_KEY] = true
|
||||
config[token] = it
|
||||
}
|
||||
NodeDescriptorBuilder(config)
|
||||
}
|
||||
else -> buildNode(name.firstOrNull()?.asName()!!).buildNode(name.cutFirst())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a child item descriptor for this node
|
||||
*/
|
||||
private fun newItem(key: String, descriptor: ItemDescriptor) {
|
||||
if (items.keys.contains(key)) error("The key $key already exists in descriptor")
|
||||
val token = ITEM_KEY.withIndex(key)
|
||||
config[token] = descriptor.toMeta()
|
||||
}
|
||||
|
||||
public fun item(name: Name, descriptor: ItemDescriptor) {
|
||||
buildNode(name.cutLast()).newItem(name.lastOrNull().toString(), descriptor)
|
||||
}
|
||||
|
||||
public fun item(name: String, descriptor: ItemDescriptor) {
|
||||
item(name.toName(), descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure a child node descriptor
|
||||
*/
|
||||
public fun node(name: Name, block: NodeDescriptorBuilder.() -> Unit) {
|
||||
item(name, NodeDescriptorBuilder().apply(block))
|
||||
}
|
||||
|
||||
public fun node(name: String, block: NodeDescriptorBuilder.() -> Unit) {
|
||||
node(name.toName(), block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure child value descriptor
|
||||
*/
|
||||
public fun value(name: Name, block: ValueDescriptorBuilder.() -> Unit) {
|
||||
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
||||
item(name, ValueDescriptorBuilder().apply(block))
|
||||
}
|
||||
|
||||
public fun value(name: String, block: ValueDescriptorBuilder.() -> Unit) {
|
||||
value(name.toName(), block)
|
||||
}
|
||||
|
||||
override fun build(): NodeDescriptor = NodeDescriptorBuilder(config.copy())
|
||||
|
||||
public companion object {
|
||||
|
||||
internal val ITEM_KEY: Name = "item".asName()
|
||||
internal val IS_NODE_KEY: Name = "@isNode".asName()
|
||||
|
||||
//TODO infer descriptor from spec
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun NodeDescriptor(block: NodeDescriptorBuilder.() -> Unit): NodeDescriptor =
|
||||
NodeDescriptorBuilder().apply(block)
|
||||
|
||||
/**
|
||||
* Merge two node descriptors into one using first one as primary
|
||||
*/
|
||||
public operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
|
||||
return NodeDescriptorBuilder().apply {
|
||||
config.update(other.toMeta())
|
||||
config.update(this@plus.toMeta())
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package space.kscience.dataforge.meta.descriptors
|
||||
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.misc.DFBuilder
|
||||
import space.kscience.dataforge.values.*
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A descriptor for meta value
|
||||
*
|
||||
* Descriptor can have non-atomic path. It is resolved when descriptor is added to the node
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@DFBuilder
|
||||
public sealed interface ValueDescriptor: ItemDescriptor{
|
||||
|
||||
/**
|
||||
* True if the value is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val required: Boolean
|
||||
|
||||
/**
|
||||
* The default for this value. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val default: Value?
|
||||
|
||||
|
||||
/**
|
||||
* A list of allowed ValueTypes. Empty if any value type allowed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val type: List<ValueType>?
|
||||
/**
|
||||
* Check if given value is allowed for here. The type should be allowed and
|
||||
* if it is value should be within allowed values
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public fun isAllowedValue(value: Value): Boolean =
|
||||
(type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
||||
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
||||
|
||||
/**
|
||||
* A list of allowed values with descriptions. If empty than any value is
|
||||
* allowed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val allowedValues: List<Value>
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder fir [ValueDescriptor]
|
||||
*/
|
||||
@DFBuilder
|
||||
public class ValueDescriptorBuilder(config: Config = Config()) : ItemDescriptorBuilder(config), ValueDescriptor {
|
||||
|
||||
/**
|
||||
* True if the value is required
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var required: Boolean by config.boolean { default == null }
|
||||
|
||||
/**
|
||||
* The default for this value. Null if there is no default.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var default: Value? by config.value()
|
||||
|
||||
public fun default(v: Any) {
|
||||
this.default = Value.of(v)
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of allowed ValueTypes. Empty if any value type allowed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var type: List<ValueType>? by config.listValue { ValueType.valueOf(it.string) }
|
||||
|
||||
public fun type(vararg t: ValueType) {
|
||||
this.type = listOf(*t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given value is allowed for here. The type should be allowed and
|
||||
* if it is value should be within allowed values
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
override fun isAllowedValue(value: Value): Boolean {
|
||||
return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
|
||||
&& (allowedValues.isEmpty() || allowedValues.contains(value))
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of allowed values with descriptions. If empty than any value is
|
||||
* allowed.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override var allowedValues: List<Value> by config.item().convert(
|
||||
reader = {
|
||||
val value = it.value
|
||||
when {
|
||||
value?.list != null -> value.list
|
||||
type?.let { type -> type.size == 1 && type[0] === ValueType.BOOLEAN } ?: false -> listOf(True, False)
|
||||
else -> emptyList()
|
||||
}
|
||||
},
|
||||
writer = {
|
||||
MetaItemValue(it.asValue())
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Allow given list of value and forbid others
|
||||
*/
|
||||
public fun allow(vararg v: Any) {
|
||||
this.allowedValues = v.map { Value.of(it) }
|
||||
}
|
||||
|
||||
override fun build(): ValueDescriptor = ValueDescriptorBuilder(config.copy())
|
||||
}
|
@ -4,7 +4,7 @@ import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.values.ValueType
|
||||
import space.kscience.dataforge.values.asValue
|
||||
|
||||
public inline fun <reified E : Enum<E>> NodeDescriptor.enum(
|
||||
public inline fun <reified E : Enum<E>> NodeDescriptorBuilder.enum(
|
||||
key: Name,
|
||||
default: E?,
|
||||
crossinline modifier: ValueDescriptor.() -> Unit = {},
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -7,7 +7,7 @@ pluginManagement {
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
}
|
||||
|
||||
val toolsVersion = "0.9.4"
|
||||
val toolsVersion = "0.9.5-dev"
|
||||
val kotlinVersion = "1.5.0-M2"
|
||||
|
||||
plugins {
|
||||
|
Loading…
Reference in New Issue
Block a user