technodesigner

Digital design

Olivier Dewit
Template based code generation - Part 1 : introduction, SVG generation

Template based code generation - Part 1 : introduction, SVG generation

Series index

Principle

The tdCodeFactory PowerShell module uses here-strings and code expansion mechanism to offer template based code generation features.

This module provides the Export-FileFromTemplate command, which receives as parameters:

The template and the script block must match. For example, the script block may define a variable used by the template. The variables must be defined with the Script scope. These variables are usually referencing .NET objects whose class can be defined in C#.

Next parts of this article assume that the tdCodeFactory module is installed and opérational.

SVG code generation example

SVG is a language for defining vector graphics scenes. It is supported by all recent browsers.

Our first example is to produce an SVG file that defines a rectangle with rounded corners. Fill and stroke are defined by a CSS style.

In the Github repository , the source code for this example is available in the Demo/1.ShapeFactory and Demo/CsCode folders.

Template and objects

The template (rect.svg.template file) expects from the script block the following variables:

The corresponding C # classes are defined as follows (in reality they are distributed in different files, and may define additional members for the next examples):

namespace CodeFactory
{
  public class ShapeboardData
  {
    public string Name { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
  }
  public class ShapeStyleData
  {
    public string Name { get; set; }
    public string Target { get; set; }
    public string Fill { get; set; }
    public string Stroke { get; set; }
    public int StrokeThickness { get; set; }
  }
  public class RectData
  {
    public string Name { get; set; }
    public string StyleDataName { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public int RadiusX { get; set; }
    public int RadiusY { get; set; }
  }
}

The template therefore uses the data from C# classes (which are instantiated by the script, as we will see below):

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 $($shapeboard.Width) $($shapeboard.Height)">
  <defs>
    <style type="text/css">
      <![CDATA[
        $($shapeStyle.Target).$($shapeStyle.Name){
          fill: $($shapeStyle.Fill);
          stroke: $($shapeStyle.Stroke);
          stroke-width: $($shapeStyle.StrokeThickness);
        }
      ]]>
    </style>
  </defs>
  <rect 
    x='0' 
    y='0' 
    width='$($shapeboard.Width)' 
    height='$($shapeboard.Height)'
    fill='#FFCC4D' />
  <rect 
    class='$($rect.StyleDataName)' 
    x='$($rect.X)'
    y='$($rect.Y)'
    width='$($rect.Width)'
    height='$($rect.Height)'
    rx='$($rect.RadiusX)'
    ry='$($rect.RadiusY)'/>
</svg>

The SVG scene viewBox is sized using data from the $shapeboard object. Also the first rectangle, which is used to show the workspace. The style is defined by the data of the $shapeStyle object. It is referenced by the second rectangle using the class attribute. Others characteristics are obtained from the $rect object.

The role of the script block given to the Export-FileFromTemplate command consists therefore in C# classes loading, instantiating and initializing.

C# class loading, instantiating and initializing

C# class loading requires 2 steps:

It is then possible to create an instance of the class.

Example :

$shapeboardDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\ShapeboardData.cs
Add-Type -Language CSharp $shapeboardDataCsCode
$script:shapeboard = New-Object CodeFactory.ShapeboardData -Property @{
  Width = 160;
  Height = 120;
}

Script

To configure and initiate the code generation, we create a script file named ShapeFactory.ps1, which defines the script block using the above principle for each of the 3 classes to be instantiated, and which calls the Export-FileFromTemplate command to generate the SVG file:

$code = {
  $shapeStyleDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\ShapeStyleData.cs
  Add-Type -Language CSharp $shapeStyleDataCsCode
  $script:shapeStyle = New-Object CodeFactory.ShapeStyleData -Property @{
    Name = "rectStyle";
    Target = "rect";
    Fill = "#F5331F";
    Stroke = "#28282A";
    StrokeThickness = 2;
  };
  $rectDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\RectData.cs
  Add-Type -Language CSharp $rectDataCsCode
  $script:rect = New-Object CodeFactory.RectData -Property @{
    Name = "shape";
    StyleDataName = $script:shapeStyle.Name;
    X = 10;
    Y = 10;
    Width = 120;
    Height = 60;
    RadiusX = 8;
    RadiusY = 8;
  }
  $shapeboardDataCsCode = Import-CodeTemplate $PSScriptRoot\..\CsCode\ShapeboardData.cs
  Add-Type -Language CSharp $shapeboardDataCsCode
  $script:shapeboard = New-Object CodeFactory.ShapeboardData -Property @{
    Width = 160;
    Height = 120;
  }
}
$OutDir = "$PSScriptRoot\Export"
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
$svg = Export-FileFromTemplate $PSScriptRoot\rect.svg.template $code $OutDir\rect.svg

Result

The generated SVG file code corresponds to the structure defined in the template, after code expansion:

<svg xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 160 120">
  <defs>
    <style type="text/css">
      <![CDATA[
        rect.rectStyle{
          fill: #F5331F;
          stroke: #28282A;
          stroke-width: 2;
        }
      ]]>
    </style>
  </defs>
  <rect 
    x='0' 
    y='0' 
    width='160' 
    height='120'
    fill='#FFCC4D' />
  <rect 
    class='rectStyle' 
    x='10'
    y='10'
    width='120'
    height='60'
    rx='8'
    ry='8'/>
</svg>

The generated SVG file is viewable in a browser:

PowerShell : SVG code generation

Summary

Thanks to here-strings and code expansion mechanism provided by PowerShell, you can easily make a template based code generator.

Here we have generated a basic SVG scene. In future articles, we will discuss in particular the following topics:



Powered by the Perspective WebApp - © Olivier Dewit - Lyon, Paris, France - Legal informations