Extra¶
Introduction¶
ExtraProperty
classes are used both by Documentable and Content
models.
Source code for ExtraProperty
:
interface ExtraProperty<in C : Any> {
interface Key<in C : Any, T : Any> {
fun mergeStrategyFor(left: T, right: T): MergeStrategy<C> = MergeStrategy.Fail {
throw NotImplementedError("Property merging for $this is not implemented")
}
}
val key: Key<C, *>
}
To declare a new extra, you need to implement ExtraProperty
interface. It is advised to use following pattern
when declaring new extras:
data class CustomExtra(
[any data relevant to your extra],
[any data relevant to your extra]
): ExtraProperty<Documentable> {
override val key: CustomExtra.Key<Documentable, *> = CustomExtra
companion object : CustomExtra.Key<Documentable, CustomExtra>
}
Merge strategy (mergeStrategyFor
method) for extras is invoked during
merging if documentables from different
source sets each
have their own Extra
.
PropertyContainer¶
All extras for ContentNode
and Documentable
classes are stored in PropertyContainer<C : Any>
class instances.
data class DFunction(
...
override val extra: PropertyContainer<DFunction> = PropertyContainer.empty()
...
) : WithExtraProperties<DFunction>
PropertyContainer
has a number of convenient functions for handling extras in a collection-like manner.
The C
generic class parameter limits the type of properties that can be stored in the container - it must
match generic C
class parameter from ExtraProperty
interface. This allows creating extra properties
which can only be stored in a specific Documentable
.
Usage example¶
In following example we will create a DFunction
-only property, store it and then retrieve its value:
data class CustomExtra(val customExtraValue: String) : ExtraProperty<DFunction> {
override val key: ExtraProperty.Key<Documentable, *> = CustomExtra
companion object: ExtraProperty.Key<Documentable, CustomExtra>
}
fun DFunction.withCustomExtraProperty(data: String): DFunction {
return this.copy(
extra = extra + CustomExtra(data)
)
}
fun DFunction.getCustomExtraPropertyValue(): String? {
return this.extra[CustomExtra]?.customExtraValue
}
You can also use extras as markers, without storing any data in them:
object MarkerExtra : ExtraProperty<Any>, ExtraProperty.Key<Any, MarkerExtra> {
override val key: ExtraProperty.Key<Any, *> = this
}
fun Documentable.markIfFunction(): Documentable {
return when(this) {
is DFunction -> this.copy(extra = extra + MarkerExtra)
else -> this
}
}
fun WithExtraProperties<Documentable>.isMarked(): Boolean {
return this.extra[MarkerExtra] != null
}