Name comparison

This commit is contained in:
Alexander Nozik 2019-06-01 08:14:37 +03:00
parent 59c46344fa
commit f0413464a3
5 changed files with 102 additions and 15 deletions

View File

@ -1,8 +1,29 @@
package hep.dataforge.descriptors package hep.dataforge.descriptors
import hep.dataforge.descriptors.Described.Companion.DESCRIPTOR_NODE
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.node
/** /**
* An object which provides its descriptor * An object which provides its descriptor
*/ */
interface Described { interface Described {
val descriptor: NodeDescriptor val descriptor: NodeDescriptor
companion object {
const val DESCRIPTOR_NODE = "@descriptor"
}
}
/**
* If meta node supplies explicit descriptor, return it, otherwise try to use descriptor node from meta itself
*/
val Meta.descriptor: NodeDescriptor?
get() {
return if (this is Described) {
descriptor
} else {
get(DESCRIPTOR_NODE).node?.let { NodeDescriptor.wrap(it) }
}
} }

View File

@ -126,5 +126,7 @@ class NodeDescriptor(override val config: Config) : Specific {
const val VALUE_KEY = "value" const val VALUE_KEY = "value"
override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config) override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config)
//TODO infer descriptor from spec
} }
} }

View File

@ -1,6 +1,7 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.startsWith
/** /**
* A transformation for meta item or a group of items * A transformation for meta item or a group of items
@ -27,17 +28,18 @@ interface TransformationRule {
} }
/** /**
* A transformation which transforms an element with given [name] to itself. * A transformation which keeps all elements, matching [selector] unchanged.
*/ */
data class SelfTransformationRule(val name: Name) : TransformationRule { data class KeepTransformationRule(val selector: (Name) -> Boolean) : TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean { override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return name == name return selector(name)
} }
override fun selectItems(meta: Meta): Sequence<Name> = sequenceOf(name) override fun selectItems(meta: Meta): Sequence<Name> =
meta.sequence().map { it.first }.filter(selector)
override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) { override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) {
if (name == this.name) target[name] = item if (selector(name)) target[name] = item
} }
} }
@ -46,8 +48,7 @@ data class SelfTransformationRule(val name: Name) : TransformationRule {
*/ */
data class SingleItemTransformationRule( data class SingleItemTransformationRule(
val from: Name, val from: Name,
val to: Name, val transform: MutableMeta<*>.(Name, MetaItem<*>?) -> Unit
val transform: MutableMeta<*>.(MetaItem<*>?) -> Unit
) : TransformationRule { ) : TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean { override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return name == from return name == from
@ -57,14 +58,29 @@ data class SingleItemTransformationRule(
override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) { override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) {
if (name == this.from) { if (name == this.from) {
target.transform(item) target.transform(name, item)
} }
} }
} }
class MetaTransformation { data class RegexpItemTransformationRule(
private val transformations = HashSet<TransformationRule>() val from: Regex,
val transform: MutableMeta<*>.(MatchResult, MetaItem<*>?) -> Unit
) : TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return from.matches(name.toString())
}
override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) {
val match = from.matchEntire(name.toString())
if (match != null) {
target.transform(match, item)
}
}
}
inline class MetaTransformation(val transformations: Collection<TransformationRule>) {
/** /**
* Produce new meta using only those items that match transformation rules * Produce new meta using only those items that match transformation rules
@ -89,7 +105,36 @@ class MetaTransformation {
} }
} }
/**
* Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule.
*/
fun <M : MutableMeta<M>> bind(source: MutableMeta<*>, target: M) {
source.onChange(target) { name, oldItem, newItem ->
transformations.forEach { t ->
if (t.matches(name, newItem)) {
t.transformItem(name, newItem, target)
}
}
}
}
companion object { companion object {
} }
} }
class MetaTransformationBuilder {
val transformations = HashSet<TransformationRule>()
fun keep(selector: (Name) -> Boolean) {
transformations.add(KeepTransformationRule(selector))
}
fun keep(name: Name) {
keep{it == name}
}
fun keepNode(name: Name){
keep{it.startsWith(name)}
}
}

View File

@ -123,3 +123,13 @@ fun Name.withIndex(index: String): Name {
operator fun <T> Map<Name, T>.get(name: String) = get(name.toName()) operator fun <T> Map<Name, T>.get(name: String) = get(name.toName())
operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value) operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value)
/* Name comparison operations */
fun Name.startsWith(token: NameToken): Boolean = first() == token
fun Name.endsWith(token: NameToken): Boolean = last() == token
fun Name.startsWith(name: Name): Boolean = tokens.subList(0, name.length) == name.tokens
fun Name.endsWith(name: Name): Boolean = tokens.subList(length - name.length, length) == name.tokens

View File

@ -1,7 +1,6 @@
package hep.dataforge.names package hep.dataforge.names
import kotlin.test.Test import kotlin.test.*
import kotlin.test.assertEquals
class NameTest { class NameTest {
@Test @Test
@ -16,4 +15,14 @@ class NameTest {
val name2 = "token1".toName() + "token2[2].token3" val name2 = "token1".toName() + "token2[2].token3"
assertEquals(name1, name2) assertEquals(name1, name2)
} }
@Test
fun comparisonTest(){
val name1 = "token1.token2.token3".toName()
val name2 = "token1.token2".toName()
val name3 = "token3".toName()
assertTrue { name1.startsWith(name2) }
assertTrue { name1.endsWith(name3) }
assertFalse { name1.startsWith(name3) }
}
} }