Providers provide map instead of sequence on provideAll (replaced by top).

Context task loading ambiguity solved by prepending plugin name.
This commit is contained in:
Alexander Nozik 2019-05-08 22:15:44 +03:00
parent f284d15ee4
commit 52fb8234fc
11 changed files with 64 additions and 40 deletions

View File

@ -20,5 +20,5 @@ abstract class AbstractPlugin(override val meta: Meta = EmptyMeta) : Plugin {
override fun provideTop(target: String, name: Name): Any? = null
override fun listTop(target: String): Sequence<Name> = emptySequence()
override fun listNames(target: String): Sequence<Name> = emptySequence()
}

View File

@ -2,9 +2,10 @@ package hep.dataforge.context
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import hep.dataforge.names.appendLeft
import hep.dataforge.names.toName
import hep.dataforge.provider.Provider
import hep.dataforge.provider.provideAll
import hep.dataforge.provider.top
import hep.dataforge.values.Value
import kotlinx.coroutines.CoroutineScope
import mu.KLogger
@ -66,7 +67,7 @@ open class Context(final override val name: String, val parent: Context? = Globa
}
}
override fun listTop(target: String): Sequence<Name> {
override fun listNames(target: String): Sequence<Name> {
return when (target) {
Plugin.PLUGIN_TARGET -> plugins.asSequence().map { it.name.toName() }
Value.TYPE -> properties.values().map { it.first }
@ -118,12 +119,13 @@ open class Context(final override val name: String, val parent: Context? = Globa
/**
* A sequences of all objects provided by plugins with given target and type
*/
fun Context.members(target: String): Sequence<Any> =
plugins.asSequence().flatMap { it.provideAll(target) }
fun Context.content(target: String): Map<Name, Any> = content<Any>(target)
@JvmName("typedMembers")
inline fun <reified T : Any> Context.members(target: String) =
members(target).filterIsInstance<T>()
@JvmName("typedContent")
inline fun <reified T : Any> Context.content(target: String): Map<Name, T> =
plugins.flatMap { plugin ->
plugin.top<T>(target).entries.map { (it.key.appendLeft(plugin.name)) to it.value }
}.associate { it }
/**

View File

@ -17,6 +17,7 @@ package hep.dataforge.provider
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlin.jvm.JvmName
/**
* A marker utility interface for providers.
@ -51,7 +52,7 @@ interface Provider {
* @param target
* @return
*/
fun listTop(target: String): Sequence<Name>
fun listNames(target: String): Sequence<Name>
}
fun Provider.provide(path: Path, targetOverride: String? = null): Any? {
@ -77,15 +78,23 @@ inline fun <reified T : Any> Provider.provide(path: String): T? {
return provide(Path.parse(path)) as? T
}
inline fun <reified T : Any> Provider.provide(target: String, name: String): T? {
return provide(PathToken(name.toName(), target).toPath()) as? T
inline fun <reified T : Any> Provider.provide(target: String, name: Name): T? {
return provide(PathToken(name, target).toPath()) as? T
}
inline fun <reified T : Any> Provider.provide(target: String, name: String): T? =
provide(target, name.toName())
/**
* [Sequence] of all elements with given target
* A top level content with names
*/
fun Provider.provideAll(target: String): Sequence<Any> {
return listTop(target).map { provideTop(target, it) ?: error("The element $it is declared but not provided") }
fun Provider.top(target: String): Map<Name, Any> = top<Any>(target)
@JvmName("typedTop")
inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> {
return listNames(target).associate {
it to (provideTop(target, it) as? T ?: error("The element $it is declared but not provided"))
}
}

View File

@ -17,10 +17,10 @@ class ContextTest {
}
}
override fun listTop(target: String): Sequence<Name> {
override fun listNames(target: String): Sequence<Name> {
return when (target) {
"test" -> sequenceOf("a", "b", "c.d").map { it.toName() }
else -> super.listTop(target)
else -> super.listNames(target)
}
}
}
@ -28,7 +28,7 @@ class ContextTest {
@Test
fun testPluginManager() {
Global.plugins.load(DummyPlugin())
val members = Global.members<Name>("test")
val members = Global.content<Name>("test")
assertEquals(3, members.count())
members.forEach {
println(it)

View File

@ -1,11 +1,14 @@
package hep.dataforge.provider
import hep.dataforge.context.Context
import hep.dataforge.context.members
import hep.dataforge.context.content
import hep.dataforge.names.Name
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation
/**
*
*/
object Types {
operator fun get(cl: KClass<*>): String {
return cl.findAnnotation<Type>()?.id ?: cl.simpleName ?: ""
@ -24,13 +27,20 @@ inline fun <reified T : Any> Provider.provideByType(name: String): T? {
return provide(target, name)
}
inline fun <reified T : Any> Provider.provideAllByType(): Sequence<T> {
inline fun <reified T : Any> Provider.provideByType(name: Name): T? {
val target = Types[T::class]
return provideAll(target).filterIsInstance<T>()
return provide(target, name)
}
inline fun <reified T : Any> Provider.top(): Map<Name, T> {
val target = Types[T::class]
return listNames(target).associate { name ->
name to (provideByType<T>(name) ?: error("The element $name is declared but not provided"))
}
}
/**
* A sequences of all objects provided by plugins with given target and type
*/
inline fun <reified T : Any> Context.members(): Sequence<T> = members<T>(Types[T::class])
inline fun <reified T : Any> Context.content(): Map<Name, T> = content<T>(Types[T::class])

View File

@ -102,6 +102,8 @@ operator fun Name.plus(other: Name): Name = Name(this.tokens + other.tokens)
operator fun Name.plus(other: String): Name = this + other.toName()
fun Name.appendLeft(other: String): Name = NameToken(other) + this
fun NameToken.asName() = Name(listOf(this))
val EmptyName = Name(emptyList())

View File

@ -4,11 +4,9 @@ import hep.dataforge.context.Context
import hep.dataforge.meta.Meta
import hep.dataforge.output.Output
import hep.dataforge.output.TextRenderer
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.output.html.HtmlBuilder.Companion.HTML_CONVERTER_TYPE
import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll
import hep.dataforge.provider.provideAllByType
import hep.dataforge.provider.top
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.html.TagConsumer
@ -29,7 +27,7 @@ class HtmlOutput<T : Any>(override val context: Context, private val consumer: T
} else {
val value = cache[obj::class]
if (value == null) {
val answer = context.provideAllByType<HtmlBuilder<*>>()
val answer = context.top<HtmlBuilder<*>>().values
.filter { it.type.isInstance(obj) }.firstOrNull()
if (answer != null) {
cache[obj::class] = answer

View File

@ -1,10 +1,10 @@
package hep.dataforge.output
import hep.dataforge.context.Context
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.meta.Meta
import hep.dataforge.output.TextRenderer.Companion.TEXT_RENDERER_TYPE
import hep.dataforge.provider.Type
import hep.dataforge.provider.provideAll
import hep.dataforge.provider.top
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
@ -21,8 +21,8 @@ class TextOutput(override val context: Context, private val output: kotlinx.io.c
} else {
val value = cache[obj::class]
if (value == null) {
val answer = context.provideAll(TEXT_RENDERER_TYPE).filterIsInstance<TextRenderer>()
.filter { it.type.isInstance(obj) }.firstOrNull()
val answer =
context.top<TextRenderer>(TEXT_RENDERER_TYPE).values.firstOrNull { it.type.isInstance(obj) }
if (answer != null) {
cache[obj::class] = answer
answer

View File

@ -8,6 +8,7 @@ import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.buildMeta
import hep.dataforge.names.EmptyName
import hep.dataforge.names.Name
import hep.dataforge.names.get
import hep.dataforge.names.isEmpty
/**
@ -49,7 +50,7 @@ class AllDataDependency(val placement: Name = EmptyName) : Dependency() {
class TaskModelDependency(val name: String, val meta: Meta, val placement: Name = EmptyName) : Dependency() {
override fun apply(workspace: Workspace): DataNode<Any> {
val task = workspace.tasks[name] ?: error("Task with name ${name} is not found in the workspace")
val task = workspace.tasks[name] ?: error("Task with name $name is not found in the workspace")
if (task.isTerminal) TODO("Support terminal task")
val result = workspace.run(task, meta)
return if (placement.isEmpty()) {

View File

@ -2,9 +2,11 @@ package hep.dataforge.workspace
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.context.members
import hep.dataforge.data.DataNode
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import hep.dataforge.provider.top
/**
@ -16,8 +18,8 @@ class SimpleWorkspace(
override val targets: Map<String, Meta>,
tasks: Collection<Task<Any>>
) : Workspace {
override val tasks: Map<String, Task<*>> by lazy {
(context.members<Task<*>>(Task.TYPE) + tasks).associate { it.name to it }
override val tasks: Map<Name, Task<*>> by lazy {
context.top<Task<*>>(Task.TYPE) + tasks.associate { it.name.toName() to it }
}
companion object {

View File

@ -27,22 +27,22 @@ interface Workspace : ContextAware, Provider {
/**
* All tasks associated with the workspace
*/
val tasks: Map<String, Task<*>>
val tasks: Map<Name, Task<*>>
override fun provideTop(target: String, name: Name): Any? {
return when (target) {
"target", Meta.TYPE -> targets[name.toString()]
Task.TYPE -> tasks[name.toString()]
Task.TYPE -> tasks[name]
Data.TYPE -> data[name]
DataNode.TYPE -> data.getNode(name)
else -> null
}
}
override fun listTop(target: String): Sequence<Name> {
override fun listNames(target: String): Sequence<Name> {
return when (target) {
"target", Meta.TYPE -> targets.keys.asSequence().map { it.toName() }
Task.TYPE -> tasks.keys.asSequence().map { it.toName() }
Task.TYPE -> tasks.keys.asSequence().map { it }
Data.TYPE -> data.data().map { it.first }
DataNode.TYPE -> data.nodes().map { it.first }
else -> emptySequence()
@ -85,10 +85,10 @@ fun Workspace.run(task: Task<*>, target: String): DataNode<Any> {
fun Workspace.run(task: String, target: String) =
tasks[task]?.let { run(it, target) } ?: error("Task with name $task not found")
tasks[task.toName()]?.let { run(it, target) } ?: error("Task with name $task not found")
fun Workspace.run(task: String, meta: Meta) =
tasks[task]?.let { run(it, meta) } ?: error("Task with name $task not found")
tasks[task.toName()]?.let { run(it, meta) } ?: error("Task with name $task not found")
fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}) =
run(task, buildMeta(block))