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
of the same type.
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
}