Fixed inline invloke on Specification

This commit is contained in:
Alexander Nozik 2020-11-20 14:47:18 +03:00
parent 920366388d
commit 0a77f729ec
12 changed files with 23 additions and 150 deletions

View File

@ -14,9 +14,11 @@
### Deprecated
- Context activation API
- TextRenderer
### Removed
- Functional server prototype
- `dataforge-output` module
### Fixed
- Global context CoroutineScope resolution

View File

@ -2,7 +2,7 @@ plugins {
id("ru.mipt.npm.project")
}
val dataforgeVersion by extra("0.2.0-dev-7")
val dataforgeVersion by extra("0.2.0-dev-8")
val bintrayRepo by extra("dataforge")
val githubProject by extra("dataforge-core")

View File

@ -18,10 +18,10 @@ public interface Specification<T : MutableItemProvider> {
public fun wrap(meta: Meta, defaultProvider: ItemProvider = ItemProvider.EMPTY): T
}
public operator fun <T : MutableItemProvider> Specification<T>.invoke(action: T.() -> Unit): T = empty().apply(action)
public fun <T : MutableItemProvider> Specification<T>.empty(): T = wrap(Config())
public inline operator fun <T : MutableItemProvider> Specification<T>.invoke(action: T.() -> Unit): T = empty().apply(action)
/**
* Update given configuration using given type as a builder
*/

View File

