Dsl Block Delegation

link to DSL docs

Chassis DSL tries to use the DRY principle (Don’t Repeat Yourself) also for implementation of sub-DSL Structures, that may appear below multiple different DSL nodes.

Let’s take a showcase { ... } substructure that may appear inside a model as well as under a dto,

    model("someModel") {
        showcase {
            ...
        }
        dto {
            showcase {
                ...
            }
        }
    }

Chassis solves this, by giving (creating via dslCtx) a delegate Instance (DslDelegateImpl) dslShowcaseDelegateImpl which implements its corresponding IDslApiShowcase and then delegates all sub-DSL Structure calls to it with IDslApiShowcase by dslShowcaseDelegateImpl.
If you don’t know about kotlin interface delegation see the Kotlin Docs

context(DslCtxWrapper)
class DslModel(
    val simpleName: String,
    val modelRef: DslRef.model,
    val dslShowcaseDelegateImpl: DslShowcaseDelegateImpl = dslCtx.ctxObjOrCreate(DslRef.showcase(simpleName, modelRef)),
) : ADslClass(),
    IDslApiModel,
    IDslApiShowcase by dslShowcaseDelegateImpl
{
    val log = LoggerFactory.getLogger(javaClass)
    override val selfDslRef = modelRef

The DslShocaseDelegateImpl then implements the delegated node itself (NOT what is INSIDE that node!!!):

/** outer scope */
context(DslCtxWrapper)
class DslShowcaseDelegateImpl(
    simpleNameOfDelegator: String,
    delegatorRef: IDslRef
) : ADslDelegateClass(simpleNameOfDelegator, delegatorRef), IDslImplShowcaseDelegate {
    override fun toString() = "${this::class.simpleName}(${theShowcaseBlocks.size})"
    val log = LoggerFactory.getLogger(javaClass)
    override val selfDslRef = DslRef.showcase(simpleNameOfDelegator, delegatorRef)
 
    /** different gathered dsl data holder for different simpleName's inside the BlockImpl's */
    override var theShowcaseBlocks: MutableMap<String, DslShowcaseBlockImpl> = mutableMapOf()
 
    /** DslBlock funcs always operate on IDslApi interfaces */
    override fun showcase(simpleName: String, block: IDslApiShowcaseBlock.() -> Unit) {
        val dslImpl = theShowcaseBlocks.getOrPut(simpleName) { DslShowcaseBlockImpl(simpleName, selfDslRef) }
        dslImpl.apply(block)
    }
}

the DslShowcaseDelegateImpl also holds one or more properties which the inner logic of the delegated node:

/** inner scope */
context(DslCtxWrapper)
class DslShowcaseBlockImpl(
    val simpleName: String,
    override val selfDslRef: IDslRef // that should be the Delegate of this and NOT the parentRef in the Dsl
) : ADslClass(), IDslImplShowcaseBlock
{
    override fun toString() = "${this::class.simpleName}(${dslShowcasePropsData})"
    val log = LoggerFactory.getLogger(javaClass)
    // back reference to own DelegateImpl (from context or as function parameter)
    val showcaseDelegate: DslShowcaseDelegateImpl = dslCtx.ctxObj(selfDslRef)

This way any DSL node that wants to have the showcase node, just needs to add it to its constructor (creating it via context in its initializer) and delegate the DslApiShowcase to that constructor argument.


back to root