Merge pull request #49 from mipt-npm/dev

0.1.8-dev-2
This commit is contained in:
Alexander Nozik 2020-05-17 20:14:06 +03:00 committed by GitHub
commit 90a241ac75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 162 additions and 88 deletions

View File

@ -1,12 +1,13 @@
plugins { plugins {
val toolsVersion = "0.4.2" val toolsVersion = "0.5.5"
id("scientifik.mpp") version toolsVersion apply false id("scientifik.mpp") version toolsVersion apply false
id("scientifik.jvm") version toolsVersion apply false id("scientifik.jvm") version toolsVersion apply false
id("scientifik.publish") version toolsVersion apply false id("scientifik.publish") version toolsVersion apply false
id("org.jetbrains.dokka") version "0.10.1"
} }
val dataforgeVersion by extra("0.1.7") 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")
@ -22,4 +23,5 @@ allprojects {
subprojects { subprojects {
apply(plugin = "scientifik.publish") apply(plugin = "scientifik.publish")
apply(plugin = "org.jetbrains.dokka")
} }

View File

@ -13,19 +13,19 @@ kotlin {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
api(project(":dataforge-meta")) api(project(":dataforge-meta"))
api(kotlin("reflect")) api("io.github.microutils:kotlin-logging-common:1.7.9")
api("io.github.microutils:kotlin-logging-common:1.7.8")
} }
} }
val jvmMain by getting { val jvmMain by getting {
dependencies { dependencies {
api("io.github.microutils:kotlin-logging:1.7.8") api(kotlin("reflect"))
api("io.github.microutils:kotlin-logging:1.7.9")
api("ch.qos.logback:logback-classic:1.2.3") api("ch.qos.logback:logback-classic:1.2.3")
} }
} }
val jsMain by getting { val jsMain by getting {
dependencies { dependencies {
api("io.github.microutils:kotlin-logging-js:1.7.8") api("io.github.microutils:kotlin-logging-js:1.7.9")
} }
} }
} }

View File

@ -8,10 +8,11 @@ import hep.dataforge.provider.Provider
import hep.dataforge.provider.top import hep.dataforge.provider.top
import hep.dataforge.values.Value import hep.dataforge.values.Value
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import mu.KLogger import mu.KLogger
import mu.KotlinLogging import mu.KotlinLogging
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
/** /**
@ -91,8 +92,11 @@ open class Context(
config.action() config.action()
} }
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext by lazy {
get() = EmptyCoroutineContext (parent ?: Global).coroutineContext.let { parenContext ->
parenContext + SupervisorJob(parenContext[Job])
}
}
/** /**
* Detach all plugins and terminate context * Detach all plugins and terminate context

View File

@ -31,7 +31,7 @@ class MapActionBuilder<T, R>(var name: Name, var meta: MetaBuilder, val actionMe
class MapAction<T : Any, out R : Any>( class MapAction<T : Any, out R : Any>(
val inputType: KClass<out T>, val inputType: KClass<T>,
val outputType: KClass<out R>, val outputType: KClass<out R>,
private val block: MapActionBuilder<T, R>.() -> Unit private val block: MapActionBuilder<T, R>.() -> Unit
) : Action<T, R> { ) : Action<T, R> {

View File

@ -72,7 +72,7 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
* The same rules as for KPipe * The same rules as for KPipe
*/ */
class ReduceAction<T : Any, R : Any>( class ReduceAction<T : Any, R : Any>(
val inputType: KClass<out T>, val inputType: KClass<T>,
val outputType: KClass<out R>, val outputType: KClass<out R>,
private val action: ReduceGroupBuilder<T, R>.() -> Unit private val action: ReduceGroupBuilder<T, R>.() -> Unit
) : Action<T, R> { ) : Action<T, R> {

View File

@ -33,7 +33,7 @@ class SplitBuilder<T : Any, R : Any>(val name: Name, val meta: Meta) {
} }
class SplitAction<T : Any, R : Any>( class SplitAction<T : Any, R : Any>(
val inputType: KClass<out T>, val inputType: KClass<T>,
val outputType: KClass<out R>, val outputType: KClass<out R>,
private val action: SplitBuilder<T, R>.() -> Unit private val action: SplitBuilder<T, R>.() -> Unit
) : Action<T, R> { ) : Action<T, R> {

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

@ -14,7 +14,7 @@ data class MetaListener(
) )
interface ObservableMeta : Meta { interface ObservableMeta : Meta {
fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
fun removeListener(owner: Any?) fun removeListener(owner: Any?)
} }

View File

@ -50,6 +50,13 @@ interface Configurable : Described {
} }
} }
/**
* Reset the property to its default value
*/
fun Configurable.resetProperty(name: Name) {
setProperty(name, null)
}
fun Configurable.getProperty(key: String) = getProperty(key.toName()) fun Configurable.getProperty(key: String) = getProperty(key.toName())
fun Configurable.setProperty(name: Name, value: Value?) = setProperty(name, value?.let { MetaItem.ValueItem(value) }) fun Configurable.setProperty(name: Name, value: Value?) = setProperty(name, value?.let { MetaItem.ValueItem(value) })
@ -64,4 +71,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

