Refactor inner workings of descriptors
This commit is contained in:
parent
e835d81183
commit
417c292507
@ -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.5")
|
val dataforgeVersion by extra("0.1.6-dev")
|
||||||
|
|
||||||
val bintrayRepo by extra("dataforge")
|
val bintrayRepo by extra("dataforge")
|
||||||
val githubProject by extra("dataforge-core")
|
val githubProject by extra("dataforge-core")
|
||||||
|
@ -2,15 +2,13 @@ package hep.dataforge.meta.descriptors
|
|||||||
|
|
||||||
import hep.dataforge.meta.*
|
import hep.dataforge.meta.*
|
||||||
import hep.dataforge.meta.scheme.*
|
import hep.dataforge.meta.scheme.*
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.*
|
||||||
import hep.dataforge.names.NameToken
|
|
||||||
import hep.dataforge.names.asName
|
|
||||||
import hep.dataforge.names.isEmpty
|
|
||||||
import hep.dataforge.values.False
|
import hep.dataforge.values.False
|
||||||
import hep.dataforge.values.True
|
import hep.dataforge.values.True
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
|
|
||||||
|
@DFBuilder
|
||||||
sealed class ItemDescriptor : Scheme() {
|
sealed class ItemDescriptor : Scheme() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,8 +66,7 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class NodeDescriptor : ItemDescriptor() {
|
class NodeDescriptor private constructor() : ItemDescriptor() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the node is required
|
* True if the node is required
|
||||||
*
|
*
|
||||||
@ -84,86 +81,98 @@ class NodeDescriptor : ItemDescriptor() {
|
|||||||
*/
|
*/
|
||||||
var default by node()
|
var default by node()
|
||||||
|
|
||||||
|
val items: Map<String, ItemDescriptor>
|
||||||
|
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
||||||
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
|
if (node[IS_NODE_KEY].boolean == true) {
|
||||||
|
NodeDescriptor.wrap(node)
|
||||||
|
} else {
|
||||||
|
ValueDescriptor.wrap(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map of children node descriptors
|
* The map of children node descriptors
|
||||||
*/
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
val nodes: Map<String, NodeDescriptor>
|
val nodes: Map<String, NodeDescriptor>
|
||||||
get() = config.getIndexed(NODE_KEY.asName()).entries.associate { (name, node) ->
|
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||||
name to wrap(node.node ?: error("Node descriptor must be a node"))
|
it.value.node[IS_NODE_KEY].boolean == true
|
||||||
|
}.associate { (name, item) ->
|
||||||
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
|
name to NodeDescriptor.wrap(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define a child item descriptor for this node
|
* The list of value descriptors
|
||||||
*/
|
*/
|
||||||
fun defineItem(name: String, descriptor: ItemDescriptor) {
|
val values: Map<String, ValueDescriptor>
|
||||||
if (items.keys.contains(name)) error("The key $name already exists in descriptor")
|
get() = config.getIndexed(ITEM_KEY).entries.filter {
|
||||||
val token = when (descriptor) {
|
it.value.node[IS_NODE_KEY].boolean != true
|
||||||
is NodeDescriptor -> NameToken(NODE_KEY, name)
|
}.associate { (name, item) ->
|
||||||
is ValueDescriptor -> NameToken(VALUE_KEY, name)
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
|
name to ValueDescriptor.wrap(node)
|
||||||
}
|
}
|
||||||
config[token] = descriptor.config
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun defineNode(name: String, block: NodeDescriptor.() -> Unit) {
|
|
||||||
val token = NameToken(NODE_KEY, name)
|
|
||||||
if (config[token] == null) {
|
|
||||||
config[token] = NodeDescriptor(block)
|
|
||||||
} else {
|
|
||||||
NodeDescriptor.update(config[token].node ?: error("Node expected"), block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildNode(name: Name): NodeDescriptor {
|
private fun buildNode(name: Name): NodeDescriptor {
|
||||||
return when (name.length) {
|
return when (name.length) {
|
||||||
0 -> this
|
0 -> this
|
||||||
1 -> {
|
1 -> {
|
||||||
val token = NameToken(NODE_KEY, name.toString())
|
val token = NameToken(ITEM_KEY.toString(), name.toString())
|
||||||
val config: Config = config[token].node ?: Config().also { config[token] = it }
|
val config: Config = config[token].node ?: Config().also {
|
||||||
|
it[IS_NODE_KEY] = true
|
||||||
|
config[token] = it
|
||||||
|
}
|
||||||
wrap(config)
|
wrap(config)
|
||||||
}
|
}
|
||||||
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
|
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) {
|
/**
|
||||||
buildNode(name).apply(block)
|
* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun defineItem(name: Name, descriptor: ItemDescriptor) {
|
||||||
* The list of value descriptors
|
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
|
||||||
*/
|
}
|
||||||
val values: Map<String, ValueDescriptor>
|
|
||||||
get() = config.getIndexed(VALUE_KEY.asName()).entries.associate { (name, node) ->
|
|
||||||
name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node"))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fun defineItem(name: String, descriptor: ItemDescriptor) {
|
||||||
|
defineItem(name.toName(), descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) {
|
||||||
* Add a value descriptor using block for
|
defineItem(name, NodeDescriptor(block))
|
||||||
*/
|
}
|
||||||
fun defineValue(name: String, block: ValueDescriptor.() -> Unit) {
|
|
||||||
defineItem(name, ValueDescriptor(block))
|
fun defineNode(name: String, block: NodeDescriptor.() -> Unit) {
|
||||||
|
defineNode(name.toName(), block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineValue(name: Name, block: ValueDescriptor.() -> Unit) {
|
fun defineValue(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" }
|
||||||
buildNode(name.cutLast()).defineValue(name.last().toString(), block)
|
defineItem(name, ValueDescriptor(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
val items: Map<String, ItemDescriptor> get() = nodes + values
|
fun defineValue(name: String, block: ValueDescriptor.() -> Unit) {
|
||||||
|
defineValue(name.toName(), block)
|
||||||
|
}
|
||||||
//override val descriptor: NodeDescriptor = empty("descriptor")
|
|
||||||
|
|
||||||
companion object : SchemeSpec<NodeDescriptor>(::NodeDescriptor) {
|
companion object : SchemeSpec<NodeDescriptor>(::NodeDescriptor) {
|
||||||
|
|
||||||
// const val ITEM_KEY = "item"
|
val ITEM_KEY = "item".asName()
|
||||||
const val NODE_KEY = "node"
|
val IS_NODE_KEY = "@isNode".asName()
|
||||||
const val VALUE_KEY = "value"
|
|
||||||
|
|
||||||
//override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config)
|
override fun empty(): NodeDescriptor {
|
||||||
|
return super.empty().apply {
|
||||||
|
config[IS_NODE_KEY] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TODO infer descriptor from spec
|
//TODO infer descriptor from spec
|
||||||
}
|
}
|
||||||
@ -187,9 +196,9 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
|||||||
*
|
*
|
||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
|
@DFBuilder
|
||||||
class ValueDescriptor : ItemDescriptor() {
|
class ValueDescriptor : ItemDescriptor() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the value is required
|
* True if the value is required
|
||||||
*
|
*
|
||||||
@ -255,68 +264,5 @@ class ValueDescriptor : ItemDescriptor() {
|
|||||||
this.allowedValues = v.map { Value.of(it) }
|
this.allowedValues = v.map { Value.of(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : SchemeSpec<ValueDescriptor>(::ValueDescriptor) {
|
companion object : SchemeSpec<ValueDescriptor>(::ValueDescriptor)
|
||||||
// inline fun <reified E : Enum<E>> enum(name: String) = ValueDescriptor {
|
|
||||||
// type(ValueType.STRING)
|
|
||||||
// this.allowedValues = enumValues<E>().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))
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,12 +6,11 @@ import hep.dataforge.names.toName
|
|||||||
/**
|
/**
|
||||||
* Get all items matching given name.
|
* Get all items matching given name.
|
||||||
*/
|
*/
|
||||||
@DFExperimental
|
|
||||||
fun Meta.getIndexed(name: Name): Map<String, MetaItem<*>> {
|
fun Meta.getIndexed(name: Name): Map<String, MetaItem<*>> {
|
||||||
val root = when (name.length) {
|
val root = when (name.length) {
|
||||||
0 -> error("Can't use empty name for that")
|
0 -> error("Can't use empty name for 'getIndexed'")
|
||||||
1 -> this
|
1 -> this
|
||||||
else -> (this[name.cutLast()] as? MetaItem.NodeItem<*>)?.node
|
else -> this[name.cutLast()].node
|
||||||
}
|
}
|
||||||
|
|
||||||
val (body, index) = name.last()!!
|
val (body, index) = name.last()!!
|
||||||
@ -23,16 +22,13 @@ fun Meta.getIndexed(name: Name): Map<String, MetaItem<*>> {
|
|||||||
?: emptyMap()
|
?: emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
fun Meta.getIndexed(name: String): Map<String, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
|
fun Meta.getIndexed(name: String): Map<String, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all items matching given name.
|
* Get all items matching given name.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
@DFExperimental
|
|
||||||
fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> =
|
fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> =
|
||||||
(this as Meta).getIndexed(name) as Map<String, MetaItem<M>>
|
(this as Meta).getIndexed(name) as Map<String, MetaItem<M>>
|
||||||
|
|
||||||
@DFExperimental
|
|
||||||
fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> = getIndexed(name.toName())
|
fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> = getIndexed(name.toName())
|
@ -168,9 +168,10 @@ fun Configurable.float(default: Float, key: Name? = null): ReadWriteProperty<Any
|
|||||||
/**
|
/**
|
||||||
* Enum delegate
|
* Enum delegate
|
||||||
*/
|
*/
|
||||||
fun <E : Enum<E>> Configurable.enum(
|
inline fun <reified E : Enum<E>> Configurable.enum(
|
||||||
default: E, key: Name? = null, resolve: MetaItem<*>.() -> E?
|
default: E, key: Name? = null
|
||||||
): ReadWriteProperty<Any?, E> = item(default, key).transform { it?.resolve() ?: default }
|
): ReadWriteProperty<Any?, E> =
|
||||||
|
item(default, key).transform { item -> item?.string?.let { enumValueOf<E>(it) } ?: default }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extra delegates for special cases
|
* Extra delegates for special cases
|
||||||
@ -225,7 +226,7 @@ fun <T : Configurable> Configurable.spec(
|
|||||||
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
val name = key ?: property.name.asName()
|
val name = key ?: property.name.asName()
|
||||||
return config[name].node?.let { spec.wrap(it) }?:default
|
return config[name].node?.let { spec.wrap(it) } ?: default
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
|
@ -60,8 +60,10 @@ inline operator fun <T : Scheme> T.invoke(block: T.() -> Unit) = apply(block)
|
|||||||
* A specification for simplified generation of wrappers
|
* A specification for simplified generation of wrappers
|
||||||
*/
|
*/
|
||||||
open class SchemeSpec<T : Scheme>(val builder: () -> T) : Specification<T> {
|
open class SchemeSpec<T : Scheme>(val builder: () -> T) : Specification<T> {
|
||||||
|
override fun empty(): T = builder()
|
||||||
|
|
||||||
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T {
|
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T {
|
||||||
return builder().apply {
|
return empty().apply {
|
||||||
this.config = config
|
this.config = config
|
||||||
this.defaultProvider = defaultProvider
|
this.defaultProvider = defaultProvider
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ interface Specification<T : Configurable> {
|
|||||||
return wrap(config).apply(action)
|
return wrap(config).apply(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun invoke(action: T.() -> Unit) = update(Config(), action)
|
operator fun invoke(action: T.() -> Unit) = empty().apply(action)
|
||||||
|
|
||||||
fun empty() = wrap()
|
fun empty() = wrap()
|
||||||
|
|
||||||
@ -34,9 +34,7 @@ interface Specification<T : Configurable> {
|
|||||||
/**
|
/**
|
||||||
* Wrap a configuration using static meta as default
|
* Wrap a configuration using static meta as default
|
||||||
*/
|
*/
|
||||||
fun wrap(default: Meta): T = wrap(
|
fun wrap(default: Meta): T = wrap(Config()) { default[it] }
|
||||||
Config()
|
|
||||||
) { default[it] }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,7 +59,8 @@ class Name(val tokens: List<NameToken>) {
|
|||||||
|
|
||||||
val EMPTY = Name(emptyList())
|
val EMPTY = Name(emptyList())
|
||||||
|
|
||||||
override val descriptor: SerialDescriptor = PrimitiveDescriptor("hep.dataforge.names.Name", PrimitiveKind.STRING)
|
override val descriptor: SerialDescriptor =
|
||||||
|
PrimitiveDescriptor("hep.dataforge.names.Name", PrimitiveKind.STRING)
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Name {
|
override fun deserialize(decoder: Decoder): Name {
|
||||||
return decoder.decodeString().toName()
|
return decoder.decodeString().toName()
|
||||||
@ -99,7 +100,8 @@ data class NameToken(val body: String, val index: String = "") {
|
|||||||
|
|
||||||
@Serializer(NameToken::class)
|
@Serializer(NameToken::class)
|
||||||
companion object : KSerializer<NameToken> {
|
companion object : KSerializer<NameToken> {
|
||||||
override val descriptor: SerialDescriptor = PrimitiveDescriptor("hep.dataforge.names.NameToken", PrimitiveKind.STRING)
|
override val descriptor: SerialDescriptor =
|
||||||
|
PrimitiveDescriptor("hep.dataforge.names.NameToken", PrimitiveKind.STRING)
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): NameToken {
|
override fun deserialize(decoder: Decoder): NameToken {
|
||||||
return decoder.decodeString().toName().first()!!
|
return decoder.decodeString().toName().first()!!
|
||||||
@ -188,8 +190,12 @@ fun Name.isEmpty(): Boolean = this.length == 0
|
|||||||
* Set or replace last token index
|
* Set or replace last token index
|
||||||
*/
|
*/
|
||||||
fun Name.withIndex(index: String): Name {
|
fun Name.withIndex(index: String): Name {
|
||||||
val tokens = ArrayList(tokens)
|
|
||||||
val last = NameToken(tokens.last().body, index)
|
val last = NameToken(tokens.last().body, index)
|
||||||
|
if (length == 0) error("Can't add index to empty name")
|
||||||
|
if (length == 1) {
|
||||||
|
return last.asName()
|
||||||
|
}
|
||||||
|
val tokens = ArrayList(tokens)
|
||||||
tokens.removeAt(tokens.size - 1)
|
tokens.removeAt(tokens.size - 1)
|
||||||
tokens.add(last)
|
tokens.add(last)
|
||||||
return Name(tokens)
|
return Name(tokens)
|
||||||
|
@ -20,7 +20,7 @@ class MetaDelegateTest {
|
|||||||
class TestScheme : Scheme() {
|
class TestScheme : Scheme() {
|
||||||
var myValue by string()
|
var myValue by string()
|
||||||
var safeValue by double(2.2)
|
var safeValue by double(2.2)
|
||||||
var enumValue by enum(TestEnum.YES) { enum<TestEnum>() }
|
var enumValue by enum(TestEnum.YES)
|
||||||
var inner by spec(InnerSpec)
|
var inner by spec(InnerSpec)
|
||||||
|
|
||||||
companion object : SchemeSpec<TestScheme>(::TestScheme)
|
companion object : SchemeSpec<TestScheme>(::TestScheme)
|
||||||
|
@ -26,6 +26,6 @@ class DescriptorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun testAllowedValues() {
|
fun testAllowedValues() {
|
||||||
val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues
|
val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues
|
||||||
assertEquals(allowed, emptyList())
|
assertEquals(emptyList(), allowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.tables
|
package hep.dataforge.tables
|
||||||
|
|
||||||
import hep.dataforge.meta.enum
|
|
||||||
import hep.dataforge.meta.scheme.Scheme
|
import hep.dataforge.meta.scheme.Scheme
|
||||||
import hep.dataforge.meta.scheme.SchemeSpec
|
import hep.dataforge.meta.scheme.SchemeSpec
|
||||||
import hep.dataforge.meta.scheme.enum
|
import hep.dataforge.meta.scheme.enum
|
||||||
@ -14,5 +13,5 @@ open class ColumnScheme : Scheme() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ValueColumnScheme : ColumnScheme() {
|
class ValueColumnScheme : ColumnScheme() {
|
||||||
var valueType by enum(ValueType.STRING){enum<ValueType>()}
|
var valueType by enum(ValueType.STRING)
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user