Code cleanup

This commit is contained in:
Alexander Nozik 2019-01-27 17:16:40 +03:00
parent 5dd40f0226
commit 4cafac1f1b
26 changed files with 159 additions and 106 deletions

0
README.md Normal file
View File

View File

@ -7,7 +7,7 @@ description = "Context and provider definitions"
val coroutinesVersion: String by rootProject.extra val coroutinesVersion: String by rootProject.extra
kotlin { kotlin {
jvm () jvm()
js() js()
sourceSets { sourceSets {

View File

@ -11,7 +11,6 @@ import kotlinx.coroutines.Dispatchers
import mu.KLogger import mu.KLogger
import mu.KotlinLogging import mu.KotlinLogging
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.reflect.KClass
/** /**
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top. * The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
@ -102,12 +101,11 @@ inline fun <reified T : Any> Context.list(target: String): Sequence<T> {
/** /**
* A global root context * A global root context
*/ */
expect object Global : Context{ expect object Global : Context {
fun getContext(name: String): Context fun getContext(name: String): Context
} }
/** /**
* The interface for something that encapsulated in context * The interface for something that encapsulated in context
* *

View File

@ -59,7 +59,8 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
* @return * @return
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T : Plugin> get(type: KClass<T>, recursive: Boolean = true): T? = get(recursive) { type.isInstance(it) } as T? operator fun <T : Plugin> get(type: KClass<T>, recursive: Boolean = true): T? =
get(recursive) { type.isInstance(it) } as T?
inline fun <reified T : Plugin> get(recursive: Boolean = true): T? = get(T::class, recursive) inline fun <reified T : Plugin> get(recursive: Boolean = true): T? = get(T::class, recursive)

View File

@ -24,5 +24,6 @@ expect object PluginRepository {
/** /**
* Fetch specific plugin and instantiate it with given meta * Fetch specific plugin and instantiate it with given meta
*/ */
fun PluginRepository.fetch(tag: PluginTag, meta: Meta): Plugin = PluginRepository.list().find { it.tag.matches(tag) }?.build(meta) fun PluginRepository.fetch(tag: PluginTag, meta: Meta): Plugin =
PluginRepository.list().find { it.tag.matches(tag) }?.build(meta)
?: error("Plugin with tag $tag not found in the repository") ?: error("Plugin with tag $tag not found in the repository")

View File

@ -11,9 +11,9 @@ import hep.dataforge.meta.buildMeta
* @author Alexander Nozik * @author Alexander Nozik
*/ */
data class PluginTag( data class PluginTag(
val name: String, val name: String,
val group: String = "", val group: String = "",
val version: String = "" val version: String = ""
) : MetaRepr { ) : MetaRepr {
/** /**

View File

@ -5,14 +5,14 @@ import mu.KLogger
import mu.KotlinLogging import mu.KotlinLogging
import kotlin.jvm.Synchronized import kotlin.jvm.Synchronized
actual object Global: Context, JSContext("GLOBAL", null){ actual object Global : Context, JSContext("GLOBAL", null) {
/** /**
* Closing all contexts * Closing all contexts
* *
* @throws Exception * @throws Exception
*/ */
override fun close() { override fun close() {
logger.info{"Shutting down GLOBAL"} logger.info { "Shutting down GLOBAL" }
for (ctx in contextRegistry.values) { for (ctx in contextRegistry.values) {
ctx.close() ctx.close()
} }
@ -34,10 +34,10 @@ actual object Global: Context, JSContext("GLOBAL", null){
} }
open class JSContext( open class JSContext(
final override val name: String, final override val name: String,
final override val parent: JSContext? = Global, final override val parent: JSContext? = Global,
properties: Meta = EmptyMeta properties: Meta = EmptyMeta
): Context { ) : Context {
private val _properties = Config().apply { update(properties) } private val _properties = Config().apply { update(properties) }
override val properties: Meta override val properties: Meta

View File

@ -24,7 +24,7 @@ actual object PluginRepository {
} }
inline fun <reified T : Plugin> register(tag: PluginTag, noinline constructor: (Meta) -> T) = inline fun <reified T : Plugin> register(tag: PluginTag, noinline constructor: (Meta) -> T) =
register(tag, T::class, constructor) register(tag, T::class, constructor)
/** /**
* List plugins available in the repository * List plugins available in the repository

View File

@ -16,7 +16,6 @@
package hep.dataforge.context package hep.dataforge.context
import hep.dataforge.meta.* import hep.dataforge.meta.*
import kotlinx.coroutines.Dispatchers
import mu.KLogger import mu.KLogger
import mu.KotlinLogging import mu.KotlinLogging
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -24,15 +23,14 @@ import java.util.*
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.collections.HashSet import kotlin.collections.HashSet
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.cast import kotlin.reflect.full.cast
open class JVMContext( open class JVMContext(
final override val name: String, final override val name: String,
final override val parent: JVMContext? = Global, final override val parent: JVMContext? = Global,
classLoader: ClassLoader? = null, classLoader: ClassLoader? = null,
properties: Meta = EmptyMeta properties: Meta = EmptyMeta
) : Context, AutoCloseable { ) : Context, AutoCloseable {
private val _properties = Config().apply { update(properties) } private val _properties = Config().apply { update(properties) }
@ -75,7 +73,8 @@ open class JVMContext(
private val serviceCache: MutableMap<Class<*>, ServiceLoader<*>> = HashMap() private val serviceCache: MutableMap<Class<*>, ServiceLoader<*>> = HashMap()
fun <T : Any> services(type: KClass<T>): Sequence<T> { fun <T : Any> services(type: KClass<T>): Sequence<T> {
return serviceCache.getOrPut(type.java) { ServiceLoader.load(type.java, classLoader) }.asSequence().map { type.cast(it) } return serviceCache.getOrPut(type.java) { ServiceLoader.load(type.java, classLoader) }.asSequence()
.map { type.cast(it) }
} }
/** /**

View File

@ -12,6 +12,6 @@ actual object PluginRepository {
* List plugins available in the repository * List plugins available in the repository
*/ */
actual fun list(): Sequence<PluginFactory> = actual fun list(): Sequence<PluginFactory> =
factories.asSequence() + Global.services(PluginFactory::class) factories.asSequence() + Global.services(PluginFactory::class)
} }

View File

@ -50,10 +50,11 @@ class PipeAction<in T : Any, out R : Any>(val transform: (Name, Data<T>, Meta) -
/** /**
* A simple pipe that performs transformation on the data and copies input meta into the output * A simple pipe that performs transformation on the data and copies input meta into the output
*/ */
inline fun <T : Any, reified R : Any> simple(noinline transform: suspend (Name, T, Meta) -> R) = PipeAction { name, data: Data<T>, meta -> inline fun <T : Any, reified R : Any> simple(noinline transform: suspend (Name, T, Meta) -> R) =
val goal = data.goal.pipe { transform(name, it, meta) } PipeAction { name, data: Data<T>, meta ->
return@PipeAction Data.of(goal, data.meta) val goal = data.goal.pipe { transform(name, it, meta) }
} return@PipeAction Data.of(goal, data.meta)
}
} }
} }

View File

@ -20,7 +20,8 @@ interface Goal<out T> : Deferred<T>, CoroutineScope {
/** /**
* Create goal wrapping static value. This goal is always completed * Create goal wrapping static value. This goal is always completed
*/ */
fun <T> static(context: CoroutineContext, value: T): Goal<T> = StaticGoalImpl(context, CompletableDeferred(value)) fun <T> static(context: CoroutineContext, value: T): Goal<T> =
StaticGoalImpl(context, CompletableDeferred(value))
} }
} }
@ -48,16 +49,18 @@ class GoalMonitor {
} }
private class GoalImpl<T>( private class GoalImpl<T>(
override val dependencies: Collection<Goal<*>>, override val dependencies: Collection<Goal<*>>,
val monitor: GoalMonitor, val monitor: GoalMonitor,
deferred: Deferred<T>) : Goal<T>, Deferred<T> by deferred { deferred: Deferred<T>
) : Goal<T>, Deferred<T> by deferred {
override val coroutineContext: CoroutineContext get() = this override val coroutineContext: CoroutineContext get() = this
override val totalWork: Double get() = dependencies.sumByDouble { totalWork } + monitor.totalWork override val totalWork: Double get() = dependencies.sumByDouble { totalWork } + monitor.totalWork
override val workDone: Double get() = dependencies.sumByDouble { workDone } + monitor.workDone override val workDone: Double get() = dependencies.sumByDouble { workDone } + monitor.workDone
override val status: String get() = monitor.status override val status: String get() = monitor.status
} }
private class StaticGoalImpl<T>(val context: CoroutineContext, deferred: CompletableDeferred<T>) : Goal<T>, Deferred<T> by deferred { private class StaticGoalImpl<T>(val context: CoroutineContext, deferred: CompletableDeferred<T>) : Goal<T>,
Deferred<T> by deferred {
override val dependencies: Collection<Goal<*>> get() = emptyList() override val dependencies: Collection<Goal<*>> get() = emptyList()
override val status: String get() = "" override val status: String get() = ""
override val totalWork: Double get() = 0.0 override val totalWork: Double get() = 0.0
@ -94,7 +97,10 @@ fun <T, R> Goal<T>.pipe(block: suspend GoalMonitor.(T) -> R): Goal<R> = createGo
* Create a joining goal. * Create a joining goal.
* @param scope the scope for resulting goal. By default use first goal in list * @param scope the scope for resulting goal. By default use first goal in list
*/ */
fun <T, R> Collection<Goal<T>>.join(scope: CoroutineScope = first(), block: suspend GoalMonitor.(Collection<T>) -> R): Goal<R> = fun <T, R> Collection<Goal<T>>.join(
scope.createGoal(this) { scope: CoroutineScope = first(),
block(map { it.await() }) block: suspend GoalMonitor.(Collection<T>) -> R
} ): Goal<R> =
scope.createGoal(this) {
block(map { it.await() })
}

View File

@ -31,6 +31,10 @@ interface OutputManager : Plugin {
/** /**
* Get an output with given [name], [stage] and reified content type * Get an output with given [name], [stage] and reified content type
*/ */
inline fun <reified T : Any> OutputManager.typed(name: Name, stage: Name = EmptyName, meta: Meta = EmptyMeta): Output<T> { inline fun <reified T : Any> OutputManager.typed(
name: Name,
stage: Name = EmptyName,
meta: Meta = EmptyMeta
): Output<T> {
return typed(T::class, name, stage, meta) return typed(T::class, name, stage, meta)
} }

View File

@ -124,7 +124,7 @@ object BinaryMetaFormat : MetaFormat {
} }
} }
class BinaryMetaFormatFactory: MetaFormatFactory{ class BinaryMetaFormatFactory : MetaFormatFactory {
override val name: String = "bin" override val name: String = "bin"
override val key: Short = 0x4249//BI override val key: Short = 0x4249//BI

View File

@ -74,7 +74,7 @@ class JsonMeta(val json: JsonObject) : Meta {
} }
} }
class JsonMetaFormatFactory: MetaFormatFactory{ class JsonMetaFormatFactory : MetaFormatFactory {
override val name: String = "json" override val name: String = "json"
override val key: Short = 0x4a53//"JS" override val key: Short = 0x4a53//"JS"

View File

@ -21,13 +21,13 @@ interface MetaFormatFactory {
fun build(): MetaFormat fun build(): MetaFormat
} }
fun Meta.asString(format: MetaFormat = JsonMetaFormat): String{ fun Meta.asString(format: MetaFormat = JsonMetaFormat): String {
val builder = BytePacketBuilder() val builder = BytePacketBuilder()
format.write(this,builder) format.write(this, builder)
return builder.build().readText() return builder.build().readText()
} }
fun MetaFormat.parse(str: String): Meta{ fun MetaFormat.parse(str: String): Meta {
return read(ByteReadPacket(str.toByteArray())) return read(ByteReadPacket(str.toByteArray()))
} }

View File

@ -4,9 +4,9 @@ import hep.dataforge.meta.buildMeta
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class MetaFormatTest{ class MetaFormatTest {
@Test @Test
fun testBinaryMetaFormat(){ fun testBinaryMetaFormat() {
val meta = buildMeta { val meta = buildMeta {
"a" to 22 "a" to 22
"node" to { "node" to {
@ -14,13 +14,13 @@ class MetaFormatTest{
"c" to 11.1 "c" to 11.1
} }
} }
val string = meta.asString(BinaryMetaFormat) val string = meta.asString(BinaryMetaFormat)
val result = BinaryMetaFormat.parse(string) val result = BinaryMetaFormat.parse(string)
assertEquals(meta, result) assertEquals(meta, result)
} }
@Test @Test
fun testJsonMetaFormat(){ fun testJsonMetaFormat() {
val meta = buildMeta { val meta = buildMeta {
"a" to 22 "a" to 22
"node" to { "node" to {
@ -30,7 +30,7 @@ class MetaFormatTest{
} }
val string = meta.asString(JsonMetaFormat) val string = meta.asString(JsonMetaFormat)
val result = JsonMetaFormat.parse(string) val result = JsonMetaFormat.parse(string)
assertEquals(meta,result) assertEquals(meta, result)
} }
} }

View File

@ -11,25 +11,29 @@ import kotlin.reflect.KProperty
//TODO add caching for sealed nodes //TODO add caching for sealed nodes
class ValueDelegate(private val key: String? = null, private val default: Value? = null) : ReadOnlyProperty<Metoid, Value?> { class ValueDelegate(private val key: String? = null, private val default: Value? = null) :
ReadOnlyProperty<Metoid, Value?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? { override fun getValue(thisRef: Metoid, property: KProperty<*>): Value? {
return thisRef.meta[key ?: property.name]?.value ?: default return thisRef.meta[key ?: property.name]?.value ?: default
} }
} }
class StringDelegate(private val key: String? = null, private val default: String? = null) : ReadOnlyProperty<Metoid, String?> { class StringDelegate(private val key: String? = null, private val default: String? = null) :
ReadOnlyProperty<Metoid, String?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): String? { override fun getValue(thisRef: Metoid, property: KProperty<*>): String? {
return thisRef.meta[key ?: property.name]?.string ?: default return thisRef.meta[key ?: property.name]?.string ?: default
} }
} }
class BooleanDelegate(private val key: String? = null, private val default: Boolean? = null) : ReadOnlyProperty<Metoid, Boolean?> { class BooleanDelegate(private val key: String? = null, private val default: Boolean? = null) :
ReadOnlyProperty<Metoid, Boolean?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean? { override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean? {
return thisRef.meta[key ?: property.name]?.boolean ?: default return thisRef.meta[key ?: property.name]?.boolean ?: default
} }
} }
class NumberDelegate(private val key: String? = null, private val default: Number? = null) : ReadOnlyProperty<Metoid, Number?> { class NumberDelegate(private val key: String? = null, private val default: Number? = null) :
ReadOnlyProperty<Metoid, Number?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Number? { override fun getValue(thisRef: Metoid, property: KProperty<*>): Number? {
return thisRef.meta[key ?: property.name]?.number ?: default return thisRef.meta[key ?: property.name]?.number ?: default
} }
@ -37,25 +41,32 @@ class NumberDelegate(private val key: String? = null, private val default: Numbe
//Delegates with non-null values //Delegates with non-null values
class SafeStringDelegate(private val key: String? = null, private val default: String) : ReadOnlyProperty<Metoid, String> { class SafeStringDelegate(private val key: String? = null, private val default: String) :
ReadOnlyProperty<Metoid, String> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): String { override fun getValue(thisRef: Metoid, property: KProperty<*>): String {
return thisRef.meta[key ?: property.name]?.string ?: default return thisRef.meta[key ?: property.name]?.string ?: default
} }
} }
class SafeBooleanDelegate(private val key: String? = null, private val default: Boolean) : ReadOnlyProperty<Metoid, Boolean> { class SafeBooleanDelegate(private val key: String? = null, private val default: Boolean) :
ReadOnlyProperty<Metoid, Boolean> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean { override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean {
return thisRef.meta[key ?: property.name]?.boolean ?: default return thisRef.meta[key ?: property.name]?.boolean ?: default
} }
} }
class SafeNumberDelegate(private val key: String? = null, private val default: Number) : ReadOnlyProperty<Metoid, Number> { class SafeNumberDelegate(private val key: String? = null, private val default: Number) :
ReadOnlyProperty<Metoid, Number> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Number { override fun getValue(thisRef: Metoid, property: KProperty<*>): Number {
return thisRef.meta[key ?: property.name]?.number ?: default return thisRef.meta[key ?: property.name]?.number ?: default
} }
} }
class SafeEnumDelegate<E : Enum<E>>(private val key: String? = null, private val default: E, private val resolver: (String) -> E) : ReadOnlyProperty<Metoid, E> { class SafeEnumDelegate<E : Enum<E>>(
private val key: String? = null,
private val default: E,
private val resolver: (String) -> E
) : ReadOnlyProperty<Metoid, E> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): E { override fun getValue(thisRef: Metoid, property: KProperty<*>): E {
return (thisRef.meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default return (thisRef.meta[key ?: property.name]?.string)?.let { resolver(it) } ?: default
} }
@ -63,9 +74,10 @@ class SafeEnumDelegate<E : Enum<E>>(private val key: String? = null, private val
//Child node delegate //Child node delegate
class ChildDelegate<T>(private val key: String? = null, private val converter: (Meta) -> T) : ReadOnlyProperty<Metoid, T?> { class ChildDelegate<T>(private val key: String? = null, private val converter: (Meta) -> T) :
ReadOnlyProperty<Metoid, T?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): T? { override fun getValue(thisRef: Metoid, property: KProperty<*>): T? {
return thisRef.meta[key ?: property.name]?.node?.let { converter(it)} return thisRef.meta[key ?: property.name]?.node?.let { converter(it) }
} }
} }
@ -95,18 +107,20 @@ fun Metoid.boolean(default: Boolean, key: String? = null) = SafeBooleanDelegate(
@JvmName("safeNumber") @JvmName("safeNumber")
fun Metoid.number(default: Number, key: String? = null) = SafeNumberDelegate(key, default) fun Metoid.number(default: Number, key: String? = null) = SafeNumberDelegate(key, default)
inline fun <reified E : Enum<E>> Metoid.enum(default: E, key: String? = null) = SafeEnumDelegate(key, default) { enumValueOf(it) } inline fun <reified E : Enum<E>> Metoid.enum(default: E, key: String? = null) =
SafeEnumDelegate(key, default) { enumValueOf(it) }
/* Config delegates */ /* Config delegates */
class ValueConfigDelegate(private val key: String? = null, private val default: Value? = null) : ReadWriteProperty<Configurable, Value?> { class ValueConfigDelegate(private val key: String? = null, private val default: Value? = null) :
ReadWriteProperty<Configurable, Value?> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): Value? { override fun getValue(thisRef: Configurable, property: KProperty<*>): Value? {
return thisRef.config[key ?: property.name]?.value ?: default return thisRef.config[key ?: property.name]?.value ?: default
} }
override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Value?) { override fun setValue(thisRef: Configurable, property: KProperty<*>, value: Value?) {
val name = key ?: property.name val name = key ?: property.name
if(value == null){ if (value == null) {
thisRef.config.remove(name) thisRef.config.remove(name)
} else { } else {
thisRef.config[name] = value thisRef.config[name] = value
@ -114,7 +128,8 @@ class ValueConfigDelegate(private val key: String? = null, private val default:
} }
} }
class StringConfigDelegate(private val key: String? = null, private val default: String? = null) : ReadWriteProperty<Configurable, String?> { class StringConfigDelegate(private val key: String? = null, private val default: String? = null) :
ReadWriteProperty<Configurable, String?> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): String? { override fun getValue(thisRef: Configurable, property: KProperty<*>): String? {
return thisRef.config[key ?: property.name]?.string ?: default return thisRef.config[key ?: property.name]?.string ?: default
} }
@ -124,7 +139,8 @@ class StringConfigDelegate(private val key: String? = null, private val default:
} }
} }
class BooleanConfigDelegate(private val key: String? = null, private val default: Boolean? = null) : ReadWriteProperty<Configurable, Boolean?> { class BooleanConfigDelegate(private val key: String? = null, private val default: Boolean? = null) :
ReadWriteProperty<Configurable, Boolean?> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean? { override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean? {
return thisRef.config[key ?: property.name]?.boolean ?: default return thisRef.config[key ?: property.name]?.boolean ?: default
} }
@ -134,7 +150,8 @@ class BooleanConfigDelegate(private val key: String? = null, private val default
} }
} }
class NumberConfigDelegate(private val key: String? = null, private val default: Number? = null) : ReadWriteProperty<Configurable, Number?> { class NumberConfigDelegate(private val key: String? = null, private val default: Number? = null) :
ReadWriteProperty<Configurable, Number?> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): Number? { override fun getValue(thisRef: Configurable, property: KProperty<*>): Number? {
return thisRef.config[key ?: property.name]?.number ?: default return thisRef.config[key ?: property.name]?.number ?: default
} }
@ -146,7 +163,8 @@ class NumberConfigDelegate(private val key: String? = null, private val default:
//Delegates with non-null values //Delegates with non-null values
class SafeStringConfigDelegate(private val key: String? = null, private val default: String) : ReadWriteProperty<Configurable, String> { class SafeStringConfigDelegate(private val key: String? = null, private val default: String) :
ReadWriteProperty<Configurable, String> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): String { override fun getValue(thisRef: Configurable, property: KProperty<*>): String {
return thisRef.config[key ?: property.name]?.string ?: default return thisRef.config[key ?: property.name]?.string ?: default
} }
@ -156,7 +174,8 @@ class SafeStringConfigDelegate(private val key: String? = null, private val defa
} }
} }
class SafeBooleanConfigDelegate(private val key: String? = null, private val default: Boolean) : ReadWriteProperty<Configurable, Boolean> { class SafeBooleanConfigDelegate(private val key: String? = null, private val default: Boolean) :
ReadWriteProperty<Configurable, Boolean> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean { override fun getValue(thisRef: Configurable, property: KProperty<*>): Boolean {
return thisRef.config[key ?: property.name]?.boolean ?: default return thisRef.config[key ?: property.name]?.boolean ?: default
} }
@ -166,7 +185,8 @@ class SafeBooleanConfigDelegate(private val key: String? = null, private val def
} }
} }
class SafeNumberConfigDelegate(private val key: String? = null, private val default: Number) : ReadWriteProperty<Configurable, Number> { class SafeNumberConfigDelegate(private val key: String? = null, private val default: Number) :
ReadWriteProperty<Configurable, Number> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): Number { override fun getValue(thisRef: Configurable, property: KProperty<*>): Number {
return thisRef.config[key ?: property.name]?.number ?: default return thisRef.config[key ?: property.name]?.number ?: default
} }
@ -176,7 +196,11 @@ class SafeNumberConfigDelegate(private val key: String? = null, private val defa
} }
} }
class SafeEnumvConfigDelegate<E : Enum<E>>(private val key: String? = null, private val default: E, private val resolver: (String) -> E) : ReadWriteProperty<Configurable, E> { class SafeEnumvConfigDelegate<E : Enum<E>>(
private val key: String? = null,
private val default: E,
private val resolver: (String) -> E
) : ReadWriteProperty<Configurable, E> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): E { override fun getValue(thisRef: Configurable, property: KProperty<*>): E {
return (thisRef.config[key ?: property.name]?.string)?.let { resolver(it) } ?: default return (thisRef.config[key ?: property.name]?.string)?.let { resolver(it) } ?: default
} }
@ -188,7 +212,8 @@ class SafeEnumvConfigDelegate<E : Enum<E>>(private val key: String? = null, priv
//Child node delegate //Child node delegate
class ChildConfigDelegate<T : Configurable>(private val key: String? = null, private val converter: (Config) -> T) : ReadWriteProperty<Configurable, T> { class ChildConfigDelegate<T : Configurable>(private val key: String? = null, private val converter: (Config) -> T) :
ReadWriteProperty<Configurable, T> {
override fun getValue(thisRef: Configurable, property: KProperty<*>): T { override fun getValue(thisRef: Configurable, property: KProperty<*>): T {
return converter(thisRef.config[key ?: property.name]?.node ?: Config()) return converter(thisRef.config[key ?: property.name]?.node ?: Config())
} }
@ -214,7 +239,8 @@ fun Configurable.number(default: Number? = null, key: String? = null) = NumberCo
fun Configurable.child(key: String? = null) = ChildConfigDelegate(key) { SimpleConfigurable(it) } fun Configurable.child(key: String? = null) = ChildConfigDelegate(key) { SimpleConfigurable(it) }
fun <T : Configurable> Configurable.child(key: String? = null, converter: (Config) -> T) = ChildConfigDelegate(key, converter) fun <T : Configurable> Configurable.child(key: String? = null, converter: (Config) -> T) =
ChildConfigDelegate(key, converter)
//fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) } //fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: String? = null) = ChildConfigDelegate<T>(key) { spec.wrap(this) }
@ -227,4 +253,5 @@ fun Configurable.boolean(default: Boolean, key: String? = null) = SafeBooleanCon
@JvmName("safeNumber") @JvmName("safeNumber")
fun Configurable.number(default: Number, key: String? = null) = SafeNumberConfigDelegate(key, default) fun Configurable.number(default: Number, key: String? = null) = SafeNumberConfigDelegate(key, default)
inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) = SafeEnumvConfigDelegate(key, default) { enumValueOf(it) } inline fun <reified E : Enum<E>> Configurable.enum(default: E, key: String? = null) =
SafeEnumvConfigDelegate(key, default) { enumValueOf(it) }

View File

@ -10,14 +10,14 @@ import hep.dataforge.names.NameToken
class Laminate(layers: List<Meta>) : Meta { class Laminate(layers: List<Meta>) : Meta {
val layers: List<Meta> = layers.flatMap { val layers: List<Meta> = layers.flatMap {
if(it is Laminate){ if (it is Laminate) {
it.layers it.layers
} else{ } else {
listOf(it) listOf(it)
} }
} }
constructor(vararg layers: Meta): this(layers.asList()) constructor(vararg layers: Meta) : this(layers.asList())
override val items: Map<NameToken, MetaItem<out Meta>> override val items: Map<NameToken, MetaItem<out Meta>>
get() = layers.map { it.items.keys }.flatten().associateWith { key -> get() = layers.map { it.items.keys }.flatten().associateWith { key ->

View File

@ -77,9 +77,9 @@ fun Meta.getAll(name: Name): Map<String, MetaItem<out Meta>> {
val (body, query) = name.last()!! val (body, query) = name.last()!!
val regex = query.toRegex() val regex = query.toRegex()
return (this[name.cutLast()] as? NodeItem<*>)?.node?.items return (this[name.cutLast()] as? NodeItem<*>)?.node?.items
?.filter { it.key.body == body && (query.isEmpty() || regex.matches(it.key.query)) } ?.filter { it.key.body == body && (query.isEmpty() || regex.matches(it.key.query)) }
?.mapKeys { it.key.query } ?.mapKeys { it.key.query }
?: emptyMap() ?: emptyMap()
} }
@ -155,8 +155,8 @@ object EmptyMeta : Meta {
val MetaItem<*>.value val MetaItem<*>.value
get() = (this as? MetaItem.ValueItem)?.value get() = (this as? MetaItem.ValueItem)?.value
?: (this.node[VALUE_KEY] as? MetaItem.ValueItem)?.value ?: (this.node[VALUE_KEY] as? MetaItem.ValueItem)?.value
?: error("Trying to interpret node meta item as value item") ?: error("Trying to interpret node meta item as value item")
val MetaItem<*>.string get() = value.string val MetaItem<*>.string get() = value.string
val MetaItem<*>.boolean get() = value.boolean val MetaItem<*>.boolean get() = value.boolean
val MetaItem<*>.number get() = value.number val MetaItem<*>.number get() = value.number

View File

@ -6,7 +6,10 @@ import hep.dataforge.names.plus
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.values.Value import hep.dataforge.values.Value
class MetaListener(val owner: Any? = null, val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit) { class MetaListener(
val owner: Any? = null,
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
) {
operator fun invoke(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) = action(name, oldItem, newItem) operator fun invoke(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) = action(name, oldItem, newItem)
} }
@ -87,7 +90,7 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : MetaNode<M>(), MutableM
val token = name.first()!! val token = name.first()!!
//get existing or create new node. Query is ignored for new node //get existing or create new node. Query is ignored for new node
val child = this.items[token]?.node val child = this.items[token]?.node
?: empty().also { this[token.body.toName()] = MetaItem.NodeItem(it) } ?: empty().also { this[token.body.toName()] = MetaItem.NodeItem(it) }
child[name.cutFirst()] = item child[name.cutFirst()] = item
} }
} }
@ -130,16 +133,20 @@ fun <M : MutableMetaNode<M>> M.update(meta: Meta) {
meta.items.forEach { entry -> meta.items.forEach { entry ->
val value = entry.value val value = entry.value
when (value) { when (value) {
is MetaItem.ValueItem -> setValue(entry.key.toName(),value.value) is MetaItem.ValueItem -> setValue(entry.key.toName(), value.value)
is MetaItem.NodeItem -> (this[entry.key.toName()] as? MetaItem.NodeItem)?.node?.update(value.node) is MetaItem.NodeItem -> (this[entry.key.toName()] as? MetaItem.NodeItem)?.node?.update(value.node)
?: run { setNode(entry.key.toName(),value.node)} ?: run { setNode(entry.key.toName(), value.node) }
} }
} }
} }
/* Same name siblings generation */ /* Same name siblings generation */
fun <M : MutableMeta<M>> M.setIndexed(name: Name, items: Iterable<MetaItem<M>>, queryFactory: (Int) -> String = { it.toString() }) { fun <M : MutableMeta<M>> M.setIndexed(
name: Name,
items: Iterable<MetaItem<M>>,
queryFactory: (Int) -> String = { it.toString() }
) {
val tokens = name.tokens.toMutableList() val tokens = name.tokens.toMutableList()
val last = tokens.last() val last = tokens.last()
items.forEachIndexed { index, meta -> items.forEachIndexed { index, meta ->
@ -149,7 +156,11 @@ fun <M : MutableMeta<M>> M.setIndexed(name: Name, items: Iterable<MetaItem<M>>,
} }
} }
fun <M : MutableMetaNode<M>> M.setIndexed(name: Name, metas: Iterable<Meta>, queryFactory: (Int) -> String = { it.toString() }) { fun <M : MutableMetaNode<M>> M.setIndexed(
name: Name,
metas: Iterable<Meta>,
queryFactory: (Int) -> String = { it.toString() }
) {
setIndexed(name, metas.map { wrap(name, it) }, queryFactory) setIndexed(name, metas.map { wrap(name, it) }, queryFactory)
} }

View File

@ -3,7 +3,7 @@ package hep.dataforge.meta
/** /**
* Marker interface for specifications * Marker interface for specifications
*/ */
interface Specification: Configurable{ interface Specification : Configurable {
operator fun get(name: String): MetaItem<Config>? = config[name] operator fun get(name: String): MetaItem<Config>? = config[name]
} }
@ -26,24 +26,29 @@ interface SpecificationBuilder<T : Specification> {
fun wrap(meta: Meta): T = wrap(meta.toConfig()) fun wrap(meta: Meta): T = wrap(meta.toConfig())
} }
fun <T : Specification> specification(wrapper: (Config) -> T): SpecificationBuilder<T> = object : SpecificationBuilder<T> { fun <T : Specification> specification(wrapper: (Config) -> T): SpecificationBuilder<T> =
override fun wrap(config: Config): T = wrapper(config) object : SpecificationBuilder<T> {
} override fun wrap(config: Config): T = wrapper(config)
}
/** /**
* Apply specified configuration to configurable * Apply specified configuration to configurable
*/ */
fun <T : Configurable, C : Specification, S : SpecificationBuilder<C>> T.configure(spec: S, action: C.() -> Unit) = apply { spec.update(config, action) } fun <T : Configurable, C : Specification, S : SpecificationBuilder<C>> T.configure(spec: S, action: C.() -> Unit) =
apply { spec.update(config, action) }
/** /**
* Update configuration using given specification * Update configuration using given specification
*/ */
fun <C : Specification, S : SpecificationBuilder<C>> Specification.update(spec: S, action: C.() -> Unit) = apply { spec.update(config, action) } fun <C : Specification, S : SpecificationBuilder<C>> Specification.update(spec: S, action: C.() -> Unit) =
apply { spec.update(config, action) }
/** /**
* Create a style based on given specification * Create a style based on given specification
*/ */
fun <C : Specification, S : SpecificationBuilder<C>> S.createStyle(action: C.() -> Unit): Meta = Config().also { update(it, action) } fun <C : Specification, S : SpecificationBuilder<C>> S.createStyle(action: C.() -> Unit): Meta =
Config().also { update(it, action) }
fun <C : Specification> Specification.spec(spec: SpecificationBuilder<C>, key: String? = null) = ChildConfigDelegate<C>(key) { spec.wrap(config) } fun <C : Specification> Specification.spec(spec: SpecificationBuilder<C>, key: String? = null) =
ChildConfigDelegate<C>(key) { spec.wrap(config) }

View File

@ -44,7 +44,7 @@ class StyledConfig(val config: Config, style: Meta = EmptyMeta) : Config() {
} }
is MetaItem.ValueItem -> MetaItem.ValueItem(value.value) is MetaItem.ValueItem -> MetaItem.ValueItem(value.value)
is MetaItem.NodeItem -> MetaItem.NodeItem( is MetaItem.NodeItem -> MetaItem.NodeItem(
StyledConfig(value.node, styleValue?.node ?: EmptyMeta) StyledConfig(value.node, styleValue?.node ?: EmptyMeta)
) )
} }
key to item key to item

