Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Warning

The information on this page is out of date. There is currently no way to provide custom builders with the build2 api. This lack will be remedied at some point.

Custom Builders

You will occasionally find classes that need to be built in a particular way that dconstructor doesn't allow. For instance, if you are using Tango's log implementation, you must use Log.getLogger rather than directly calling a constructor. This tutorial will show how to accomplish that.

The base class

All builders must inherit from the AbstractBuilder? class:

class AbstractBuilder(TBuilder, T)
{
    T build (TBuilder parent);
}

Let's look at the parts of that in more detail.

  • TBuilder

See the section on Interceptors for more information on why this is necessary. TBuilder is the type of the builder that this object builder will use if it needs to build any further elements or get any other information on configuration or what is currently being built.

  • T

This is the type that you are building.

A simple builder

Let's say you have a class Log with a static method getLogger(char[] name) that returns a Log. You can write your interceptor as follows:

class LogBuilder(TBuilder) : AbstractBuilder!(TBuilder, Log)
{
    Log build (TBuilder parent)
    {
        return Log.getLogger("name");
    }
}

Adding the builder

To add your builder, use the following:

builder().config.custom!(Log)(new LogBuilder!(typeof(builder())));

Examining the build stack

Often, you need a custom builder because you need to customize the object you return based on what object it is being built for. For that reason, dconstructor provides a build stack: Builder.stack. You can see the API docmentation for dconstructor.stack for more details.

For the logging example, let's see how this would work:

ClassInfo info = parent.stack.buildfor();
auto name = info.name;
return Log.getLogger(name);

In the case that you directly called the Builder to get a particular type, buildfor will return null, so to handle this case, here's the completed code:

class LogBuilder(TBuilder) : AbstractBuilder!(TBuilder, Log)
{
    Log build (TBuilder parent)
    {
        ClassInfo info = parent.stack.buildfor();
        auto name = (info) ? info.name : "Application";
        return Log.getLogger(name);
    }
}

Post-build dependencies

If your object has post-build dependencies, you can have dconstructor fill those automatically:

class Optional
{
    ...
    void inject (IDependency dependency) {}
}
class OptionalBuilder(TBuilder) : AbstractBuilder!(TBuilder, Optional)
{
    Optional build (TBuilder parent)
    {
        auto optional = get(parent);
        parent.postDependencies(optional);
        return optional;
    }
}

Interceptors

If you want your object to go through any defined interceptors that your builder has, you need to do that manually (for various reasons that I'll not get into here). Doing so is simple:

class OptionalBuilder(TBuilder) : AbstractBuilder!(TBuilder, Optional)
{
    Optional build (TBuilder parent)
    {
        auto optional = get(parent);
        parent.interceptors.intercept!(Optional)(optional);
        return optional;
    }
}

Of course, not doing so is simpler.