From 73b3bbe7fcec4239bce85d52c3ff1d9b6a8845be Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Thu, 8 Jul 2021 12:15:34 +0300 Subject: [PATCH] Immutable plugin manager --- CHANGELOG.md | 3 + build.gradle.kts | 2 +- .../kscience/dataforge/context/Context.kt | 3 +- .../dataforge/context/ContextBuilder.kt | 28 +++- .../kscience/dataforge/context/Global.kt | 2 +- .../dataforge/context/PluginManager.kt | 68 +-------- .../space/kscience/dataforge/meta/Config.kt | 110 --------------- .../kscience/dataforge/meta/Configurable.kt | 8 +- .../dataforge/meta/ObservableItemProvider.kt | 133 +++++++++++++++++- .../space/kscience/dataforge/meta/Scheme.kt | 28 ++-- .../meta/descriptors/ItemDescriptor.kt | 8 +- .../meta/descriptors/NodeDescriptor.kt | 16 +-- .../meta/descriptors/ValueDescriptor.kt | 8 +- .../transformations/MetaTransformation.kt | 4 +- .../kscience/dataforge/meta/ConfigTest.kt | 2 +- .../dataforge/meta/MutableMetaTest.kt | 2 +- .../kscience/dataforge/meta/SchemeTest.kt | 4 +- .../dataforge/meta/SpecificationTest.kt | 6 +- .../kscience/dataforge/scripting/Builders.kt | 4 +- .../dataforge/scripting/BuildersKtTest.kt | 4 +- .../dataforge/workspace/WorkspaceBuilder.kt | 5 +- 21 files changed, 207 insertions(+), 241 deletions(-) delete mode 100644 dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Config.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index df34ec50..efa70834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,17 @@ - Experimental `listOfSpec` delegate. ### Changed +- **API breaking** Config is deprecated, use `ObservableMeta` instead. - **API breaking** Descriptor no has a member property `defaultValue` instead of `defaultItem()` extension. It caches default value state on the first call. It is done because computing default on each call is too expensive. - Kotlin 1.5.10 - Build tools 0.10.0 - Relaxed type restriction on `MetaConverter`. Now nullables are available. ### Deprecated +- Direct use of `Config` ### Removed +- Public PluginManager mutability ### Fixed - Proper json array index treatment diff --git a/build.gradle.kts b/build.gradle.kts index 3c9b82ac..8cf2014a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { allprojects { group = "space.kscience" - version = "0.4.4-dev-1" + version = "0.5.0-dev-1" } subprojects { diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt index 2451048d..3c2cf28b 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt @@ -26,6 +26,7 @@ import kotlin.jvm.Synchronized public open class Context internal constructor( final override val name: Name, public val parent: Context?, + plugins: Set, meta: Meta, ) : Named, MetaRepr, Provider, CoroutineScope { @@ -42,7 +43,7 @@ public open class Context internal constructor( /** * A [PluginManager] for current context */ - public val plugins: PluginManager by lazy { PluginManager(this) } + public val plugins: PluginManager by lazy { PluginManager(this, plugins) } override val defaultTarget: String get() = Plugin.TARGET diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt index 30005912..52db8dae 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt @@ -64,12 +64,32 @@ public class ContextBuilder internal constructor( public fun build(): Context { val contextName = name ?: "@auto[${hashCode().toUInt().toString(16)}]".toName() - return Context(contextName, parent, meta.seal()).apply { - factories.forEach { (factory, meta) -> - @Suppress("DEPRECATION") - plugins.fetch(factory, meta) + val plugins = HashMap() + + fun addPlugin(factory: PluginFactory<*>, meta: Meta) { + val existing = plugins[factory.tag] + // Add if does not exist + if (existing == null) { + //TODO bypass if parent already has plugin with given meta? + val plugin = factory(meta, parent) + + for ((depFactory, deoMeta) in plugin.dependsOn()) { + addPlugin(depFactory, deoMeta) + } + + parent.logger.info { "Loading plugin ${plugin.name} into $contextName" } + plugins[plugin.tag] = plugin + } else if (existing.meta != meta) { + error("Plugin with tag ${factory.tag} and meta $meta already exists in $contextName") } + //bypass if exists with the same meta } + + factories.forEach { (factory, meta) -> + addPlugin(factory, meta) + } + + return Context(contextName, parent, plugins.values.toSet(), meta.seal()) } } diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Global.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Global.kt index 59450fdb..9ace5800 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Global.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Global.kt @@ -13,7 +13,7 @@ internal expect val globalLoggerFactory: PluginFactory * A global root context. Closing [Global] terminates the framework. */ @ThreadLocal -private object GlobalContext : Context("GLOBAL".asName(), null, Meta.EMPTY) { +private object GlobalContext : Context("GLOBAL".asName(), null, emptySet(), Meta.EMPTY) { override val coroutineContext: CoroutineContext = Job() + CoroutineName("GlobalContext") } diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/PluginManager.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/PluginManager.kt index 748c2359..81d455c7 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/PluginManager.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/PluginManager.kt @@ -1,7 +1,6 @@ package space.kscience.dataforge.context import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.MetaBuilder import kotlin.reflect.KClass @@ -11,12 +10,10 @@ import kotlin.reflect.KClass * @property context A context for this plugin manager * @author Alexander Nozik */ -public class PluginManager(override val context: Context) : ContextAware, Iterable { - - /** - * A set of loaded plugins - */ - private val plugins: HashSet = HashSet() +public class PluginManager internal constructor( + override val context: Context, + private val plugins: Set +) : ContextAware, Iterable { init { plugins.forEach { it.attach(context) } @@ -76,64 +73,7 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab public inline operator fun get(factory: PluginFactory, recursive: Boolean = true): T? = get(factory.type, factory.tag, recursive) - /** - * Load given plugin into this manager and return loaded instance. - * Throw error if plugin of the same type and tag already exists in manager. - * - * @param plugin - * @return - */ - private fun load(plugin: T): T { - if (get(plugin::class, plugin.tag, recursive = false) != null) { - error("Plugin with tag ${plugin.tag} already exists in ${context.name}") - } else { - for ((factory, meta) in plugin.dependsOn()) { - @Suppress("DEPRECATION") - fetch(factory, meta, true) - } - - logger.info { "Loading plugin ${plugin.name} into ${context.name}" } - plugin.attach(context) - plugins.add(plugin) - return plugin - } - } - - - /** - * Remove a plugin from [PluginManager] - */ - @Deprecated("Use immutable contexts instead") - public fun remove(plugin: Plugin) { - if (plugins.contains(plugin)) { - Global.logger.info { "Removing plugin ${plugin.name} from ${context.name}" } - plugin.detach() - plugins.remove(plugin) - } - } - - /** - * Get an existing plugin with given meta or load new one using provided factory - */ - @Deprecated("Use immutable contexts instead") - public fun fetch(factory: PluginFactory, meta: Meta = Meta.EMPTY, recursive: Boolean = true): T { - val loaded = get(factory.type, factory.tag, recursive) - return when { - loaded == null -> load(factory(meta, context)) - loaded.meta == meta -> loaded // if meta is the same, return existing plugin - else -> throw RuntimeException("Can't load plugin with tag ${factory.tag}. Plugin with this tag and different configuration already exists in context.") - } - } - - @Deprecated("Use immutable contexts instead") - public fun fetch( - factory: PluginFactory, - recursive: Boolean = true, - metaBuilder: MetaBuilder.() -> Unit, - ): T = fetch(factory, Meta(metaBuilder), recursive) - override fun iterator(): Iterator = plugins.iterator() - } /** diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Config.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Config.kt deleted file mode 100644 index 14beb87b..00000000 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Config.kt +++ /dev/null @@ -1,110 +0,0 @@ -package space.kscience.dataforge.meta - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.NameToken -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.plus -import kotlin.collections.set -import kotlin.jvm.Synchronized - -//TODO add validator to configuration - -/** - * Mutable meta representing object state - */ -@Serializable(Config.Companion::class) -public class Config : AbstractMutableMeta(), ItemPropertyProvider { - - private val listeners = HashSet() - - @Synchronized - private fun itemChanged(name: Name, oldItem: MetaItem?, newItem: MetaItem?) { - listeners.forEach { it.action(name, oldItem, newItem) } - } - - /** - * Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed - */ - @Synchronized - override fun onChange(owner: Any?, action: (Name, MetaItem?, MetaItem?) -> Unit) { - listeners.add(ItemListener(owner, action)) - } - - /** - * Remove all listeners belonging to given owner - */ - @Synchronized - override fun removeListener(owner: Any?) { - listeners.removeAll { it.owner === owner } - } - - override fun replaceItem(key: NameToken, oldItem: TypedMetaItem?, newItem: TypedMetaItem?) { - if (newItem == null) { - children.remove(key) - if (oldItem != null && oldItem is MetaItemNode) { - oldItem.node.removeListener(this) - } - } else { - children[key] = newItem - if (newItem is MetaItemNode) { - newItem.node.onChange(this) { name, oldChild, newChild -> - itemChanged(key + name, oldChild, newChild) - } - } - } - itemChanged(key.asName(), oldItem, newItem) - } - - /** - * Attach configuration node instead of creating one - */ - override fun wrapNode(meta: Meta): Config = meta.asConfig() - - override fun empty(): Config = Config() - - public companion object ConfigSerializer : KSerializer { - - public fun empty(): Config = Config() - override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor - - override fun deserialize(decoder: Decoder): Config { - return MetaSerializer.deserialize(decoder).asConfig() - } - - override fun serialize(encoder: Encoder, value: Config) { - MetaSerializer.serialize(encoder, value) - } - } -} - -public operator fun Config.get(token: NameToken): TypedMetaItem? = items[token] - -/** - * Create a mutable copy of this [Meta]. The copy is created event if initial [Meta] is a [Config]. - * Listeners are not preserved - */ -public fun Meta.toConfig(): Config = Config().also { builder -> - this.items.mapValues { entry -> - val item = entry.value - builder[entry.key.asName()] = when (item) { - is MetaItemValue -> item.value - is MetaItemNode -> MetaItemNode(item.node.asConfig()) - } - } -} - -/** - * Create a copy of this config, optionally applying the given [block]. - * The listeners of the original Config are not retained. - */ -public inline fun Config.copy(block: Config.() -> Unit = {}): Config = toConfig().apply(block) - -/** - * Return this [Meta] as [Config] if it is [Config] and create a new copy otherwise - */ -public fun Meta.asConfig(): Config = this as? Config ?: toConfig() \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Configurable.kt index 3f4b154e..dbd22f21 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Configurable.kt @@ -5,21 +5,21 @@ import space.kscience.dataforge.names.Name import kotlin.properties.ReadWriteProperty /** - * A container that holds a [Config]. + * A container that holds a [ObservableMeta]. */ public interface Configurable { /** * Backing config */ - public val config: Config + public val config: ObservableMeta } public fun T.configure(meta: Meta): T = this.apply { config.update(meta) } @DFBuilder -public inline fun T.configure(action: Config.() -> Unit): T = apply { config.apply(action) } +public inline fun T.configure(action: ObservableMeta.() -> Unit): T = apply { config.apply(action) } /* Node delegates */ -public fun Configurable.config(key: Name? = null): ReadWriteProperty = config.node(key) +public fun Configurable.config(key: Name? = null): ReadWriteProperty = config.node(key) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableItemProvider.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableItemProvider.kt index b6dc78e7..331c333e 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableItemProvider.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableItemProvider.kt @@ -1,9 +1,14 @@ package space.kscience.dataforge.meta +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.startsWith +import space.kscience.dataforge.names.* +import kotlin.js.JsName +import kotlin.jvm.Synchronized import kotlin.reflect.KProperty1 @@ -12,13 +17,105 @@ internal data class ItemListener( val action: (name: Name, oldItem: MetaItem?, newItem: MetaItem?) -> Unit, ) - -public interface ObservableItemProvider : ItemProvider { +/** + * An item provider that could be observed and mutated + */ +public interface ObservableItemProvider : ItemProvider, MutableItemProvider { + /** + * Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed + */ public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem?, newItem: MetaItem?) -> Unit) + + /** + * Remove all listeners belonging to given owner + */ public fun removeListener(owner: Any?) } -public interface ItemPropertyProvider: ObservableItemProvider, MutableItemProvider +private open class ObservableItemProviderWrapper( + open val itemProvider: MutableItemProvider, + open val parent: Pair? = null +) : ObservableItemProvider { + + override fun getItem(name: Name): MetaItem? = itemProvider.getItem(name) + + private val listeners = HashSet() + + @Synchronized + private fun itemChanged(name: Name, oldItem: MetaItem?, newItem: MetaItem?) { + listeners.forEach { it.action(name, oldItem, newItem) } + } + + override fun setItem(name: Name, item: MetaItem?) { + val oldItem = getItem(name) + itemProvider.setItem(name, item) + itemChanged(name, oldItem, item) + + //Recursively send update to parent listeners + parent?.let { (parentNode, token) -> + parentNode.itemChanged(token + name, oldItem, item) + } + } + + @Synchronized + override fun onChange(owner: Any?, action: (Name, MetaItem?, MetaItem?) -> Unit) { + listeners.add(ItemListener(owner, action)) + } + + @Synchronized + override fun removeListener(owner: Any?) { + listeners.removeAll { it.owner === owner } + } +} + +public fun MutableItemProvider.asObservable(): ObservableItemProvider = + (this as? ObservableItemProvider) ?: ObservableItemProviderWrapper(this) + +/** + * A Meta instance that could be both mutated and observed. + */ +@Serializable(ObservableMetaSerializer::class) +public interface ObservableMeta : ObservableItemProvider, MutableMeta + +/** + * A wrapper class that creates observable meta node from regular meta node + */ +private class ObservableMetaWrapper>( + override val itemProvider: M, + override val parent: Pair, Name>? = null +) : ObservableItemProviderWrapper(itemProvider, parent), ObservableMeta { + override fun equals(other: Any?): Boolean = (itemProvider == other) + + override fun hashCode(): Int = itemProvider.hashCode() + + override fun toString(): String = itemProvider.toString() + + private fun wrapItem(name: Name, item: TypedMetaItem): TypedMetaItem { + return when (item) { + is MetaItemValue -> item + is MetaItemNode -> ObservableMetaWrapper(item.node, this to name).asMetaItem() + } + } + + override fun getItem(name: Name): TypedMetaItem? = itemProvider[name]?.let { + wrapItem(name, it) + } + + override val items: Map> + get() = itemProvider.items.mapValues { (token, childItem: TypedMetaItem) -> + wrapItem(token.asName(), childItem) + } +} + +/** + * If this meta is observable return itself. Otherwise return an observable wrapper. The changes of initial meta are + * reflected on wrapper but are **NOT** observed. + */ +public fun > M.asObservable(): ObservableMeta = + (this as? ObservableMeta) ?: ObservableMetaWrapper(this) + +@JsName("buildObservableMeta") +public fun ObservableMeta(): ObservableMeta = MetaBuilder().asObservable() /** * Use the value of the property in a [callBack]. @@ -39,4 +136,26 @@ public fun O.useProperty( callBack(property.get(this)) } } -} \ No newline at end of file +} + +public object ObservableMetaSerializer : KSerializer { + public fun empty(): ObservableMeta = ObservableMeta() + override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor + + override fun deserialize(decoder: Decoder): ObservableMeta { + return MetaSerializer.deserialize(decoder).toMutableMeta().asObservable() + } + + override fun serialize(encoder: Encoder, value: ObservableMeta) { + MetaSerializer.serialize(encoder, value) + } +} + +public operator fun ObservableMeta.get(token: NameToken): TypedMetaItem? = items[token] + +/** + * Create a copy of this config, optionally applying the given [block]. + * The listeners of the original Config are not retained. + */ +public inline fun ObservableMeta.copy(block: ObservableMeta.() -> Unit = {}): ObservableMeta = + asObservable().apply(block) \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt index c8118954..2edc3ab3 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt @@ -13,16 +13,11 @@ import kotlin.jvm.Synchronized * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. * Default item provider and [NodeDescriptor] are optional */ -public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { - - private var items: MutableItemProvider = Config() - - private val listeners = HashSet() - +public open class Scheme( + private var items: ObservableItemProvider = ObservableMeta(), + final override var descriptor: NodeDescriptor? = null, private var default: ItemProvider? = null - - final override var descriptor: NodeDescriptor? = null - +) : Described, MetaRepr, ObservableItemProvider, MutableItemProvider { /** * Add a listener to this scheme changes. If the inner provider is observable, then listening will be delegated to it. @@ -30,8 +25,7 @@ public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { */ @Synchronized override fun onChange(owner: Any?, action: (Name, MetaItem?, MetaItem?) -> Unit) { - (items as? ObservableItemProvider)?.onChange(owner, action) - ?: run { listeners.add(ItemListener(owner, action)) } + items.onChange(owner, action) } /** @@ -39,8 +33,7 @@ public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { */ @Synchronized override fun removeListener(owner: Any?) { - (items as? ObservableItemProvider)?.removeListener(owner) - ?: listeners.removeAll { it.owner === owner } + items.removeListener(owner) } internal fun wrap( @@ -51,11 +44,11 @@ public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { //use properties in the init block as default this.default = this.items.withDefault(default) //reset values, defaults are already saved - this.items = items + this.items = items.asObservable() this.descriptor = descriptor } - private fun getDefaultItem(name: Name): MetaItem? { + protected open fun getDefaultItem(name: Name): MetaItem? { return default?.get(name) ?: descriptor?.get(name)?.defaultValue } @@ -79,7 +72,6 @@ public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { val oldItem = items[name] if (validateItem(name, item)) { items[name] = item - listeners.forEach { it.action(name, oldItem, item) } } else { error("Validation failed for property $name with value $item") } @@ -105,7 +97,7 @@ public open class Scheme() : Described, MetaRepr, ItemPropertyProvider { } } - override fun toMeta(): Laminate = Laminate(items[Name.EMPTY].node, defaultLayer) + override fun toMeta(): Laminate = Laminate(items.rootNode, defaultLayer) } /** @@ -145,7 +137,7 @@ public open class SchemeSpec( override fun empty(): T = builder() - override fun read(items: ItemProvider): T = wrap(Config(), items, descriptor) + override fun read(items: ItemProvider): T = wrap(ObservableMeta(), items, descriptor) override fun write(target: MutableItemProvider, defaultProvider: ItemProvider): T = wrap(target, defaultProvider, descriptor) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ItemDescriptor.kt index 8e9c4d20..29e6e2dd 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ItemDescriptor.kt @@ -52,7 +52,7 @@ public sealed interface ItemDescriptor: MetaRepr { * The builder for [ItemDescriptor] */ @DFBuilder -public sealed class ItemDescriptorBuilder(final override val config: Config) : Configurable, ItemDescriptor { +public sealed class ItemDescriptorBuilder(final override val config: ObservableMeta) : Configurable, ItemDescriptor { /** * True if same name siblings with this name are allowed @@ -75,7 +75,7 @@ public sealed class ItemDescriptorBuilder(final override val config: Config) : C * * @return */ - override var attributes: Config? by config.node() + override var attributes: ObservableMeta? by config.node() /** * An index field by which this node is identified in case of same name siblings construct @@ -94,8 +94,8 @@ public sealed class ItemDescriptorBuilder(final override val config: Config) : C /** * Configure attributes of the descriptor, creating an attributes node if needed. */ -public inline fun ItemDescriptorBuilder.attributes(block: Config.() -> Unit) { - (attributes ?: Config().also { this.attributes = it }).apply(block) +public inline fun ItemDescriptorBuilder.attributes(block: ObservableMeta.() -> Unit) { + (attributes ?: ObservableMeta().also { this.attributes = it }).apply(block) } /** diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/NodeDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/NodeDescriptor.kt index 772ae221..71cb1cf9 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/NodeDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/NodeDescriptor.kt @@ -41,7 +41,7 @@ public sealed interface NodeDescriptor : ItemDescriptor { * * @return */ - public val default: Config? + public val default: Meta? /** * The map of children item descriptors (both nodes and values) @@ -74,7 +74,7 @@ public sealed interface NodeDescriptor : ItemDescriptor { @DFBuilder -public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBuilder(config), NodeDescriptor { +public class NodeDescriptorBuilder(config: ObservableMeta = ObservableMeta()) : ItemDescriptorBuilder(config), NodeDescriptor { init { config[IS_NODE_KEY] = true } @@ -91,7 +91,7 @@ public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBu * * @return */ - override var default: Config? by config.node() + override var default: ObservableMeta? by config.node() /** * The map of children item descriptors (both nodes and values) @@ -101,9 +101,9 @@ public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBu if (name == null) error("Child item index should not be null") val node = item.node ?: error("Node descriptor must be a node") if (node[IS_NODE_KEY].boolean == true) { - name to NodeDescriptorBuilder(node as Config) + name to NodeDescriptorBuilder(node as ObservableMeta) } else { - name to ValueDescriptorBuilder(node as Config) + name to ValueDescriptorBuilder(node as ObservableMeta) } } @@ -117,7 +117,7 @@ public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBu }.associate { (name, item) -> if (name == null) error("Child node index should not be null") val node = item.node ?: error("Node descriptor must be a node") - name to NodeDescriptorBuilder(node as Config) + name to NodeDescriptorBuilder(node as ObservableMeta) } /** @@ -129,7 +129,7 @@ public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBu }.associate { (name, item) -> if (name == null) error("Child value index should not be null") val node = item.node ?: error("Node descriptor must be a node") - name to ValueDescriptorBuilder(node as Config) + name to ValueDescriptorBuilder(node as ObservableMeta) } private fun buildNode(name: Name): NodeDescriptorBuilder { @@ -137,7 +137,7 @@ public class NodeDescriptorBuilder(config: Config = Config()) : ItemDescriptorBu 0 -> this 1 -> { val token = NameToken(ITEM_KEY.toString(), name.toString()) - val config: Config = config[token].node ?: Config().also { + val config: ObservableMeta = config[token].node ?: ObservableMeta().also { it[IS_NODE_KEY] = true config[token] = it } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ValueDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ValueDescriptor.kt index dd530ed2..a58248bd 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ValueDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/ValueDescriptor.kt @@ -5,7 +5,6 @@ import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.values.* - /** * A descriptor for meta value * @@ -14,7 +13,7 @@ import space.kscience.dataforge.values.* * @author Alexander Nozik */ @DFBuilder -public sealed interface ValueDescriptor: ItemDescriptor{ +public sealed interface ValueDescriptor : ItemDescriptor { /** * True if the value is required @@ -37,6 +36,7 @@ public sealed interface ValueDescriptor: ItemDescriptor{ * @return */ public val type: List? + /** * Check if given value is allowed for here. The type should be allowed and * if it is value should be within allowed values @@ -61,7 +61,9 @@ public sealed interface ValueDescriptor: ItemDescriptor{ * A builder fir [ValueDescriptor] */ @DFBuilder -public class ValueDescriptorBuilder(config: Config = Config()) : ItemDescriptorBuilder(config), ValueDescriptor { +public class ValueDescriptorBuilder( + config: ObservableMeta = ObservableMeta() +) : ItemDescriptorBuilder(config), ValueDescriptor { /** * True if the value is required diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt index 3a35dbf8..8bce8aec 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt @@ -105,7 +105,7 @@ public value class MetaTransformation(private val transformations: Collection rule.selectItems(source).forEach { name -> rule.transformItem(name, source[name], this) @@ -131,7 +131,7 @@ public value class MetaTransformation(private val transformations: Collection> bind(source: Config, target: M) { + public fun > bind(source: ObservableMeta, target: M) { source.onChange(target) { name, _, newItem -> transformations.forEach { t -> if (t.matches(name, newItem)) { diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/ConfigTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/ConfigTest.kt index 3ea8d7d3..3ec27c97 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/ConfigTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/ConfigTest.kt @@ -6,7 +6,7 @@ import kotlin.test.assertEquals class ConfigTest { @Test fun testIndexedWrite(){ - val config = Config() + val config = MetaBuilder() config["a[1].b"] = 1 assertEquals(null, config["a.b"].int) assertEquals(1, config["a[1].b"].int) diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MutableMetaTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MutableMetaTest.kt index 55a0a6de..51503f29 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MutableMetaTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MutableMetaTest.kt @@ -14,7 +14,7 @@ class MutableMetaTest{ "b" put 22 "c" put "StringValue" } - }.asConfig() + }.asObservable() meta.remove("aNode.c") assertEquals(meta["aNode.c"], null) diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt index 2b55658e..4d614d21 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt @@ -8,7 +8,7 @@ import kotlin.test.assertEquals class SchemeTest { @Test fun testSchemeWrappingBeforeEdit(){ - val config = Config() + val config = MetaBuilder() val scheme = TestScheme.wrap(config) scheme.a = 29 assertEquals(29, config["a"].int) @@ -18,7 +18,7 @@ class SchemeTest { fun testSchemeWrappingAfterEdit(){ val scheme = TestScheme.empty() scheme.a = 29 - val config = Config() + val config = MetaBuilder() scheme.retarget(config) assertEquals(29, scheme.a) } diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt index 66e749be..dfd9de19 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt @@ -13,7 +13,7 @@ internal class TestScheme : Scheme() { override fun empty(): TestScheme = TestScheme() override fun read(items: ItemProvider): TestScheme = - wrap(Config(), items) + wrap(MetaBuilder(), items) override fun write(target: MutableItemProvider, defaultProvider: ItemProvider): TestScheme = wrap(target, defaultProvider) @@ -58,7 +58,7 @@ class SpecificationTest { @Test fun testChildModification() { - val config = Config() + val config = MetaBuilder() val child = config.getChild("child") val scheme = TestScheme.write(child) scheme.a = 22 @@ -69,7 +69,7 @@ class SpecificationTest { @Test fun testChildUpdate() { - val config = Config() + val config = MetaBuilder() val child = config.getChild("child") child.update(TestScheme) { a = 22 diff --git a/dataforge-scripting/src/jvmMain/kotlin/space/kscience/dataforge/scripting/Builders.kt b/dataforge-scripting/src/jvmMain/kotlin/space/kscience/dataforge/scripting/Builders.kt index 28f05216..19c6e640 100644 --- a/dataforge-scripting/src/jvmMain/kotlin/space/kscience/dataforge/scripting/Builders.kt +++ b/dataforge-scripting/src/jvmMain/kotlin/space/kscience/dataforge/scripting/Builders.kt @@ -51,7 +51,7 @@ public object Builders { return builder.build() } - public fun buildWorkspace(file: File): Workspace = buildWorkspace(file.toScriptSource()) + public fun buildWorkspace(scriptFile: File): Workspace = buildWorkspace(scriptFile.toScriptSource()) - public fun buildWorkspace(string: String): Workspace = buildWorkspace(string.toScriptSource()) + public fun buildWorkspace(scriptString: String): Workspace = buildWorkspace(scriptString.toScriptSource()) } \ No newline at end of file diff --git a/dataforge-scripting/src/jvmTest/kotlin/space/kscience/dataforge/scripting/BuildersKtTest.kt b/dataforge-scripting/src/jvmTest/kotlin/space/kscience/dataforge/scripting/BuildersKtTest.kt index c0f557e4..36ad16fb 100644 --- a/dataforge-scripting/src/jvmTest/kotlin/space/kscience/dataforge/scripting/BuildersKtTest.kt +++ b/dataforge-scripting/src/jvmTest/kotlin/space/kscience/dataforge/scripting/BuildersKtTest.kt @@ -3,7 +3,7 @@ package space.kscience.dataforge.scripting import space.kscience.dataforge.context.Global import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.int -import space.kscience.dataforge.workspace.WorkspaceBuilder +import space.kscience.dataforge.workspace.Workspace import space.kscience.dataforge.workspace.target import kotlin.test.Test import kotlin.test.assertEquals @@ -12,7 +12,7 @@ import kotlin.test.assertEquals class BuildersKtTest { @Test fun checkBuilder() { - val workspace = WorkspaceBuilder(Global).apply { + Workspace(Global){ println("I am working") context { name("test") } diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt index 68598714..c17c5991 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt @@ -91,6 +91,5 @@ public inline fun WorkspaceBuilder.target(name: String, metaBuilder: MetaBuilder target(name, Meta(metaBuilder)) @DFBuilder -public fun Workspace(parentContext: Context = Global, builder: WorkspaceBuilder.() -> Unit): Workspace { - return WorkspaceBuilder(parentContext).apply(builder).build() -} \ No newline at end of file +public fun Workspace(parentContext: Context = Global, builder: WorkspaceBuilder.() -> Unit): Workspace = + WorkspaceBuilder(parentContext).apply(builder).build() \ No newline at end of file