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
interface Factory<out T : Any> {
operator fun invoke(meta: Meta = Meta.EMPTY, context: Context = Global): T
public interface Factory<out T : Any> {
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
*/
interface Named {
public interface Named {
/**
* 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,
@ -42,7 +40,7 @@ interface Named {
* @param obj
* @return
*/
fun nameOf(obj: Any): Name {
public fun nameOf(obj: Any): Name {
return if (obj is Named) {
obj.name
} else {
@ -56,5 +54,4 @@ interface Named {
* Check if this object has an empty name and therefore is anonymous.
* @return
*/
val Named.isAnonymous: Boolean
get() = this.name.isEmpty()
public val Named.isAnonymous: Boolean get() = this.name.isEmpty()

View File

@ -22,21 +22,17 @@ import hep.dataforge.provider.Provider
*
* @author Alexander Nozik
*/
interface Plugin : Named, ContextAware, Provider, MetaRepr {
public interface Plugin : Named, ContextAware, Provider, MetaRepr {
/**
* 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
*
* @return
*/
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
* dependencies must be initialized and enabled in the Context before this
* 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
* 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
* plugins. This method should be called only via PluginManager to avoid
* dependency issues.
*/
fun detach()
public fun detach()
override fun toMeta(): Meta = Meta {
"context" put context.name.toString()
@ -71,9 +63,9 @@ interface Plugin : Named, ContextAware, Provider, MetaRepr {
"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
interface PluginFactory<T : Plugin> : Factory<T> {
val tag: PluginTag
val type: KClass<out T>
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
public val type: KClass<out T>
companion object{
const val TYPE = "pluginFactory"
public companion object{
public const val TYPE: String = "pluginFactory"
}
}
@ -21,7 +21,7 @@ interface PluginFactory<T : Plugin> : Factory<T> {
* @property context A context for this plugin manager
* @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
@ -34,7 +34,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
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) {
plugins.asSequence() + parent.sequence(true)
} else {
@ -47,7 +47,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @param recursive search for parent [PluginManager] plugins
* @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
* @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
*/
@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?
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)
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)
/**
@ -87,7 +87,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @param plugin
* @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 (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
*/
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))
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))
/**
* 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 (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
*
*/
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)
return when {
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>,
recursive: Boolean = true,
metaBuilder: MetaBuilder.() -> Unit

View File

@ -26,25 +26,25 @@ import hep.dataforge.names.toName
* @author Alexander Nozik
* @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.
*
* @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()
companion object {
const val PATH_SEGMENT_SEPARATOR = "/"
public companion object {
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 tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
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) {
name.toString()
} else {
"$target$TARGET_SEPARATOR$name"
}
companion object {
const val TARGET_SEPARATOR = "::"
fun parse(token: String): PathToken {
public companion object {
public const val TARGET_SEPARATOR: String = "::"
public fun parse(token: String): PathToken {
val target = token.substringBefore(TARGET_SEPARATOR, "")
val name = token.substringAfter(TARGET_SEPARATOR).toName()
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
*/
interface Provider {
public interface Provider {
/**
* Default target for this provider
*
* @return
*/
val defaultTarget: String get() = ""
public val defaultTarget: String get() = ""
/**
* Default target for next chain segment
*
* @return
*/
val defaultChainTarget: String get() = ""
public val defaultChainTarget: String get() = ""
/**
* 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")
val first = path.first()
val target = targetOverride ?: first.target ?: defaultTarget
@ -63,7 +59,7 @@ fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
/**
* 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
}
//
@ -77,7 +73,7 @@ inline fun <reified T : Any> Provider.provide(path: String, targetOverride: Stri
/**
* 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 {
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
@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
*/
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
* 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
*/
val isTerminal: Boolean get() = false
public val isTerminal: Boolean get() = false
}
/**
* 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
return object : Action<T, R> {
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {

View File

@ -1,48 +1,58 @@
package hep.dataforge.data
import hep.dataforge.meta.DFExperimental
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
/**
* 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
var totalWork: Double = 1.0
var workDone: Double = 0.0
var status: String = ""
public var totalWork: Double = 1.0
public var workDone: Double = 0.0
public var status: String = ""
/**
* Mark the goal as started
*/
fun start() {
public fun start() {
}
/**
* Mark the goal as completed
*/
fun finish() {
public fun finish() {
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
companion object : CoroutineContext.Key<Dependencies>
public companion object : CoroutineContext.Key<Dependencies>
}
val CoroutineContext.monitor: CoroutineMonitor? get() = this[CoroutineMonitor]
val CoroutineScope.monitor: CoroutineMonitor? get() = coroutineContext.monitor
@DFExperimental
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)
val Job.workDone: Double get() = dependencies.sumByDouble { workDone } + (monitor?.workDone ?: 0.0)
val Job.status: String get() = monitor?.status ?: ""
val Job.progress: Double get() = workDone / totalWork
@DFExperimental
public val Job.totalWork: Double get() = dependencies.sumByDouble { totalWork } + (monitor?.totalWork ?: 0.0)
@DFExperimental
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
*/
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.
*/

View File

@ -6,18 +6,18 @@ import hep.dataforge.values.*
/**
* A converter of generic object to and from [MetaItem]
*/
interface MetaConverter<T : Any> {
fun itemToObject(item: MetaItem<*>): T
fun objectToMetaItem(obj: T): MetaItem<*>
public interface MetaConverter<T : Any> {
public fun itemToObject(item: MetaItem<*>): T
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 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) {
is MetaItem.NodeItem -> item.node
is MetaItem.ValueItem -> item.value.toMeta()
@ -26,7 +26,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -35,7 +35,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -44,7 +44,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -53,7 +53,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -62,7 +62,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -71,7 +71,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -80,7 +80,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -89,7 +89,7 @@ interface MetaConverter<T : Any> {
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) {
is MetaItem.NodeItem -> item.node[Meta.VALUE_KEY].value ?: error("Can't convert node to a value")
is MetaItem.ValueItem -> item.value
@ -98,14 +98,14 @@ interface MetaConverter<T : Any> {
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")
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())
}
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>> {
override fun itemToObject(item: MetaItem<*>): List<T> =
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) }
fun <T : Any> MetaConverter<T>.nullableObjectToMetaItem(obj: T?): MetaItem<*>? = obj?.let { objectToMetaItem(it) }
public fun <T : Any> MetaConverter<T>.nullableItemToObject(item: MetaItem<*>?): T? = item?.let { itemToObject(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))
fun <T : Any> MetaConverter<T>.valueToObject(value: Value): T = itemToObject(MetaItem.ValueItem(value))
public fun <T : Any> MetaConverter<T>.metaToObject(meta: Meta): T = itemToObject(MetaItem.NodeItem(meta))
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
*/
interface TransformationRule {
public interface TransformationRule {
/**
* 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
*
* @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 }
/**
* 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.
*/
data class KeepTransformationRule(val selector: (Name) -> Boolean) :
public data class KeepTransformationRule(val selector: (Name) -> Boolean) :
TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return selector(name)
@ -47,7 +47,7 @@ data class KeepTransformationRule(val selector: (Name) -> Boolean) :
/**
* A transformation which transforms element with specific name
*/
data class SingleItemTransformationRule(
public data class SingleItemTransformationRule(
val from: Name,
val transform: MutableMeta<*>.(Name, MetaItem<*>?) -> Unit
) : TransformationRule {
@ -64,7 +64,7 @@ data class SingleItemTransformationRule(
}
}
data class RegexItemTransformationRule(
public data class RegexItemTransformationRule(
val from: Regex,
val transform: MutableMeta<*>.(name: Name, MatchResult, MetaItem<*>?) -> Unit
) : TransformationRule {
@ -84,12 +84,12 @@ data class RegexItemTransformationRule(
/**
* 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
*/
fun generate(source: Meta): Meta =
public fun generate(source: Meta): Meta =
Meta {
transformations.forEach { rule ->
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
*/
@DFExperimental
fun generate(source: Config): ObservableMeta = Config().apply {
public fun generate(source: Config): ObservableMeta = Config().apply {
transformations.forEach { rule ->
rule.selectItems(source).forEach { name ->
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
*/
fun apply(source: Meta): Meta =
public fun apply(source: Meta): Meta =
source.edit {
transformations.forEach { rule ->
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.
*/
fun <M : MutableMeta<M>> bind(source: Config, target: M) {
public fun <M : MutableMeta<M>> bind(source: Config, target: M) {
source.onChange(target) { name, _, newItem ->
transformations.forEach { t ->
if (t.matches(name, newItem)) {
@ -147,27 +147,27 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
/**
* A builder for a set of transformation rules
*/
class MetaTransformationBuilder {
val transformations = HashSet<TransformationRule>()
public class MetaTransformationBuilder {
private val transformations = HashSet<TransformationRule>()
/**
* Keep all items with name satisfying the criteria
*/
fun keep(selector: (Name) -> Boolean) {
public fun keep(selector: (Name) -> Boolean) {
transformations.add(KeepTransformationRule(selector))
}
/**
* Keep specific item (including its descendants)
*/
fun keep(name: Name) {
public fun keep(name: Name) {
keep { it == name }
}
/**
* Keep nodes by regex
*/
fun keep(regex: String) {
public fun keep(regex: String) {
transformations.add(
RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem ->
setItem(name, metaItem)
@ -177,7 +177,7 @@ class MetaTransformationBuilder {
/**
* 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(
SingleItemTransformationRule(from) { _, 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 val Value.boolean
public val Value.boolean: Boolean
get() = this == True
|| this.list.firstOrNull() == True
|| (type == ValueType.STRING && string.toBoolean())

View File

@ -35,7 +35,7 @@ public abstract class WorkspacePlugin : AbstractPlugin() {
public inline fun <reified T : Any> task(
name: String,
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