T4Toolbox icon indicating copy to clipboard operation
T4Toolbox copied to clipboard

Document how to generate multiple output files

Open felixwatts opened this issue 9 years ago • 9 comments

This feature is advertised in a few places but I can't find anywhere showing how to actually use it.

felixwatts avatar Feb 18 '16 14:02 felixwatts

Oldie but goodie here. That's what I used to create my multi-output template. Optionally I guess someone could make a wiki section here on github...

lukedoolittle avatar Jun 03 '16 16:06 lukedoolittle

Link broken...

walcher avatar Sep 27 '16 22:09 walcher

Here's the Internet Archive version of a tutorial from the author's old site:

kenny-evitt avatar Dec 13 '16 21:12 kenny-evitt

These archived posts are more relevant to using T4 Toolbox itself for this:

  1. Oleg Sych - » T4 Tutorial: Creating reusable code generation templates
  2. Oleg Sych - » T4 Tutorial: Creating complex code generators

The archived post to which I linked in my previous comment does demonstrate generating multiple outputs but the solution it outlines doesn't use (or thus require) T4 Toolbox.

kenny-evitt avatar Dec 27 '16 21:12 kenny-evitt

A quick outline of what you need to do:

  1. Create a base T4 Toolbox Template template and expose any parameters it needs as public fields (or whatever).
  2. Create a T4 Toolbox Generator that includes the base template from [1], creates an instance of the base template class, and makes multiple calls to the template objects RenderToFile method (passing it the name of the file to generate). If you need or want parameters for the generator, add them as public members.
  3. Create a T4 Toolbox Script that includes the generator template file, creates an instance of the generator class, set any parameter members as appropriate, and then call the generator instance object's Run method.

Some (possibly not-working-as-is, and definitely contrived) examples of the above:

Base template BaseTemplate.tt [1]:

<#+
public class BaseTemplate : CSharpTemplate
{
    public string className;

    public override string TransformText()
    {
        base.TransformText();
#>
namespace Blah.BlahBlah
{

    public partial class <#= className #>
    {
        public static void DoSomething()
        {
            // Do something here
        }
    }
}
<#+
        return this.GenerationEnvironment.ToString();
    }
}
#>

Generator template CodeGenerator.tt [2]:

<#@ include file="BaseTemplate.tt" #>
<#+
public class CodeGenerator : Generator
{
    public BaseTemplate baseTemplate = new BaseTemplate();

    protected override void RunCore()
    {
        List<string> classNames = new List<string>()
        {
            "Cat",
            "Dog"
        };

        foreach (string className in classNames)
        {
            this.baseTemplate.className = className;
            this.baseTemplate.RenderToFile(String.Format("{0}.cs", className));
        }
    }
}
#>

Final script template CodeGeneratorRunner.tt [3]:

<#@ template language="C#" debug="True" #>
<#@ output extension="cs" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="CodeGenerator.tt" #>
<#
	CodeGenerator generator = new CodeGenerator();
	generator.Run();
#>

I adapted the above from my own (working) templates. As in the examples above, I didn't need to parameterize the generator template. In that case, it may be possible to forego the third script.

kenny-evitt avatar Jan 23 '17 15:01 kenny-evitt

Here's an even simpler example, based on my previous example. Note that this involves moving the code previously in the generator to the script template. The base template remains unchanged.

Base template BaseTemplate.tt [1]:

<#+
public class BaseTemplate : CSharpTemplate
{
    public string className;

    public override string TransformText()
    {
        base.TransformText();
#>
namespace Blah.BlahBlah
{

    public partial class <#= className #>
    {
        public static void DoSomething()
        {
            // Do something here
        }
    }
}
<#+
        return this.GenerationEnvironment.ToString();
    }
}
#>

Script template TemplateRunner.tt [2]:

<#@ include file="BaseTemplate.tt" #>
<#
BaseTemplate baseTemplate = new BaseTemplate();

List<string> classNames = new List<string>()
{
    "Cat",
    "Dog"
};

foreach (string className in classNames)
{
    baseTemplate.className = className;
    baseTemplate.RenderToFile(String.Format("{0}.cs", className));
}
#>

kenny-evitt avatar Jan 24 '17 16:01 kenny-evitt

Thanks for sharing, I got your example to work with a minor change. I had to add these lines, it doesn't seem to matter which .tt file they go in, otherwise I got an error that about 'List<>' could not be found.

<#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #>

DreadedTuba avatar May 08 '17 17:05 DreadedTuba

Thanks everyone! The new content lives on GitHub. Pull requests to publish missing content are welcome!

olegsych avatar Aug 20 '17 18:08 olegsych

Thanks everyone! The new content lives on GitHub. Pull requests to publish missing content are welcome!

Github changed TLD for pages and so the new link is http://olegsych.com/T4Toolbox/

paralaxsd avatar Sep 30 '23 22:09 paralaxsd