Skip to content

Extensible handlebar for custom helpers #359

@fynnjuranek

Description

@fynnjuranek

Custom Handlebar Helpers for HandlebarUtils

Background

A few weeks ago, I asked a question in the Slack channel (link to message) about adding custom HandlebarHelpers to the existing HandlebarUtils string manipulations.

@jonatan-ivanov suggested creating an issue, so I thought I could also provide a possible solution with it. This is just a proposal, so please let me know what you think and how it can be improved.

Objective

(One small example) I want to cut the package names and keep only the class name of the defining Convention (rendered when using ObservationDocumentation structure).

Current Workaround

Currently, I achieve this through a Gradle Copy task to filter the end result, similar to how Spring AMQP handles their documentation.

I have taken a look in the StringHelpers provided by Handlebars.java but couldn't find what I need. Perhaps I overlooked something.

Proposed Solution

My approach now is to change HandlebarUtils to a Singleton, making the instance more extensible and allowing custom HandlebarHelpers to be registered. As of my view and tests, this change does not affect current functionality but introduces extensibility.

I've implemented the changes in my fork, do you want me to open a PR?

Example Usage

I created a simple example demonstrating how to use this, and it worked as intended. If you're interested, please check out the repository.

Here's a small peek at how I would add custom helpers:

public class CustomDocsGeneratorCommand {
    public static void main(String[] args) {

        Handlebars handlebars = HandlebarsUtils.createHandlebars();
        handlebars.registerHelpers(CustomHelpers.class);

        DocsGeneratorCommand.main(args);
    }
}
// gradle task
val generateObservabilityDocs by tasks.registering(JavaExec::class) {
    mainClass.set("com.example.CustomDocsGeneratorCommand") // use customized main instead of io.micrometer.docs.DocsGeneratorCommand
    classpath = configurations.getByName("adoc") + sourceSets.main.get().runtimeClasspath
    val conventionsTemplateFile = file("src/main/resources/conventions.adoc.hbs")
    val metricsTemplateFile = file("src/main/resources/metrics.adoc.hbs")
    val spansTemplateFile = file("src/main/resources/spans.adoc.hbs")
    args(
        project.layout.projectDirectory.asFile.absolutePath, // Input folder
        ".*",                         // Inclusion pattern
        project.layout.buildDirectory.get().asFile.absolutePath, // Output folder
        "--conventions-template=${conventionsTemplateFile.path}",
        "--metrics-template=${metricsTemplateFile.path}",
        "--spans-template=${spansTemplateFile.path}",
    )
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions