Explicit API mode

This commit is contained in:
Alexander Nozik 2020-09-09 10:22:15 +03:00
parent 606faa5e1b
commit d170f5d60c
14 changed files with 126 additions and 131 deletions

View File

@ -2,6 +2,6 @@ package hep.dataforge.context
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
interface Factory<out T : Any> { public interface Factory<out T : Any> {
operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T public operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T
} }

View File

@ -24,16 +24,14 @@ import hep.dataforge.names.isEmpty
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
interface Named { public interface Named {
/** /**
* The name of this object instance * The name of this object instance
*
* @return
*/ */
val name: Name public val name: Name
companion object { public companion object {
/** /**
* Get the name of given object. If object is Named its name is used, * Get the name of given object. If object is Named its name is used,
@ -42,7 +40,7 @@ interface Named {
* @param obj * @param obj
* @return * @return
*/ */
fun nameOf(obj: Any): Name { public fun nameOf(obj: Any): Name {
return if (obj is Named) { return if (obj is Named) {
obj.name obj.name
} else { } else {
@ -56,5 +54,4 @@ interface Named {
* Check if this object has an empty name and therefore is anonymous. * Check if this object has an empty name and therefore is anonymous.
* @return * @return
*/ */
val Named.isAnonymous: Boolean public val Named.isAnonymous: Boolean get() = this.name.isEmpty()
get() = this.name.isEmpty()

View File

@ -22,21 +22,17 @@ import hep.dataforge.provider.Provider
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
interface Plugin : Named, ContextAware, Provider, MetaRepr { public interface Plugin : Named, ContextAware, Provider, MetaRepr {
/** /**
* Get tag for this plugin * Get tag for this plugin
*
* @return
*/ */
val tag: PluginTag public val tag: PluginTag
val meta: Meta public val meta: Meta
/** /**
* The name of this plugin ignoring version and group * The name of this plugin ignoring version and group
*
* @return
*/ */
override val name: Name get() = tag.name.toName() override val name: Name get() = tag.name.toName()
@ -44,25 +40,21 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
* Plugin dependencies which are required to attach this plugin. Plugin * Plugin dependencies which are required to attach this plugin. Plugin
* dependencies must be initialized and enabled in the Context before this * dependencies must be initialized and enabled in the Context before this
* plugin is enabled. * plugin is enabled.
*
* @return
*/ */
fun dependsOn(): Collection<PluginFactory<*>> public fun dependsOn(): Collection<PluginFactory<*>>
/** /**
* Start this plugin and attach registration info to the context. This method * Start this plugin and attach registration info to the context. This method
* should be called only via PluginManager to avoid dependency issues. * should be called only via PluginManager to avoid dependency issues.
*
* @param context
*/ */
fun attach(context: Context) public fun attach(context: Context)
/** /**
* Stop this plugin and remove registration info from context and other * Stop this plugin and remove registration info from context and other
* plugins. This method should be called only via PluginManager to avoid * plugins. This method should be called only via PluginManager to avoid
* dependency issues. * dependency issues.
*/ */
fun detach() public fun detach()
override fun toMeta(): Meta = Meta { override fun toMeta(): Meta = Meta {
"context" put context.name.toString() "context" put context.name.toString()
@ -71,9 +63,9 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
"meta" put meta "meta" put meta
} }
companion object { public companion object {
const val PLUGIN_TARGET = "plugin" public const val PLUGIN_TARGET = "plugin"
} }
} }

View File

@ -5,12 +5,12 @@ import hep.dataforge.meta.MetaBuilder
import kotlin.reflect.KClass import kotlin.reflect.KClass
interface PluginFactory<T : Plugin> : Factory<T> { public interface PluginFactory<T : Plugin> : Factory<T> {
val tag: PluginTag public val tag: PluginTag
val type: KClass<out T> public val type: KClass<out T>
companion object{ public companion object{
const val TYPE = "pluginFactory" public const val TYPE: String = "pluginFactory"
} }
} }
@ -21,7 +21,7 @@ interface PluginFactory<T : Plugin> : Factory<T> {
* @property context A context for this plugin manager * @property context A context for this plugin manager
* @author Alexander Nozik * @author Alexander Nozik
*/ */
class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> { public class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> {
/** /**
* A set of loaded plugins * A set of loaded plugins
@ -34,7 +34,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
private val parent: PluginManager? = context.parent?.plugins private val parent: PluginManager? = context.parent?.plugins
fun sequence(recursive: Boolean): Sequence<Plugin> { public fun sequence(recursive: Boolean): Sequence<Plugin> {
return if (recursive && parent != null) { return if (recursive && parent != null) {
plugins.asSequence() + parent.sequence(true) plugins.asSequence() + parent.sequence(true)
} else { } else {
@ -47,7 +47,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @param recursive search for parent [PluginManager] plugins * @param recursive search for parent [PluginManager] plugins
* @param predicate condition for the plugin * @param predicate condition for the plugin
*/ */
fun find(recursive: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = sequence(recursive).find(predicate) public fun find(recursive: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = sequence(recursive).find(predicate)
/** /**
@ -56,7 +56,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @param tag * @param tag
* @return * @return
*/ */
operator fun get(tag: PluginTag, recursive: Boolean = true): Plugin? = find(recursive) { tag.matches(it.tag) } public operator fun get(tag: PluginTag, recursive: Boolean = true): Plugin? = find(recursive) { tag.matches(it.tag) }
/** /**
@ -71,13 +71,13 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @return * @return
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T : Any> get(type: KClass<out T>, tag: PluginTag? = null, recursive: Boolean = true): T? = public operator fun <T : Any> get(type: KClass<out T>, tag: PluginTag? = null, recursive: Boolean = true): T? =
find(recursive) { type.isInstance(it) && (tag == null || tag.matches(it.tag)) } as T? find(recursive) { type.isInstance(it) && (tag == null || tag.matches(it.tag)) } as T?
inline operator fun <reified T : Any> get(tag: PluginTag? = null, recursive: Boolean = true): T? = public inline operator fun <reified T : Any> get(tag: PluginTag? = null, recursive: Boolean = true): T? =
get(T::class, tag, recursive) get(T::class, tag, recursive)
inline operator fun <reified T : Plugin> get(factory: PluginFactory<T>, recursive: Boolean = true): T? = public inline operator fun <reified T : Plugin> get(factory: PluginFactory<T>, recursive: Boolean = true): T? =
get(factory.type, factory.tag, recursive) get(factory.type, factory.tag, recursive)
/** /**
@ -87,7 +87,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @param plugin * @param plugin
* @return * @return
*/ */
fun <T : Plugin> load(plugin: T): T { public fun <T : Plugin> load(plugin: T): T {
if (context.isActive) error("Can't load plugin into active context") if (context.isActive) error("Can't load plugin into active context")
if (get(plugin::class, plugin.tag, recursive = false) != null) { if (get(plugin::class, plugin.tag, recursive = false) != null) {
@ -107,16 +107,16 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
/** /**
* Load a plugin using its factory * Load a plugin using its factory
*/ */
fun <T : Plugin> load(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY): T = public fun <T : Plugin> load(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY): T =
load(factory(meta, context)) load(factory(meta, context))
fun <T : Plugin> load(factory: PluginFactory<T>, metaBuilder: MetaBuilder.() -> Unit): T = public fun <T : Plugin> load(factory: PluginFactory<T>, metaBuilder: MetaBuilder.() -> Unit): T =
load(factory, Meta(metaBuilder)) load(factory, Meta(metaBuilder))
/** /**
* Remove a plugin from [PluginManager] * Remove a plugin from [PluginManager]
*/ */
fun remove(plugin: Plugin) { public fun remove(plugin: Plugin) {
if (context.isActive) error("Can't remove plugin from active context") if (context.isActive) error("Can't remove plugin from active context")
if (plugins.contains(plugin)) { if (plugins.contains(plugin)) {
@ -130,7 +130,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* Get an existing plugin with given meta or load new one using provided factory * Get an existing plugin with given meta or load new one using provided factory
* *
*/ */
fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T { public fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T {
val loaded = get(factory.type, factory.tag, recursive) val loaded = get(factory.type, factory.tag, recursive)
return when { return when {
loaded == null -> load(factory(meta, context)) loaded == null -> load(factory(meta, context))
@ -139,7 +139,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
} }
} }
fun <T : Plugin> fetch( public fun <T : Plugin> fetch(
factory: PluginFactory<T>, factory: PluginFactory<T>,
recursive: Boolean = true, recursive: Boolean = true,
metaBuilder: MetaBuilder.() -> Unit metaBuilder: MetaBuilder.() -> Unit

View File

@ -26,25 +26,25 @@ import hep.dataforge.names.toName
* @author Alexander Nozik * @author Alexander Nozik
* @version $Id: $Id * @version $Id: $Id
*/ */
inline class Path(val tokens: List<PathToken>) : Iterable<PathToken> { public inline class Path(public val tokens: List<PathToken>) : Iterable<PathToken> {
val head: PathToken? get() = tokens.firstOrNull() public val head: PathToken? get() = tokens.firstOrNull()
val length: Int get() = tokens.size public val length: Int get() = tokens.size
/** /**
* Returns non-empty optional containing the chain without first segment in case of chain path. * Returns non-empty optional containing the chain without first segment in case of chain path.
* *
* @return * @return
*/ */
val tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1)) public val tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1))
override fun iterator(): Iterator<PathToken> = tokens.iterator() override fun iterator(): Iterator<PathToken> = tokens.iterator()
companion object { public companion object {
const val PATH_SEGMENT_SEPARATOR = "/" public const val PATH_SEGMENT_SEPARATOR = "/"
fun parse(path: String): Path { public fun parse(path: String): Path {
val head = path.substringBefore(PATH_SEGMENT_SEPARATOR) val head = path.substringBefore(PATH_SEGMENT_SEPARATOR)
val tail = path.substringAfter(PATH_SEGMENT_SEPARATOR) val tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
return PathToken.parse(head).toPath() + parse(tail) return PathToken.parse(head).toPath() + parse(tail)
@ -52,18 +52,18 @@ inline class Path(val tokens: List<PathToken>) : Iterable<PathToken> {
} }
} }
operator fun Path.plus(path: Path) = Path(this.tokens + path.tokens) public operator fun Path.plus(path: Path): Path = Path(this.tokens + path.tokens)
data class PathToken(val name: Name, val target: String? = null) { public data class PathToken(val name: Name, val target: String? = null) {
override fun toString(): String = if (target == null) { override fun toString(): String = if (target == null) {
name.toString() name.toString()
} else { } else {
"$target$TARGET_SEPARATOR$name" "$target$TARGET_SEPARATOR$name"
} }
companion object { public companion object {
const val TARGET_SEPARATOR = "::" public const val TARGET_SEPARATOR: String = "::"
fun parse(token: String): PathToken { public fun parse(token: String): PathToken {
val target = token.substringBefore(TARGET_SEPARATOR, "") val target = token.substringBefore(TARGET_SEPARATOR, "")
val name = token.substringAfter(TARGET_SEPARATOR).toName() val name = token.substringAfter(TARGET_SEPARATOR).toName()
if (target.contains("[")) TODO("target separators in queries are not supported") if (target.contains("[")) TODO("target separators in queries are not supported")
@ -72,4 +72,4 @@ data class PathToken(val name: Name, val target: String? = null) {
} }
} }
fun PathToken.toPath() = Path(listOf(this)) public fun PathToken.toPath(): Path = Path(listOf(this))

View File

@ -22,29 +22,25 @@ import hep.dataforge.names.Name
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
interface Provider { public interface Provider {
/** /**
* Default target for this provider * Default target for this provider
*
* @return
*/ */
val defaultTarget: String get() = "" public val defaultTarget: String get() = ""
/** /**
* Default target for next chain segment * Default target for next chain segment
*
* @return
*/ */
val defaultChainTarget: String get() = "" public val defaultChainTarget: String get() = ""
/** /**
* A map of direct children for specific target * A map of direct children for specific target
*/ */
fun provideTop(target: String): Map<Name, Any> = emptyMap() public fun provideTop(target: String): Map<Name, Any> = emptyMap()
} }
fun Provider.provide(path: Path, targetOverride: String? = null): Any? { public fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
if (path.length == 0) throw IllegalArgumentException("Can't provide by empty path") if (path.length == 0) throw IllegalArgumentException("Can't provide by empty path")
val first = path.first() val first = path.first()
val target = targetOverride ?: first.target ?: defaultTarget val target = targetOverride ?: first.target ?: defaultTarget
@ -63,7 +59,7 @@ fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
/** /**
* Type checked provide * Type checked provide
*/ */
inline fun <reified T : Any> Provider.provide(path: String, targetOverride: String? = null): T? { public inline fun <reified T : Any> Provider.provide(path: String, targetOverride: String? = null): T? {
return provide(Path.parse(path), targetOverride) as? T return provide(Path.parse(path), targetOverride) as? T
} }
// //
@ -77,7 +73,7 @@ inline fun <reified T : Any> Provider.provide(path: String, targetOverride: Stri
/** /**
* Typed top level content * Typed top level content
*/ */
inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> { public inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> {
return provideTop(target).mapValues { return provideTop(target).mapValues {
it.value as? T ?: error("The type of element $it is ${it::class} but ${T::class} is expected") it.value as? T ?: error("The type of element $it is ${it::class} but ${T::class} is expected")
} }

View File

@ -7,4 +7,4 @@ package hep.dataforge.provider
*/ */
@MustBeDocumented @MustBeDocumented
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
annotation class Type(val id: String) public annotation class Type(val id: String)

View File

@ -5,23 +5,23 @@ import hep.dataforge.meta.Meta
/** /**
* A simple data transformation on a data node * A simple data transformation on a data node
*/ */
interface Action<in T : Any, out R : Any> { public interface Action<in T : Any, out R : Any> {
/** /**
* Transform the data in the node, producing a new node. By default it is assumed that all calculations are lazy * Transform the data in the node, producing a new node. By default it is assumed that all calculations are lazy
* so not actual computation is started at this moment * so not actual computation is started at this moment
*/ */
operator fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> public operator fun invoke(node: DataNode<T>, meta: Meta): DataNode<R>
/** /**
* Terminal action is the one that could not be invoked lazily and requires some kind of blocking computation to invoke * Terminal action is the one that could not be invoked lazily and requires some kind of blocking computation to invoke
*/ */
val isTerminal: Boolean get() = false public val isTerminal: Boolean get() = false
} }
/** /**
* Action composition. The result is terminal if one of its parts is terminal * Action composition. The result is terminal if one of its parts is terminal
*/ */
infix fun <T : Any, I : Any, R : Any> Action<T, I>.then(action: Action<I, R>): Action<T, R> { public infix fun <T : Any, I : Any, R : Any> Action<T, I>.then(action: Action<I, R>): Action<T, R> {
// TODO introduce composite action and add optimize by adding action to the list // TODO introduce composite action and add optimize by adding action to the list
return object : Action<T, R> { return object : Action<T, R> {
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> { override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {

View File

@ -1,48 +1,58 @@
package hep.dataforge.data package hep.dataforge.data
import hep.dataforge.meta.DFExperimental
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
/** /**
* A monitor of goal state that could be accessed only form inside the goal * A monitor of goal state that could be accessed only form inside the goal
*/ */
class CoroutineMonitor : CoroutineContext.Element { @DFExperimental
public class CoroutineMonitor : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> get() = CoroutineMonitor override val key: CoroutineContext.Key<*> get() = CoroutineMonitor
var totalWork: Double = 1.0 public var totalWork: Double = 1.0
var workDone: Double = 0.0 public var workDone: Double = 0.0
var status: String = "" public var status: String = ""
/** /**
* Mark the goal as started * Mark the goal as started
*/ */
fun start() { public fun start() {
} }
/** /**
* Mark the goal as completed * Mark the goal as completed
*/ */
fun finish() { public fun finish() {
workDone = totalWork workDone = totalWork
} }
companion object : CoroutineContext.Key<CoroutineMonitor> public companion object : CoroutineContext.Key<CoroutineMonitor>
} }
class Dependencies(val values: Collection<Job>) : CoroutineContext.Element { public class Dependencies(public val values: Collection<Job>) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> get() = Dependencies override val key: CoroutineContext.Key<*> get() = Dependencies
companion object : CoroutineContext.Key<Dependencies> public companion object : CoroutineContext.Key<Dependencies>
} }
val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor] @DFExperimental
val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor public val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor]
@DFExperimental
public val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor
val Job.dependencies: Collection<Job> get() = this[Dependencies]?.values ?: emptyList() public val Job.dependencies: Collection<Job> get() = this[Dependencies]?.values ?: emptyList()
val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0) @DFExperimental
val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0) public val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0)
val Job.status: String get() = monitor?.status ?: "" @DFExperimental
val Job.progress: Double get() = workDone / totalWork public val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0)
@DFExperimental
public val Job.status: String get() = monitor?.status ?: ""
@DFExperimental
public val Job.progress: Double get() = workDone / totalWork

View File

@ -11,7 +11,7 @@ import kotlin.reflect.KClass
/** /**
* A data element characterized by its meta * A data element characterized by its meta
*/ */
interface Data<out T : Any> : Goal<T>, MetaRepr{ public interface Data<out T : Any> : Goal<T>, MetaRepr{
/** /**
* Type marker for the data. The type is known before the calculation takes place so it could be checked. * Type marker for the data. The type is known before the calculation takes place so it could be checked.
*/ */

View File

@ -6,18 +6,18 @@ import hep.dataforge.values.*
/** /**
* A converter of generic object to and from [MetaItem] * A converter of generic object to and from [MetaItem]
*/ */
interface MetaConverter<T : Any> { public interface MetaConverter<T : Any> {
fun itemToObject(item: MetaItem<*>): T public fun itemToObject(item: MetaItem<*>): T
fun objectToMetaItem(obj: T): MetaItem<*> public fun objectToMetaItem(obj: T): MetaItem<*>
companion object { public companion object {
val item = object : MetaConverter<MetaItem<*>> { public val item: MetaConverter<MetaItem<*>> = object : MetaConverter<MetaItem<*>> {
override fun itemToObject(item: MetaItem<*>): MetaItem<*> = item override fun itemToObject(item: MetaItem<*>): MetaItem<*> = item
override fun objectToMetaItem(obj: MetaItem<*>): MetaItem<*> = obj override fun objectToMetaItem(obj: MetaItem<*>): MetaItem<*> = obj
} }
val meta = object : MetaConverter<Meta> { public val meta: MetaConverter<Meta> = object : MetaConverter<Meta> {
override fun itemToObject(item: MetaItem<*>): Meta = when (item) { override fun itemToObject(item: MetaItem<*>): Meta = when (item) {
is MetaItem.NodeItem -> item.node is MetaItem.NodeItem -> item.node
is MetaItem.ValueItem -> item.value.toMeta() is MetaItem.ValueItem -> item.value.toMeta()
@ -26,7 +26,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Meta): MetaItem<*> = MetaItem.NodeItem(obj) override fun objectToMetaItem(obj: Meta): MetaItem<*> = MetaItem.NodeItem(obj)
} }
val value = object : MetaConverter<Value> { public val value: MetaConverter<Value> = object : MetaConverter<Value> {
override fun itemToObject(item: MetaItem<*>): Value = when (item) { override fun itemToObject(item: MetaItem<*>): Value = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -35,7 +35,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Value): MetaItem<*> = MetaItem.ValueItem(obj) override fun objectToMetaItem(obj: Value): MetaItem<*> = MetaItem.ValueItem(obj)
} }
val string = object : MetaConverter<String> { public val string: MetaConverter<String> = object : MetaConverter<String> {
override fun itemToObject(item: MetaItem<*>): String = when (item) { override fun itemToObject(item: MetaItem<*>): String = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -44,7 +44,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: String): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: String): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val boolean = object : MetaConverter<Boolean> { public val boolean: MetaConverter<Boolean> = object : MetaConverter<Boolean> {
override fun itemToObject(item: MetaItem<*>): Boolean = when (item) { override fun itemToObject(item: MetaItem<*>): Boolean = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -53,7 +53,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Boolean): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Boolean): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val number = object : MetaConverter<Number> { public val number: MetaConverter<Number> = object : MetaConverter<Number> {
override fun itemToObject(item: MetaItem<*>): Number = when (item) { override fun itemToObject(item: MetaItem<*>): Number = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -62,7 +62,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Number): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Number): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val double = object : MetaConverter<Double> { public val double: MetaConverter<Double> = object : MetaConverter<Double> {
override fun itemToObject(item: MetaItem<*>): Double = when (item) { override fun itemToObject(item: MetaItem<*>): Double = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -71,7 +71,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Double): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Double): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val float = object : MetaConverter<Float> { public val float: MetaConverter<Float> = object : MetaConverter<Float> {
override fun itemToObject(item: MetaItem<*>): Float = when (item) { override fun itemToObject(item: MetaItem<*>): Float = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -80,7 +80,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Float): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Float): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val int = object : MetaConverter<Int> { public val int: MetaConverter<Int> = object : MetaConverter<Int> {
override fun itemToObject(item: MetaItem<*>): Int = when (item) { override fun itemToObject(item: MetaItem<*>): Int = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -89,7 +89,7 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Int): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Int): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
val long = object : MetaConverter<Long> { public val long: MetaConverter<Long> = object : MetaConverter<Long> {
override fun itemToObject(item: MetaItem<*>): Long = when (item) { override fun itemToObject(item: MetaItem<*>): Long = when (item) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value") is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value is MetaItem.ValueItem -> item.value
@ -98,14 +98,14 @@ interface MetaConverter<T : Any> {
override fun objectToMetaItem(obj: Long): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: Long): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
inline fun <reified E : Enum<E>> enum(): MetaConverter<E> = object : MetaConverter<E> { public inline fun <reified E : Enum<E>> enum(): MetaConverter<E> = object : MetaConverter<E> {
@Suppress("USELESS_CAST") @Suppress("USELESS_CAST")
override fun itemToObject(item: MetaItem<*>): E = item.enum<E>() as? E ?: error("The Item is not a Enum") override fun itemToObject(item: MetaItem<*>): E = item.enum<E>() as? E ?: error("The Item is not a Enum")
override fun objectToMetaItem(obj: E): MetaItem<*> = MetaItem.ValueItem(obj.asValue()) override fun objectToMetaItem(obj: E): MetaItem<*> = MetaItem.ValueItem(obj.asValue())
} }
fun <T> valueList(writer: (T) -> Value = {Value.of(it)}, reader: (Value) -> T): MetaConverter<List<T>> = public fun <T> valueList(writer: (T) -> Value = {Value.of(it)}, reader: (Value) -> T): MetaConverter<List<T>> =
object : MetaConverter<List<T>> { object : MetaConverter<List<T>> {
override fun itemToObject(item: MetaItem<*>): List<T> = override fun itemToObject(item: MetaItem<*>): List<T> =
item.value?.list?.map(reader) ?: error("The item is not a value list") item.value?.list?.map(reader) ?: error("The item is not a value list")
@ -117,8 +117,8 @@ interface MetaConverter<T : Any> {
} }
} }
fun <T : Any> MetaConverter<T>.nullableItemToObject(item: MetaItem<*>?): T? = item?.let { itemToObject(it) } public fun <T : Any> MetaConverter<T>.nullableItemToObject(item: MetaItem<*>?): T? = item?.let { itemToObject(it) }
fun <T : Any> MetaConverter<T>.nullableObjectToMetaItem(obj: T?): MetaItem<*>? = obj?.let { objectToMetaItem(it) } public fun <T : Any> MetaConverter<T>.nullableObjectToMetaItem(obj: T?): MetaItem<*>? = obj?.let { objectToMetaItem(it) }
fun <T : Any> MetaConverter<T>.metaToObject(meta: Meta): T = itemToObject(MetaItem.NodeItem(meta)) public fun <T : Any> MetaConverter<T>.metaToObject(meta: Meta): T = itemToObject(MetaItem.NodeItem(meta))
fun <T : Any> MetaConverter<T>.valueToObject(value: Value): T = itemToObject(MetaItem.ValueItem(value)) public fun <T : Any> MetaConverter<T>.valueToObject(value: Value): T = itemToObject(MetaItem.ValueItem(value))

View File

@ -6,31 +6,31 @@ import hep.dataforge.names.Name
/** /**
* A transformation for meta item or a group of items * A transformation for meta item or a group of items
*/ */
interface TransformationRule { public interface TransformationRule {
/** /**
* Check if this transformation should be applied to a node with given name and value * Check if this transformation should be applied to a node with given name and value
*/ */
fun matches(name: Name, item: MetaItem<*>?): Boolean public fun matches(name: Name, item: MetaItem<*>?): Boolean
/** /**
* Select all items to be transformed. Item could be a value as well as node * Select all items to be transformed. Item could be a value as well as node
* *
* @return a sequence of item paths to be transformed * @return a sequence of item paths to be transformed
*/ */
fun selectItems(meta: Meta): Sequence<Name> = public fun selectItems(meta: Meta): Sequence<Name> =
meta.sequence().filter { matches(it.first, it.second) }.map { it.first } meta.sequence().filter { matches(it.first, it.second) }.map { it.first }
/** /**
* Apply transformation for a single item (Node or Value) to the target * Apply transformation for a single item (Node or Value) to the target
*/ */
fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M): Unit public fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M): Unit
} }
/** /**
* A transformation which keeps all elements, matching [selector] unchanged. * A transformation which keeps all elements, matching [selector] unchanged.
*/ */
data class KeepTransformationRule(val selector: (Name) -> Boolean) : public data class KeepTransformationRule(val selector: (Name) -> Boolean) :
TransformationRule { TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean { override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return selector(name) return selector(name)
@ -47,7 +47,7 @@ data class KeepTransformationRule(val selector: (Name) -> Boolean) :
/** /**
* A transformation which transforms element with specific name * A transformation which transforms element with specific name
*/ */
data class SingleItemTransformationRule( public data class SingleItemTransformationRule(
val from: Name, val from: Name,
val transform: MutableMeta<*>.(Name, MetaItem<*>?) -> Unit val transform: MutableMeta<*>.(Name, MetaItem<*>?) -> Unit
) : TransformationRule { ) : TransformationRule {
@ -64,7 +64,7 @@ data class SingleItemTransformationRule(
} }
} }
data class RegexItemTransformationRule( public data class RegexItemTransformationRule(
val from: Regex, val from: Regex,
val transform: MutableMeta<*>.(name: Name, MatchResult, MetaItem<*>?) -> Unit val transform: MutableMeta<*>.(name: Name, MatchResult, MetaItem<*>?) -> Unit
) : TransformationRule { ) : TransformationRule {
@ -84,12 +84,12 @@ data class RegexItemTransformationRule(
/** /**
* A set of [TransformationRule] to either transform static meta or create dynamically updated [MutableMeta] * A set of [TransformationRule] to either transform static meta or create dynamically updated [MutableMeta]
*/ */
inline class MetaTransformation(val transformations: Collection<TransformationRule>) { public inline class MetaTransformation(public 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
*/ */
fun generate(source: Meta): Meta = public fun generate(source: Meta): Meta =
Meta { Meta {
transformations.forEach { rule -> transformations.forEach { rule ->
rule.selectItems(source).forEach { name -> rule.selectItems(source).forEach { name ->
@ -102,7 +102,7 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
* Generate an observable configuration that contains only elements defined by transformation rules and changes with the source * Generate an observable configuration that contains only elements defined by transformation rules and changes with the source
*/ */
@DFExperimental @DFExperimental
fun generate(source: Config): ObservableMeta = Config().apply { public fun generate(source: Config): ObservableMeta = Config().apply {
transformations.forEach { rule -> transformations.forEach { rule ->
rule.selectItems(source).forEach { name -> rule.selectItems(source).forEach { name ->
rule.transformItem(name, source[name], this) rule.transformItem(name, source[name], this)
@ -115,7 +115,7 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
/** /**
* Transform a meta, replacing all elements found in rules with transformed entries * Transform a meta, replacing all elements found in rules with transformed entries
*/ */
fun apply(source: Meta): Meta = public fun apply(source: Meta): Meta =
source.edit { source.edit {
transformations.forEach { rule -> transformations.forEach { rule ->
rule.selectItems(source).forEach { name -> rule.selectItems(source).forEach { name ->
@ -128,7 +128,7 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
/** /**
* Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule. * 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: Config, target: M) { public fun <M : MutableMeta<M>> bind(source: Config, target: M) {
source.onChange(target) { name, _, newItem -> source.onChange(target) { name, _, newItem ->
transformations.forEach { t -> transformations.forEach { t ->
if (t.matches(name, newItem)) { if (t.matches(name, newItem)) {
@ -147,27 +147,27 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
/** /**
* A builder for a set of transformation rules * A builder for a set of transformation rules
*/ */
class MetaTransformationBuilder { public class MetaTransformationBuilder {
val transformations = HashSet<TransformationRule>() private val transformations = HashSet<TransformationRule>()
/** /**
* Keep all items with name satisfying the criteria * Keep all items with name satisfying the criteria
*/ */
fun keep(selector: (Name) -> Boolean) { public fun keep(selector: (Name) -> Boolean) {
transformations.add(KeepTransformationRule(selector)) transformations.add(KeepTransformationRule(selector))
} }
/** /**
* Keep specific item (including its descendants) * Keep specific item (including its descendants)
*/ */
fun keep(name: Name) { public fun keep(name: Name) {
keep { it == name } keep { it == name }
} }
/** /**
* Keep nodes by regex * Keep nodes by regex
*/ */
fun keep(regex: String) { public fun keep(regex: String) {
transformations.add( transformations.add(
RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem -> RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem ->
setItem(name, metaItem) setItem(name, metaItem)
@ -177,7 +177,7 @@ class MetaTransformationBuilder {
/** /**
* Move an item from [from] to [to], optionally applying [operation] it defined * Move an item from [from] to [to], optionally applying [operation] it defined
*/ */
fun move(from: Name, to: Name, operation: (MetaItem<*>?) -> Any? = { it }) { public fun move(from: Name, to: Name, operation: (MetaItem<*>?) -> Any? = { it }) {
transformations.add( transformations.add(
SingleItemTransformationRule(from) { _, item -> SingleItemTransformationRule(from) { _, item ->
set(to, operation(item)) set(to, operation(item))
@ -185,5 +185,5 @@ class MetaTransformationBuilder {
) )
} }
fun build() = MetaTransformation(transformations) public fun build(): MetaTransformation = MetaTransformation(transformations)
} }

View File

@ -13,7 +13,7 @@ public fun Value.isNull(): Boolean = this == Null
*/ */
public fun Value.isList(): Boolean = this.list.size > 1 public fun Value.isList(): Boolean = this.list.size > 1
public val Value.boolean public val Value.boolean: Boolean
get() = this == True get() = this == True
|| this.list.firstOrNull() == True || this.list.firstOrNull() == True
|| (type == ValueType.STRING && string.toBoolean()) || (type == ValueType.STRING && string.toBoolean())

View File

@ -35,7 +35,7 @@ public abstract class WorkspacePlugin : AbstractPlugin() {
public inline fun <reified T : Any> task( public inline fun <reified T : Any> task(
name: String, name: String,
noinline builder: TaskBuilder<T>.() -> Unit noinline builder: TaskBuilder<T>.() -> Unit
) = task(name, T::class, builder) ): GenericTask<T> = task(name, T::class, builder)
// //
////TODO add delegates to build gradle-like tasks ////TODO add delegates to build gradle-like tasks