GenerateToString

GenerateToString is a mixin string that automatically generates toString functions, both sink-based and classic, customizable with UDA annotations on classes, members and functions.

enum string GenerateToString;

Examples

When used with objects, toString methods of type string toString() are also created.

class Class
{
    mixin(GenerateToString);
}

(new Class).to!string.shouldEqual("Class()");
(new Class).toString.shouldEqual("Class()");

A trailing underline in member names is removed when labeling.

struct Struct
{
    int a_;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(a=0)");

The @(ToString.Exclude) tag can be used to exclude a member.

struct Struct
{
    @(ToString.Exclude)
    int a;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct()");

The @(ToString.Optional) tag can be used to include a member only if it's in some form "present". This means non-empty for arrays, non-null for objects, non-zero for ints.

class Class
{
    mixin(GenerateToString);
}

struct Struct
{
    @(ToString.Optional)
    int a;
    @(ToString.Optional)
    string s;
    @(ToString.Optional)
    Class obj;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct()");
Struct(2, "hi", new Class).to!string.shouldEqual("Struct(a=2, s=hi, obj=Class())");
Struct(0, "", null).to!string.shouldEqual("Struct()");

The @(ToString.Include) tag can be used to explicitly include a member. This is intended to be used on property methods.

struct Struct
{
    @(ToString.Include)
    int foo() const { return 5; }
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(foo=5)");

The @(ToString.Unlabeled) tag will omit a field's name.

struct Struct
{
    @(ToString.Unlabeled)
    int a;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(0)");

Parent class toString() methods are included automatically as the first entry, except if the parent class is Object.

class ParentClass { mixin(GenerateToString); }

class ChildClass : ParentClass { mixin(GenerateToString); }

(new ChildClass).to!string.shouldEqual("ChildClass(ParentClass())");

Inclusion of parent class toString() can be prevented using @(ToString.ExcludeSuper).

class ParentClass { }

@(ToString.ExcludeSuper)
class ChildClass : ParentClass { mixin(GenerateToString); }

(new ChildClass).to!string.shouldEqual("ChildClass()");

The @(ToString.Naked) tag will omit the name of the type and parentheses.

@(ToString.Naked)
struct Struct
{
    int a;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("a=0");

Fields with the same name (ignoring capitalization) as their type, are unlabeled by default.

struct Struct1 { mixin(GenerateToString); }

struct Struct2
{
    Struct1 struct1;
    mixin(GenerateToString);
}

Struct2.init.to!string.shouldEqual("Struct2(Struct1())");

This behavior can be prevented by explicitly tagging the field with @(ToString.Labeled).

struct Struct1 { mixin(GenerateToString); }

struct Struct2
{
    @(ToString.Labeled)
    Struct1 struct1;
    mixin(GenerateToString);
}

Struct2.init.to!string.shouldEqual("Struct2(struct1=Struct1())");

Fields of type 'SysTime' and name 'time' are unlabeled by default.

struct Struct { SysTime time; mixin(GenerateToString); }

Struct strct;
strct.time = SysTime.fromISOExtString("2003-02-01T11:55:00Z");

// see unittest/config/string.d
strct.to!string.shouldEqual("Struct(2003-02-01T11:55:00Z)");

Fields named 'id' are unlabeled only if they define their own toString().

struct IdType
{
    string toString() const { return "ID"; }
}

struct Struct
{
    IdType id;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(ID)");

Otherwise, they are labeled as normal.

struct Struct
{
    int id;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(id=0)");

Fields that are arrays with a name that is the pluralization of the array base type are also unlabeled by default.

struct SomeValue { mixin(GenerateToString); }
struct Entity { mixin(GenerateToString); }
struct Day { mixin(GenerateToString); }

struct Struct
{
    SomeValue[] someValues;
    Entity[] entities;
    Day[] days;
    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct([], [], [])");

GenerateToString can be combined with GenerateFieldAccessors without issue.

struct Struct
{
    import boilerplate.accessors : GenerateFieldAccessors, ConstRead;

    @ConstRead
    private int a_;

    mixin(GenerateFieldAccessors);

    mixin(GenerateToString);
}

Struct.init.to!string.shouldEqual("Struct(a=0)");

Meta