@ -201,8 +201,8 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri
/* Node delegates */ /* Node delegates */
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> = fun Configurable.config(default: Config? = null, key: Name? = null): ReadWriteProperty<Any?, Config?> =
config.node(key) config.node(default,key)
fun Configurable.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).map( fun Configurable.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).map(
reader = { it.node }, reader = { it.node },

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", "ReplaceGetOrSet")
(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

@ -84,8 +84,8 @@ fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: Name? = null):
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null): ReadWriteProperty<Any?, Number?> = fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null): ReadWriteProperty<Any?, Number?> =
item(default, key).transform { it.number } item(default, key).transform { it.number }
inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null) = inline fun <reified M : MutableMeta<M>> M.node(default: M? = null, key: Name? = null) =
item(this, key).transform { it.node as? M } item(default, key = key).transform { it.node as? M }
@JvmName("safeString") @JvmName("safeString")
fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) = fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) =
@ -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

@ -1,5 +1,6 @@
package hep.dataforge.meta.descriptors package hep.dataforge.meta.descriptors
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.MetaBase import hep.dataforge.meta.MetaBase
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
@ -15,8 +16,10 @@ class DescriptorMeta(val descriptor: NodeDescriptor) : MetaBase() {
} }
} }
fun NodeDescriptor.buildDefaultMeta() = Laminate(default, DescriptorMeta(this))
fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> = fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> =
MetaItem.NodeItem(default ?: DescriptorMeta(this)) MetaItem.NodeItem(buildDefaultMeta())
fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null) fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null)

View File

@ -8,28 +8,21 @@ 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
*
* @return
*/
var attributes by config()
/** /**
* True if the item is required * True if the item is required
@ -37,19 +30,37 @@ sealed class ItemDescriptor : Scheme() {
* @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()
} }
/** /**
* 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)
}
/**
* Set specific attribute in the descriptor
*/
fun ItemDescriptor.setAttribute(name: Name, value: Any?) {
attributes {
set(name, value)
}
} }
/** /**
* Check if given item suits the descriptor * Check if given item suits the descriptor
*/ */
fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
if (item == null) return !required
return when (this) { return when (this) {
is ValueDescriptor -> isAllowedValue(item.value ?: return false) is ValueDescriptor -> isAllowedValue(item.value ?: return false)
is NodeDescriptor -> items.all { (key, d) -> is NodeDescriptor -> items.all { (key, d) ->
@ -65,28 +76,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 +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 NodeDescriptor.wrap(node) name to NodeDescriptor(node)
} }
/** /**
@ -110,7 +125,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 +137,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 +152,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 +199,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 +209,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 +234,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 +261,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 +275,14 @@ 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)
/**
* 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)
}
} }

View File

@ -125,7 +125,7 @@ object False : Value {
override val number: Number get() = -1.0 override val number: Number get() = -1.0
override val string: String get() = "false" override val string: String get() = "false"
override fun toString(): String = True.value.toString() override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean = other === False override fun equals(other: Any?): Boolean = other === False
override fun hashCode(): Int = -1 override fun hashCode(): Int = -1

View File

@ -1,20 +1,23 @@
package hep.dataforge.meta.descriptors package hep.dataforge.meta.descriptors
import hep.dataforge.meta.boolean
import hep.dataforge.meta.get
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,7 +28,15 @@ 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)
} }
@Test
fun testDefaultMetaNode(){
val meta = descriptor.buildDefaultMeta()
assertEquals(false, meta["aNode.otherNode.otherValue"].boolean)
}
} }

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
@ -16,7 +16,8 @@ import kotlin.reflect.KClass
@DFBuilder @DFBuilder
class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) { class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { allData() } private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { allData() }
// private val additionalDependencies = HashSet<Dependency>()
// private val additionalDependencies = HashSet<Dependency>()
var descriptor: NodeDescriptor? = null var descriptor: NodeDescriptor? = null
private val dataTransforms: MutableList<DataTransformation> = ArrayList() private val dataTransforms: MutableList<DataTransformation> = ArrayList()
@ -96,7 +97,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
} }
class TaskEnv(val name: Name, val meta: Meta, val context: Context, val data: DataNode<Any>) { class TaskEnv(val name: Name, val meta: Meta, val context: Context, val data: DataNode<Any>) {
operator fun <T : Any> DirectTaskDependency<T>.invoke(): DataNode<T> = if(placement.isEmpty()){ operator fun <T : Any> DirectTaskDependency<T>.invoke(): DataNode<T> = if (placement.isEmpty()) {
data.cast(task.type) data.cast(task.type)
} else { } else {
data[placement].node?.cast(task.type) data[placement].node?.cast(task.type)
@ -113,10 +114,13 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
crossinline block: MapActionBuilder<T, R>.(TaskEnv) -> Unit crossinline block: MapActionBuilder<T, R>.(TaskEnv) -> Unit
) { ) {
action(from, to) { action(from, to) {
val env = this
MapAction( MapAction(
inputType = T::class, inputType = T::class,
outputType = type outputType = type
) { block(this@action) } ) {
block(env)
}
} }
} }
@ -150,10 +154,11 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
crossinline block: ReduceGroupBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176 crossinline block: ReduceGroupBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
) { ) {
action(from, to) { action(from, to) {
val env = this
ReduceAction( ReduceAction(
inputType = T::class, inputType = T::class,
outputType = type outputType = type
) { block(this@action) } ) { block(env) }
} }
} }
@ -189,10 +194,11 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
crossinline block: SplitBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176 crossinline block: SplitBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
) { ) {
action(from, to) { action(from, to) {
val env = this
SplitAction( SplitAction(
inputType = T::class, inputType = T::class,
outputType = type outputType = type
) { block(this@action) } ) { block(env) }
} }
} }
@ -200,7 +206,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 +218,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