View File

@ -5,12 +5,12 @@ import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class MetaBuilderTest{ class MetaBuilderTest {
@Test @Test
fun testBuilder(){ fun testBuilder() {
val meta = buildMeta { val meta = buildMeta {
"a" to 22 "a" to 22
"b" to listOf(1,2,3) "b" to listOf(1, 2, 3)
this["c"] = "myValue".asValue() this["c"] = "myValue".asValue()
"node" to { "node" to {
"e" to 12.2 "e" to 12.2

View File

@ -3,17 +3,17 @@ package hep.dataforge.names
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class NameTest{ class NameTest {
@Test @Test
fun simpleName(){ fun simpleName() {
val name = "token1.token2.token3".toName() val name = "token1.token2.token3".toName()
assertEquals("token2", name[1].toString()) assertEquals("token2", name[1].toString())
} }
@Test @Test
fun equalityTest(){ fun equalityTest() {
val name1 = "token1.token2[2].token3".toName() val name1 = "token1.token2[2].token3".toName()
val name2 = "token1".toName() + "token2[2].token3" val name2 = "token1".toName() + "token2[2].token3"
assertEquals(name1,name2) assertEquals(name1, name2)
} }
} }

View File

@ -9,9 +9,9 @@ pluginManagement {
rootProject.name = "dataforge-core" rootProject.name = "dataforge-core"
include( include(
":dataforge-meta", ":dataforge-meta",
":dataforge-meta-io", ":dataforge-meta-io",
":dataforge-context", ":dataforge-context",
":dataforge-data", ":dataforge-data",
":dataforge-io" ":dataforge-io"
) )