CodeBlock-Structure

Do you want to understand the code, read this chapter, otherwise, just skip ahead.

Global

CodeBlockBuilder gives an DSL-like interface to the builders from KotlinPoet. The best way to add those functions, but not clutter the code with the old functions is provide a wrapper around the builders of KotlinPoet: the CodeBlockBuilder.

class CodeBlockBuilder(private val builder: BlockWrapper)

The codeBlockBuilder accepts a BlockWrapper, which has two implementations: one for functions, and one for the CodeBlock. When we add all the functions of FunctionSpec.Builder to the wrapper, we can use the wrapper throughout our code, instead of FunctionSpec.Builder. At the same time,we leave out/add functions to KotlinPoets builders by updating only one class.

CodeBlockBuilder - implementation

As we have seen, CodeBlockBuilder is a wrapper around the real builders. This means that the code added to CodeBlockBuilder is the code that's visible from the DSL.

We can add normal functions and extension-functions to our codeblock-DSL (although we don't add those at this moment). For example:

//Note this is not implemented!
list<Int>("1, 2, 3, 4").forEach("value"){
    statement("println(value")
}

This means we have to make big class CodeBlockBuilder that does a lot of different things. But Kotlin has a way better way to do this: delegation.

Our CodeBlockBuillder looks like:

class CodeBlockBuilder(
    private val builder: BlockWrapper
) : IRepeat by RepeatBuilder(builder),
    IiFInterface by IfClassStart(builder)

In this way, the extension-functions are added to CodeBlockBuilder, so the code in the former example woud work. On the other hand, we keep the classes small (or it seems that way ;-) )

Lazy Components

When we call the special functons (see other chapters in this block) we call actions on the wrapper straight away. This means that we call actions during the creation of our components. This means our code cannot work correctly all the times:

buildCodeBlock {
    switch("1"){
        "1" then switch("a".S()){
            Else{}
        }
        Else{}
    }
}

This code asks to add switch immediately after the function is invoked. This means that the code would start with switch(1) { switch("a") {. Therefor we need to have lazy components. This are components that are a big extension-function to wrapper. That means we can add the second switch exactly when needed.

starting from V0.2, you can add your own component using an infix-function attach:

createCodeBlock {
    myComponent{
        someActions
    }.attach()
}

Last updated