Fix for #48

This commit is contained in:
Alexander Nozik 2020-04-13 15:23:05 +03:00
parent b0950f8415
commit f67fb63c45
8 changed files with 65 additions and 54 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.7") val dataforgeVersion by extra("0.1.8-dev-1")
val bintrayRepo by extra("dataforge") val bintrayRepo by extra("dataforge")
val githubProject by extra("dataforge-core") val githubProject by extra("dataforge-core")

View File

@ -28,7 +28,7 @@ class EnvelopeServer(
fun start() { fun start() {
if (job == null) { if (job == null) {
logger.info { "Starting envelope server on port $port" } logger.info { "Starting envelope server on port $port" }
val job = scope.launch(Dispatchers.IO) { job = scope.launch(Dispatchers.IO) {
val serverSocket = ServerSocket(port) val serverSocket = ServerSocket(port)
//TODO add handshake and format negotiation //TODO add handshake and format negotiation
while (isActive && !serverSocket.isClosed) { while (isActive && !serverSocket.isClosed) {

View File

@ -28,7 +28,7 @@ fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
} }
//Use these methods to customize JSON key mapping //Use these methods to customize JSON key mapping
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.getProperty("jsonName").string ?: toString() private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes["jsonName"].string ?: toString()
//private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key) //private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)
@ -146,7 +146,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit { private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
val itemDescriptor = descriptor?.items?.get(key) val itemDescriptor = descriptor?.items?.get(key)
return when (value) { when (value) {
is JsonPrimitive -> { is JsonPrimitive -> {
this[key] = this[key] =
MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem<JsonMeta> MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem<JsonMeta>

View File

@ -170,8 +170,12 @@ interface MetaNode<out M : MetaNode<M>> : Meta {
/** /**
* The same as [Meta.get], but with specific node type * The same as [Meta.get], but with specific node type
*/ */
@Suppress("UNCHECKED_CAST") 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>? = (this as Meta)[name] as MetaItem<M>? null
} else {
@Suppress("UNCHECKED_CAST")
(this as Meta).get(name) as MetaItem<M>?
}
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

@ -99,6 +99,10 @@ fun <M : MutableMeta<M>> M.boolean(default: Boolean, key: Name? = null) =
fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) = fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) =
item(default, key).transform { it.number!! } item(default, key).transform { it.number!! }
@JvmName("lazyValue")
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> Value) =
lazyItem(key, default).transform { it.value!! }
@JvmName("lazyString") @JvmName("lazyString")
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) = fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) =
lazyItem(key, default).transform { it.string!! } lazyItem(key, default).transform { it.string!! }

View File

@ -8,28 +8,28 @@ import hep.dataforge.values.Value
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
@DFBuilder @DFBuilder
sealed class ItemDescriptor : Scheme() { sealed class ItemDescriptor(val config: Config) {
/** /**
* True if same name siblings with this name are allowed * True if same name siblings with this name are allowed
* *
* @return * @return
*/ */
var multiple: Boolean by boolean(false) var multiple: Boolean by config.boolean(false)
/** /**
* The item description * The item description
* *
* @return * @return
*/ */
var info: String? by string() var info: String? by config.string()
/** /**
* Additional attributes of an item. For example validation and widget parameters * Additional attributes of an item. For example validation and widget parameters
* *
* @return * @return
*/ */
var attributes by config() var attributes by config.node()
/** /**
* True if the item is required * True if the item is required
@ -43,7 +43,7 @@ sealed class ItemDescriptor : Scheme() {
* Configure attributes of the descriptor * Configure attributes of the descriptor
*/ */
fun ItemDescriptor.attributes(block: Config.() -> Unit) { fun ItemDescriptor.attributes(block: Config.() -> Unit) {
(attributes ?: Config().also { this.config = it }).apply(block) (attributes ?: Config().also { this.attributes = it }).apply(block)
} }
/** /**
@ -65,28 +65,32 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
* @author Alexander Nozik * @author Alexander Nozik
*/ */
@DFBuilder @DFBuilder
class NodeDescriptor private constructor() : ItemDescriptor() { class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
init {
config[IS_NODE_KEY] = true
}
/** /**
* True if the node is required * True if the node is required
* *
* @return * @return
*/ */
override var required: Boolean by boolean { default == null } override var required: Boolean by config.boolean { default == null }
/** /**
* The default for this node. Null if there is no default. * The default for this node. Null if there is no default.
* *
* @return * @return
*/ */
var default by node() var default by config.node()
val items: Map<String, ItemDescriptor> val items: Map<String, ItemDescriptor>
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) -> get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
val node = item.node ?: error("Node descriptor must be a node") val node = item.node ?: error("Node descriptor must be a node")
if (node[IS_NODE_KEY].boolean == true) { if (node[IS_NODE_KEY].boolean == true) {
NodeDescriptor.wrap(node) NodeDescriptor(node)
} else { } else {
ValueDescriptor.wrap(node) ValueDescriptor(node)
} }
} }
@ -99,7 +103,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
it.value.node[IS_NODE_KEY].boolean == true it.value.node[IS_NODE_KEY].boolean == true
}.associate { (name, item) -> }.associate { (name, item) ->
val node = item.node ?: error("Node descriptor must be a node") val node = item.node ?: error("Node descriptor must be a node")
name to NodeDescriptor.wrap(node) name to NodeDescriptor(node)
} }
/** /**
@ -110,7 +114,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
it.value.node[IS_NODE_KEY].boolean != true it.value.node[IS_NODE_KEY].boolean != true
}.associate { (name, item) -> }.associate { (name, item) ->
val node = item.node ?: error("Node descriptor must be a node") val node = item.node ?: error("Node descriptor must be a node")
name to ValueDescriptor.wrap(node) name to ValueDescriptor(node)
} }
private fun buildNode(name: Name): NodeDescriptor { private fun buildNode(name: Name): NodeDescriptor {
@ -122,7 +126,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
it[IS_NODE_KEY] = true it[IS_NODE_KEY] = true
config[token] = it config[token] = it
} }
wrap(config) NodeDescriptor(config)
} }
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst()) else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
} }
@ -137,41 +141,37 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
config[token] = descriptor.config config[token] = descriptor.config
} }
fun defineItem(name: Name, descriptor: ItemDescriptor) { fun item(name: Name, descriptor: ItemDescriptor) {
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor) buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
} }
fun defineItem(name: String, descriptor: ItemDescriptor) { fun item(name: String, descriptor: ItemDescriptor) {
defineItem(name.toName(), descriptor) item(name.toName(), descriptor)
} }
fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) { fun node(name: Name, block: NodeDescriptor.() -> Unit) {
defineItem(name, NodeDescriptor(block)) item(name, NodeDescriptor().apply(block))
} }
fun defineNode(name: String, block: NodeDescriptor.() -> Unit) { fun node(name: String, block: NodeDescriptor.() -> Unit) {
defineNode(name.toName(), block) node(name.toName(), block)
} }
fun defineValue(name: Name, block: ValueDescriptor.() -> Unit) { fun value(name: Name, block: ValueDescriptor.() -> Unit) {
require(name.length >= 1) { "Name length for value descriptor must be non-empty" } require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
defineItem(name, ValueDescriptor(block)) item(name, ValueDescriptor().apply(block))
} }
fun defineValue(name: String, block: ValueDescriptor.() -> Unit) { fun value(name: String, block: ValueDescriptor.() -> Unit) {
defineValue(name.toName(), block) value(name.toName(), block)
} }
companion object : SchemeSpec<NodeDescriptor>(::NodeDescriptor) { companion object{
val ITEM_KEY = "item".asName() val ITEM_KEY = "item".asName()
val IS_NODE_KEY = "@isNode".asName() val IS_NODE_KEY = "@isNode".asName()
override fun empty(): NodeDescriptor { inline operator fun invoke(block: NodeDescriptor.()->Unit) = NodeDescriptor().apply(block)
return super.empty().apply {
config[IS_NODE_KEY] = true
}
}
//TODO infer descriptor from spec //TODO infer descriptor from spec
} }
@ -188,6 +188,8 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
} }
} }
operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
/** /**
* A descriptor for meta value * A descriptor for meta value
* *
@ -196,21 +198,21 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
* @author Alexander Nozik * @author Alexander Nozik
*/ */
@DFBuilder @DFBuilder
class ValueDescriptor : ItemDescriptor() { class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
/** /**
* True if the value is required * True if the value is required
* *
* @return * @return
*/ */
override var required: Boolean by boolean { default == null } override var required: Boolean by config.boolean { default == null }
/** /**
* The default for this value. Null if there is no default. * The default for this value. Null if there is no default.
* *
* @return * @return
*/ */
var default: Value? by value() var default: Value? by config.value()
fun default(v: Any) { fun default(v: Any) {
this.default = Value.of(v) this.default = Value.of(v)
@ -221,7 +223,7 @@ class ValueDescriptor : ItemDescriptor() {
* *
* @return * @return
*/ */
var type: List<ValueType> by item { var type: List<ValueType> by config.item().transform {
it?.value?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList() it?.value?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList()
} }
@ -248,11 +250,11 @@ class ValueDescriptor : ItemDescriptor() {
* *
* @return * @return
*/ */
var allowedValues: List<Value> by value { var allowedValues: List<Value> by config.value().transform {
it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) { when{
listOf(True, False) it?.list != null -> it.list
} else { type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False)
emptyList() else -> emptyList()
} }
} }
@ -262,6 +264,4 @@ class ValueDescriptor : ItemDescriptor() {
fun allow(vararg v: Any) { fun allow(vararg v: Any) {
this.allowedValues = v.map { Value.of(it) } this.allowedValues = v.map { Value.of(it) }
} }
companion object : SchemeSpec<ValueDescriptor>(::ValueDescriptor)
} }

View File

@ -3,18 +3,19 @@ package hep.dataforge.meta.descriptors
import hep.dataforge.values.ValueType import hep.dataforge.values.ValueType
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotNull
class DescriptorTest { class DescriptorTest {
val descriptor = NodeDescriptor { val descriptor = NodeDescriptor {
defineNode("aNode") { node("aNode") {
info = "A root demo node" info = "A root demo node"
defineValue("b") { value("b") {
info = "b number value" info = "b number value"
type(ValueType.NUMBER) type(ValueType.NUMBER)
} }
defineNode("otherNode") { node("otherNode") {
defineValue("otherValue") { value("otherValue") {
type(ValueType.BOOLEAN) type(ValueType.BOOLEAN)
default(false) default(false)
info = "default value" info = "default value"
@ -25,6 +26,8 @@ class DescriptorTest {
@Test @Test
fun testAllowedValues() { fun testAllowedValues() {
val child = descriptor["aNode.b"]
assertNotNull(child)
val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues
assertEquals(emptyList(), allowed) assertEquals(emptyList(), allowed)
} }

View File

@ -2,9 +2,9 @@ package hep.dataforge.workspace
import hep.dataforge.context.Context import hep.dataforge.context.Context
import hep.dataforge.data.* import hep.dataforge.data.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.DFBuilder import hep.dataforge.meta.DFBuilder
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.string import hep.dataforge.meta.string
import hep.dataforge.names.Name import hep.dataforge.names.Name
@ -200,7 +200,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
* Use DSL to create a descriptor for this task * Use DSL to create a descriptor for this task
*/ */
fun description(transform: NodeDescriptor.() -> Unit) { fun description(transform: NodeDescriptor.() -> Unit) {
this.descriptor = NodeDescriptor(transform) this.descriptor = NodeDescriptor().apply(transform)
} }
internal fun build(): GenericTask<R> { internal fun build(): GenericTask<R> {
@ -212,7 +212,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
return GenericTask( return GenericTask(
name, name,
type, type,
descriptor ?: NodeDescriptor.empty(), descriptor ?: NodeDescriptor(),
modelTransform modelTransform
) { ) {
val workspace = this val workspace = this