@ -1,26 +0,0 @@
public final class hep/dataforge/output/html/DefaultHtmlBuilder : hep/dataforge/output/html/HtmlBuilder {
public static final field INSTANCE Lhep/dataforge/output/html/DefaultHtmlBuilder;
public fun getPriority ()I
public fun getType ()Lkotlin/reflect/KClass;
public fun render (Lkotlinx/html/FlowContent;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public abstract interface class hep/dataforge/output/html/HtmlBuilder {
public static final field Companion Lhep/dataforge/output/html/HtmlBuilder$Companion;
public static final field HTML_CONVERTER_TYPE Ljava/lang/String;
public abstract fun getPriority ()I
public abstract fun getType ()Lkotlin/reflect/KClass;
public abstract fun render (Lkotlinx/html/FlowContent;Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class hep/dataforge/output/html/HtmlBuilder$Companion {
public static final field HTML_CONVERTER_TYPE Ljava/lang/String;
}
public final class hep/dataforge/output/html/HtmlRenderer : hep/dataforge/output/Renderer {
public fun <init> (Lhep/dataforge/context/Context;Lkotlinx/html/TagConsumer;)V
public fun getContext ()Lhep/dataforge/context/Context;
public fun getLogger ()Lmu/KLogger;
public fun render (Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V
}

View File

@ -1,16 +0,0 @@
plugins {
id("ru.mipt.npm.mpp")
}
val htmlVersion by rootProject.extra("0.7.2")
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api(project(":dataforge-output"))
api("org.jetbrains.kotlinx:kotlinx-html:$htmlVersion")
}
}
}
}

View File

@ -1,82 +0,0 @@
package hep.dataforge.output.html
import hep.dataforge.context.Context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.output.Output
import hep.dataforge.output.Renderer
import hep.dataforge.output.TextFormat
import hep.dataforge.output.html.HtmlBuilder.Companion.HTML_CONVERTER_TYPE
import hep.dataforge.provider.Type
import hep.dataforge.provider.top
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.html.FlowContent
import kotlinx.html.TagConsumer
import kotlinx.html.p
import kotlin.reflect.KClass
@DFExperimental
public class HtmlRenderer<T : Any>(override val context: Context, private val consumer: TagConsumer<*>) : Renderer<T> {
private val cache = HashMap<KClass<*>, HtmlBuilder<*>>()
/**
* Find the first [TextFormat] matching the given object type.
*/
override fun render(obj: T, meta: Meta) {
val builder: HtmlBuilder<*> = if (obj is CharSequence) {
DefaultHtmlBuilder
} else {
val value = cache[obj::class]
if (value == null) {
val answer =
context.top<HtmlBuilder<*>>(HTML_CONVERTER_TYPE).values.firstOrNull { it.type.isInstance(obj) }
if (answer != null) {
cache[obj::class] = answer
answer
} else {
DefaultHtmlBuilder
}
} else {
value
}
}
context.launch(Dispatchers.Output) {
@Suppress("UNCHECKED_CAST")
(builder as HtmlBuilder<T>).run { render(obj) }
}
}
}
/**
* A text or binary renderer based on [Renderer]
*/
@Type(HTML_CONVERTER_TYPE)
public interface HtmlBuilder<T : Any> {
/**
* The priority of this renderer compared to other renderers
*/
public val priority: Int
/**
* The type of the content served by this renderer
*/
public val type: KClass<T>
public suspend fun FlowContent.render(obj: T)
public companion object {
public const val HTML_CONVERTER_TYPE: String = "dataforge.htmlBuilder"
}
}
public object DefaultHtmlBuilder : HtmlBuilder<Any> {
override val priority: Int = Int.MAX_VALUE
override val type: KClass<Any> = Any::class
override suspend fun FlowContent.render(obj: Any) {
p { +obj.toString() }
}
}

View File

@ -19,7 +19,7 @@ public interface OutputManager {
* @param name represents the name inside the node.
* @param meta configuration for [Renderer] (not for rendered object)
*/
public operator fun <T : Any> get(
public fun <T : Any> getOutputContainer(
type: KClass<out T>,
name: Name,
stage: Name = Name.EMPTY,
@ -35,37 +35,30 @@ public val Context.output: OutputManager get() = plugins.get() ?: ConsoleOutputM
/**
* Get an output with given [name], [stage] and reified content type
*/
public inline operator fun <reified T : Any> OutputManager.get(
public inline fun <reified T : Any> OutputManager.getOutputContainer(
name: Name,
stage: Name = Name.EMPTY,
meta: Meta = Meta.EMPTY
): Renderer<T> {
return get(T::class, name, stage, meta)
return getOutputContainer(T::class, name, stage, meta)
}
/**
* Directly render an object using the most suitable renderer
*/
public fun OutputManager.render(obj: Any, name: Name, stage: Name = Name.EMPTY, meta: Meta = Meta.EMPTY): Unit =
get(obj::class, name, stage).render(obj, meta)
getOutputContainer(obj::class, name, stage).render(obj, meta)
/**
* System console output.
* The [CONSOLE_RENDERER] is used when no other [OutputManager] is provided.
*/
public val CONSOLE_RENDERER: Renderer<Any> = object : Renderer<Any> {
override fun render(obj: Any, meta: Meta) {
println(obj)
}
override val context: Context get() = Global
}
public val CONSOLE_RENDERER: Renderer<Any> = Renderer { obj, meta -> println(obj) }
public class ConsoleOutputManager : AbstractPlugin(), OutputManager {
override val tag: PluginTag get() = ConsoleOutputManager.tag
override fun <T : Any> get(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> = CONSOLE_RENDERER
override fun <T : Any> getOutputContainer(type: KClass<out T>, name: Name, stage: Name, meta: Meta): Renderer<T> = CONSOLE_RENDERER
public companion object : PluginFactory<ConsoleOutputManager> {
override val tag: PluginTag = PluginTag("output.console", group = DATAFORGE_GROUP)

View File

@ -10,12 +10,12 @@ import hep.dataforge.meta.Meta
* based on its configuration and provided meta
*
*/
public interface Renderer<in T : Any> : ContextAware {
public fun interface Renderer<in T : Any> {
/**
* Render specific object with configuration.
*
* By convention actual render is called in asynchronous mode, so this method should never
* block execution
*/
public fun render(obj: T, meta: Meta = Meta.EMPTY)
public fun render(obj: T, meta: Meta)
}

View File

@ -8,12 +8,14 @@ import hep.dataforge.provider.top
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.reflect.KClass
import kotlin.reflect.KType
/**
* A text or binary renderer based on [Output]
*/
@Type(TEXT_RENDERER_TYPE)
@Deprecated("Bad design")
public interface TextFormat {
/**
* The priority of this renderer compared to other renderers
@ -31,6 +33,7 @@ public interface TextFormat {
}
}
@Deprecated("Bad design")
public object DefaultTextFormat : TextFormat {
override val priority: Int = Int.MAX_VALUE
override val type: KClass<*> = Any::class
@ -43,6 +46,7 @@ public object DefaultTextFormat : TextFormat {
/**
* A text-based renderer
*/
@Deprecated("Bad design")
public class TextRenderer(override val context: Context, private val output: Appendable) : Renderer<Any> {
private val cache = HashMap<KClass<*>, TextFormat>()

View File

@ -9,7 +9,6 @@ kotlin {
dependencies {
api(project(":dataforge-context"))
api(project(":dataforge-data"))
api(project(":dataforge-output"))
api(project(":dataforge-io"))
}
}

View File

@ -36,7 +36,7 @@ private fun newZFS(path: Path): FileSystem {
* @param metaFileFormat the meta format for override
*/
@DFExperimental
fun <T : Any> IOPlugin.readDataFile(
public fun <T : Any> IOPlugin.readDataFile(
path: Path,
type: KClass<out T>,
formatResolver: FileFormatResolver<T>
@ -47,7 +47,7 @@ fun <T : Any> IOPlugin.readDataFile(
}
@DFExperimental
inline fun <reified T : Any> IOPlugin.readDataFile(path: Path): Data<T> =
public inline fun <reified T : Any> IOPlugin.readDataFile(path: Path): Data<T> =
readDataFile(path, T::class) { _, _ ->
resolveIOFormat<T>() ?: error("Can't resolve IO format for ${T::class}")
}
@ -56,7 +56,7 @@ inline fun <reified T : Any> IOPlugin.readDataFile(path: Path): Data<T> =
* Add file/directory-based data tree item
*/
@DFExperimental
fun <T : Any> DataTreeBuilder<T>.file(
public fun <T : Any> DataTreeBuilder<T>.file(
plugin: IOPlugin,
path: Path,
formatResolver: FileFormatResolver<T>
@ -109,7 +109,7 @@ fun <T : Any> IOPlugin.readDataDirectory(
}
@DFExperimental
inline fun <reified T : Any> IOPlugin.readDataDirectory(path: Path): DataNode<T> =
public inline fun <reified T : Any> IOPlugin.readDataDirectory(path: Path): DataNode<T> =
readDataDirectory(path, T::class) { _, _ ->
resolveIOFormat<T>() ?: error("Can't resolve IO format for ${T::class}")
}
@ -118,7 +118,7 @@ inline fun <reified T : Any> IOPlugin.readDataDirectory(path: Path): DataNode<T>
* Write data tree to existing directory or create a new one using default [java.nio.file.FileSystem] provider
*/
@DFExperimental
suspend fun <T : Any> IOPlugin.writeDataDirectory(
public suspend fun <T : Any> IOPlugin.writeDataDirectory(
path: Path,
node: DataNode<T>,
format: IOFormat<T>,

View File

@ -30,8 +30,7 @@ include(
":dataforge-io:dataforge-io-yaml",
":dataforge-context",
":dataforge-data",
":dataforge-output",
":dataforge-output:dataforge-output-html",
// ":dataforge-output",
":dataforge-tables",
":dataforge-workspace",
":dataforge-scripting"