From 4bb95ca79336d05fc13ba23602d578500d3dea8f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 10 Jun 2019 20:07:40 +0300 Subject: [PATCH] Joined descriptors --- build.gradle.kts | 2 +- .../dataforge/descriptors/ItemDescriptor.kt | 280 +++++++++++++++++- .../dataforge/descriptors/NodeDescriptor.kt | 134 --------- .../dataforge/descriptors/ValueDescriptor.kt | 193 ------------ 4 files changed, 274 insertions(+), 335 deletions(-) delete mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt delete mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt diff --git a/build.gradle.kts b/build.gradle.kts index 9d89d17b..b24c5a70 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,4 @@ -val dataforgeVersion by extra("0.1.3-dev-2") +val dataforgeVersion by extra("0.1.3-dev-3") allprojects { repositories { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt index 1616fff4..09e4d11e 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt @@ -1,9 +1,275 @@ package hep.dataforge.descriptors -interface ItemDescriptor { - val name: String - val multiple: Boolean - val required: Boolean - val info: String? - val tags: List -} \ No newline at end of file +import hep.dataforge.meta.* +import hep.dataforge.names.NameToken +import hep.dataforge.names.toName +import hep.dataforge.values.False +import hep.dataforge.values.True +import hep.dataforge.values.Value +import hep.dataforge.values.ValueType + +sealed class ItemDescriptor(override val config: Config) : Specific { + + /** + * The name of this item + * + * @return + */ + var name: String by string { error("Anonymous descriptors are not allowed") } + + /** + * True if same name siblings with this name are allowed + * + * @return + */ + var multiple: Boolean by boolean(false) + + /** + * The item description + * + * @return + */ + var info: String? by string() + + /** + * A list of tags for this item. Tags used to customize item usage + * + * @return + */ + var tags: List by value { value -> + value?.list?.map { it.string } ?: emptyList() + } + + /** + * True if the item is required + * + * @return + */ + abstract var required: Boolean +} + +/** + * Descriptor for meta node. Could contain additional information for viewing + * and editing. + * + * @author Alexander Nozik + */ +class NodeDescriptor(config: Config) : ItemDescriptor(config){ + + /** + * True if the node is required + * + * @return + */ + override var required: Boolean by boolean { default == null } + + /** + * The default for this node. Null if there is no default. + * + * @return + */ + var default: Meta? by node() + + /** + * The list of value descriptors + */ + val values: Map + get() = config.getAll(VALUE_KEY.toName()).entries.associate { (name, node) -> + name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node")) + } + + fun value(name: String, descriptor: ValueDescriptor) { + if(items.keys.contains(name)) error("The key $name already exists in descriptor") + val token = NameToken(VALUE_KEY, name) + config[token] = descriptor.config + } + + /** + * Add a value descriptor using block for + */ + fun value(name: String, block: ValueDescriptor.() -> Unit) { + value(name, ValueDescriptor.build { this.name = name }.apply(block)) + } + + /** + * The map of children node descriptors + */ + val nodes: Map + get() = config.getAll(NODE_KEY.toName()).entries.associate { (name, node) -> + name to wrap(node.node ?: error("Node descriptor must be a node")) + } + + + fun node(name: String, descriptor: NodeDescriptor) { + if(items.keys.contains(name)) error("The key $name already exists in descriptor") + val token = NameToken(NODE_KEY, name) + config[token] = descriptor.config + } + + fun node(name: String, block: NodeDescriptor.() -> Unit) { + node(name, build { this.name = name }.apply(block)) + } + + val items: Map get() = nodes + values + + + //override val descriptor: NodeDescriptor = empty("descriptor") + + companion object : Specification { + +// const val ITEM_KEY = "item" + const val NODE_KEY = "node" + const val VALUE_KEY = "value" + + override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config) + + //TODO infer descriptor from spec + } +} + + +/** + * A descriptor for meta value + * + * Descriptor can have non-atomic path. It is resolved when descriptor is added to the node + * + * @author Alexander Nozik + */ +class ValueDescriptor(config: Config) : ItemDescriptor(config){ + + + /** + * True if the value is required + * + * @return + */ + override var required: Boolean by boolean { default == null } + + /** + * The default for this value. Null if there is no default. + * + * @return + */ + var default: Value? by value() + + fun default(v: Any) { + this.default = Value.of(v) + } + + /** + * A list of allowed ValueTypes. Empty if any value type allowed + * + * @return + */ + var type: List by value { + it?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList() + } + + 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 + */ + fun isAllowedValue(value: Value): Boolean { + return (type.isEmpty() || type.contains(ValueType.STRING) || type.contains(value.type)) && (allowedValues.isEmpty() || allowedValues.contains( + value + )) + } + + /** + * A list of allowed values with descriptions. If empty than any value is + * allowed. + * + * @return + */ + var allowedValues: List by value { + it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) { + listOf(True, False) + } else { + emptyList() + } + } + + /** + * Allow given list of value and forbid others + */ + fun allow(vararg v: Any) { + this.allowedValues = v.map { Value.of(it) } + } + + companion object : Specification { + + override fun wrap(config: Config): ValueDescriptor = ValueDescriptor(config) + + inline fun > enum(name: String) = + build { + this.name = name + type(ValueType.STRING) + this.allowedValues = enumValues().map { Value.of(it.name) } + } + +// /** +// * Build a value descriptor from annotation +// */ +// fun build(def: ValueDef): ValueDescriptor { +// val builder = MetaBuilder("value") +// .setValue("name", def.key) +// +// if (def.type.isNotEmpty()) { +// builder.setValue("type", def.type) +// } +// +// if (def.multiple) { +// builder.setValue("multiple", def.multiple) +// } +// +// if (!def.info.isEmpty()) { +// builder.setValue("info", def.info) +// } +// +// if (def.allowed.isNotEmpty()) { +// builder.setValue("allowedValues", def.allowed) +// } else if (def.enumeration != Any::class) { +// if (def.enumeration.java.isEnum) { +// val values = def.enumeration.java.enumConstants +// builder.setValue("allowedValues", values.map { it.toString() }) +// } else { +// throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property") +// } +// } +// +// if (def.def.isNotEmpty()) { +// builder.setValue("default", def.def) +// } else if (!def.required) { +// builder.setValue("required", def.required) +// } +// +// if (def.tags.isNotEmpty()) { +// builder.setValue("tags", def.tags) +// } +// return ValueDescriptor(builder) +// } +// +// /** +// * Build empty value descriptor +// */ +// fun empty(valueName: String): ValueDescriptor { +// val builder = MetaBuilder("value") +// .setValue("name", valueName) +// return ValueDescriptor(builder) +// } +// +// /** +// * Merge two separate value descriptors +// */ +// fun merge(primary: ValueDescriptor, secondary: ValueDescriptor): ValueDescriptor { +// return ValueDescriptor(Laminate(primary.meta, secondary.meta)) +// } + } +} diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt deleted file mode 100644 index 0c001889..00000000 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/NodeDescriptor.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2018 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package hep.dataforge.descriptors - -import hep.dataforge.meta.* -import hep.dataforge.names.NameToken -import hep.dataforge.names.toName - -/** - * Descriptor for meta node. Could contain additional information for viewing - * and editing. - * - * @author Alexander Nozik - */ -class NodeDescriptor(override val config: Config) : ItemDescriptor, Specific { - - /** - * The name of this node - * - * @return - */ - override var name: String by string { error("Anonymous descriptors are not allowed") } - - - /** - * The default for this node. Null if there is no default. - * - * @return - */ - var default: Meta? by node() - - /** - * True if multiple children with this nodes name are allowed. Anonymous - * nodes are always single - * - * @return - */ - override var multiple: Boolean by boolean(false) - - /** - * True if the node is required - * - * @return - */ - override var required: Boolean by boolean { default == null } - - /** - * The node description - * - * @return - */ - override var info: String? by string() - - /** - * A list of tags for this node. Tags used to customize node usage - * - * @return - */ - override var tags: List by value { value -> - value?.list?.map { it.string } ?: emptyList() - } - - /** - * The list of value descriptors - */ - val values: Map - get() = config.getAll(VALUE_KEY.toName()).entries.associate { (name, node) -> - name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node")) - } - - fun value(name: String, descriptor: ValueDescriptor) { - val token = NameToken(VALUE_KEY, name) - config[token] = descriptor.config - } - - /** - * Add a value descriptor using block for - */ - fun value(name: String, block: ValueDescriptor.() -> Unit) { - value(name, ValueDescriptor.build { this.name = name }.apply(block)) - } - - /** - * The map of children node descriptors - */ - val nodes: Map - get() = config.getAll(NODE_KEY.toName()).entries.associate { (name, node) -> - name to wrap(node.node ?: error("Node descriptor must be a node")) - } - - - fun node(name: String, descriptor: NodeDescriptor) { - val token = NameToken(NODE_KEY, name) - config[token] = descriptor.config - } - - fun node(name: String, block: NodeDescriptor.() -> Unit) { - node(name, build { this.name = name }.apply(block)) - } - - val items: Map get() = nodes + values - - - //override val descriptor: NodeDescriptor = empty("descriptor") - - companion object : Specification { - - const val NODE_KEY = "node" - const val VALUE_KEY = "value" - - override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config) - - //TODO infer descriptor from spec - } -} diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt deleted file mode 100644 index cfaaf5f9..00000000 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ValueDescriptor.kt +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2018 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package hep.dataforge.descriptors - -import hep.dataforge.meta.* -import hep.dataforge.values.False -import hep.dataforge.values.True -import hep.dataforge.values.Value -import hep.dataforge.values.ValueType - -/** - * A descriptor for meta value - * - * Descriptor can have non-atomic path. It is resolved when descriptor is added to the node - * - * @author Alexander Nozik - */ -class ValueDescriptor(override val config: Config) : ItemDescriptor, Specific { - - /** - * The default for this value. Null if there is no default. - * - * @return - */ - var default: Value? by value() - - fun default(v: Any) { - this.default = Value.of(v) - } - - /** - * True if multiple values with this name are allowed. - * - * @return - */ - override var multiple: Boolean by boolean(false) - - /** - * True if the value is required - * - * @return - */ - override var required: Boolean by boolean { default == null } - - /** - * Value name - * - * @return - */ - override var name: String by string { error("Anonymous descriptors are not allowed") } - - /** - * The value info - * - * @return - */ - override var info: String? by string() - - /** - * A list of allowed ValueTypes. Empty if any value type allowed - * - * @return - */ - var type: List by value { - it?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList() - } - - fun type(vararg t: ValueType) { - this.type = listOf(*t) - } - - override var tags: List by value { value -> - value?.list?.map { it.string } ?: emptyList() - } - - /** - * 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 - */ - fun isAllowedValue(value: Value): Boolean { - return (type.isEmpty() || type.contains(ValueType.STRING) || type.contains(value.type)) && (allowedValues.isEmpty() || allowedValues.contains( - value - )) - } - - /** - * A list of allowed values with descriptions. If empty than any value is - * allowed. - * - * @return - */ - var allowedValues: List by value { - it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) { - listOf(True, False) - } else { - emptyList() - } - } - - /** - * Allow given list of value and forbid others - */ - fun allow(vararg v: Any) { - this.allowedValues = v.map { Value.of(it) } - } - - companion object : Specification { - - override fun wrap(config: Config): ValueDescriptor = ValueDescriptor(config) - - inline fun > enum(name: String) = - build { - this.name = name - type(ValueType.STRING) - this.allowedValues = enumValues().map { Value.of(it.name) } - } - -// /** -// * Build a value descriptor from annotation -// */ -// fun build(def: ValueDef): ValueDescriptor { -// val builder = MetaBuilder("value") -// .setValue("name", def.key) -// -// if (def.type.isNotEmpty()) { -// builder.setValue("type", def.type) -// } -// -// if (def.multiple) { -// builder.setValue("multiple", def.multiple) -// } -// -// if (!def.info.isEmpty()) { -// builder.setValue("info", def.info) -// } -// -// if (def.allowed.isNotEmpty()) { -// builder.setValue("allowedValues", def.allowed) -// } else if (def.enumeration != Any::class) { -// if (def.enumeration.java.isEnum) { -// val values = def.enumeration.java.enumConstants -// builder.setValue("allowedValues", values.map { it.toString() }) -// } else { -// throw RuntimeException("Only enumeration classes are allowed in 'enumeration' annotation property") -// } -// } -// -// if (def.def.isNotEmpty()) { -// builder.setValue("default", def.def) -// } else if (!def.required) { -// builder.setValue("required", def.required) -// } -// -// if (def.tags.isNotEmpty()) { -// builder.setValue("tags", def.tags) -// } -// return ValueDescriptor(builder) -// } -// -// /** -// * Build empty value descriptor -// */ -// fun empty(valueName: String): ValueDescriptor { -// val builder = MetaBuilder("value") -// .setValue("name", valueName) -// return ValueDescriptor(builder) -// } -// -// /** -// * Merge two separate value descriptors -// */ -// fun merge(primary: ValueDescriptor, secondary: ValueDescriptor): ValueDescriptor { -// return ValueDescriptor(Laminate(primary.meta, secondary.meta)) -// } - } -}