Documentation

Library

genesis

Version

2.0.0

This section contains the Seadex genesis documentation including the API reference.

Building genesis

This section provides you with instructions on how to build genesis in your environment.

Getting the source

  • Download the genesis package including the C++ source code from the genesis homepage.

  • Unzip the source package into a directory of your choice (this is referred to as $EDIR in the rest of the documentation). You can use 7-Zip or a similar tool for this task.

Building

These building options are available:

  • Microsoft Visual Studio - Description of how to build the genesis library with Microsoft Visual Studio and the Microsoft Visual Studio Compiler (using the provided solution and projects).

  • CMake - Description page for building the genesis library using CMake for Linux and Windows (Visual Studio/MSBuild).

Other compilers and platforms

Building for Linux with GCC is supported out of the box. For other compilers and/or platforms you can just adopt the CMake files.

Alternatively, you can quite easily set up your build. All you need to build genesis with a different compiler suite and/or on a different platform is C++17 support. Just take the genesis source code and set up a library project according to the procedures necessary for your platform.

You can also contact us to get a quote for commercial support for porting genesis to your platform!

If you run into compiler/build problems in your environment (especially compiler errors or warnings), please contact us. We then will try to resolve these issues.

Microsoft Visual Studio

2019

For Visual Studio 2019 a ready-to-use solution is provided. It contains:

  • genesis - source code of the genesis library

  • examples - project using and demonstrating some of the features of genesis

  • build - a folder containing the property sheets for the projects

  • genesis.sln - the solution file that contains the projects mentioned above

  • license file

  • docs - a folder containing the documentation

Use of Conan

The genesis library can use Conan to get its dependencies (see the Dependencies)

After the build, the genesis library can be integrated into your projects.

CMake

The build with CMake is currently tested for Linux (Debian, GCC, Clang) and Windows (Microsoft Visual Studio).

The CMakeFileLists.txt files are located in the solution directory, the genesis project directory and the examples directory.

Generating with CMake and Conan
Note
The following commands require Conan version 2.0.
Linux

In a terminal go to the directory into which you extracted genesis and run the following commands:

conan install . -g CMakeToolchain --profile=release --build=missing -of cmake

cd cmake

cmake .. -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=Release  -DGEN_BUILD_EXAMPLES=ON

cmake --build --preset conan-release
Note
Options (e.g. architecture) are used from the Conan profile.
Windows

In a terminal go to the directory into which you extracted genesis and run the following commands:

conan install . -g CMakeToolchain --profile=release --build=missing

cmake . -G "Visual Studio 16 2019" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DGEN_BUILD_EXAMPLES=ON

cmake --build --preset conan-release
Note
Options like architecture, Visual Studio version (generator), etc…​ are used from Conan profiles.

Release/Debug

Choosing between release and debug builds is done via Conan profiles and presets.

Preprocessor definitions

Using genesis' preprocessor definitions with CMake is also possible by passing them as parameters in the console/terminal.

Definition Description

CPP_VERSION=[VALUE]

Sets the standard for the C++ compiler. When it is not used, C++11 will be used.

Build options

The genesis build can be customized using the following options:

Definition Description

GEN_BUILD_EXAMPLES=[OFF]

When GEN_BUILD_EXAMPLES is defined, the example is built as well. By default, it is not defined and therefore, not built.

FMT_LIB_INCLUDE=[VALUE]

FMT_LIB=[VALUE]

SPDLOG_LIB_INCLUDE=[VALUE]

SPDLOG_LIB=[VALUE]

ESSENTIALS_LIB_INCLUDE=[VALUE]

ESSENTIALS_LIB=[VALUE]

To use the essentials, fmt and spdlog libraries from the user location, all the variables must be used at the same time with the correct paths. For the libs, the library is specified as well (e.g. "…​/fmt/lib/fmt.lib").

Dependencies

The genesis library starting with version 2.0 has the following dependencies:

  • seadex-essentials/2.1.3

  • spdlog/1.11.0

  • fmt/9.1.0

These dependencies can be provided using Conan (see Use of Conan).

Features

List of supported functionality.

Steps and blocks

The genesis library generates code by using internally defined elements.

Basic elements are called steps. There are:

  • Text step - containing a text sequence from the template file

  • Variable step - a variable that will be replaced by its value

The 'blocks' are complex elements that can contain other elements (steps and other blocks):

Text step

A text step contains a sequence of text from the template file. It will be written to the output string stream when the output is generated.

Variable step

A variable step contains the name of a variable. When the output is generated, the value of the variable will be written.

Command
$var(variable_name)

Condition block

A condition block represents an 'if'. If the condition is true, then all nested elements will be created, otherwise not.

Command

A condition block has the following structure:

$if(condition_name[, condition_modifier])
// child steps
$fi

A condition block must end with a '$fi' command. If the condition is not correctly ended (with '$fi'), then the template is considered ill-formed.

Condition modifier

A condition block can have an optional condition modifier. The following pre-defined values can be used:

Value

in template file

Effect

NONE

Does not affect the condition.

NOT

not

Negate the result of the condition.

The default value of the condition modifier is 'NONE'.

Note
New line after the close command '$fi' is discarded.

Loop block

A loop block represents a 'for' loop. For each iteration of the loop, all nested elements will be created.

Command
$loop(loop_name)
// child steps
$pool

A loop block must end with a '$pool' command. If the loop is not correctly ended (with '$pool'), then the template is considered to be ill-formed.

Note
New line after the close command '$pool' is discarded.

Switch block

A switch block represents a 'switch' statement. Only elements of the selected case will be created.

Command
$switch(switch_name)
$case(0)
	// child steps
$esac
$case(1)
	// child steps
$esac
// ...
$default()
	// child steps
$tluafed
$hctiws

A switch block must end with a '$hctiws' command (it is 'switch' backward).

Case and default

Each case command ( '$case') must have a matching closing command ('$esac'). Cases take an index as a parameter (an int).

The default command '$default' has to have empty parentheses and an end command '$tluafed' ('default' backward).

An index value will be passed to the switch block during generation. The value is determined by the return value of the method 'get_switch_case' of the callback interface. Then the code within the matching case command will be generated. If the value returned by the callback method does not match any of the cases then the code within the default command will be generated. The default command is optional though. If it is omitted and no case matches, no code will be generated for the switch block at all.

Only indexes equal to or greater than 0 are legal.

Note
New lines after the close commands '$esac', '$tluafed' and '$hctiws' are discarded.

Template block

A template block reads the specified template file which is treated as a recipe itself. All nested elements will be created.

Command
$template(template_file_name)
Note
template_file_name must contain the extension of the template file as well!

Recipe callback

The recipe callback is the interface that has to be implemented by the generator using genesis.

The recipe callback has the following default methods:

Method Parameters Return type Scope

get_variable_content

variable name (string)

string

Returns the content of the variable with the given name.

condition_begin

condition name (string)

void

Executes actions before the check of the condition with the given name.

check_condition

condition name (string) condition modifier

bool

Checks the condition with the given name and returns its result.

condition_end

condition name (string)

void

Executes actions after the condition with the given name.

before_loop

loop name (string)

void

Executes actions before the loop with the given name is executed.

before_loop_iteration

loop name (string)

void

Executes actions before an iteration of the loop with the given name is executed.

check_loop_condition

loop name (string)

bool

Checks if the loop with the given name needs to execute another iteration.

after_loop_iteration

loop name (string)

void

Executes actions after an iteration of the loop with the given name was executed.

after_loop

loop name (string)

void

Executes actions after the loop with the given name was executed.

get_switch_case

switch name (string)

int

Returns the index of the case of the switch with the given name which shall be executed.

Escape sequences

In genesis the '$' symbol represents the start of a command. For example:

$var(variable_name)
$loop(condition_name)
$pool

genesis defines certain escape sequences. An escape sequence starts with a '$' (dollar sign) just like a command.

Line break

genesis has a special command for inserting a new line: '$@'. When this sequence is found in the template, it will be replaced by a new line character.

Print $

If a '$' is needed in the output, then a double '$' has to be used.

Example
I got $$s!

The template above will print 'I got $s!'

Examples

In this section examples of generators that use the genesis library are provided. For now a simple HTML page generator is available, other examples will be added in the future.

  • [Html page generator] - A project demonstrating how genesis can be used to generate a simple HTML page. It is using a base template and a table template that is called multiple times.

HTML page generator example

In this example, the genesis library is used to create a generator for an HTML page that contains tables with cities for different countries.

Template files
Base template

The base template is the entry point for generating the page.

It looks like this:

Listing 1. countries.gtpl
<!DOCTYPE html>
<html>
<head>
<style>
table {
    font-family: arial, sans-serif;
    border-collapse: collapse;
    width: 300px;
}

td, th {
    border: 1px solid #E7C324;;
    text-align: left;
    padding: 3px;
    height: 20px;
}

tr:nth-child(even) {
    background-color: #252525;
}

body{
background-color:#262626;
color: #E7C324;
}

hr{
color: #E7C324;
}
</style>

<title>Population of big cities</title>

</head>
<body>

<h1>Population of big cities.</h1>
<p>List of countries:</p>
<p style="font-size:12px">*The capital is marked <b>bold</b> and <a style="color:#1E90FF">blue</a></p>
$loop(countries)
<h3> <b>$var(country_name)</b></h3>
$template(country_table.gtpl)
<hr>
$pool

</body>
</html>

This template for an HTML page contains a loop (starting at line 40, and ending at line 44) for iterating over a list of countries. For each country, the name will be generated using the '$var' command (line 41). Then a template that generates the table will be called using the '$template' command (line 42). The loop ends with the command '$pool'.

Table template file

The template file for a table looks like this:

Listing 2. country_table.gtpl
<table>
  <tr>
    <th>City</th>
    <th>Population</th>
  </tr>
  $loop(cities)
  <tr>
    <td>$if(is_capital)<b><p style="color:#1E90FF">$fi$var(city_name)$if(is_capital)</p></b>$fi</td>
    <td>$if(is_capital)<b><p style="color:#1E90FF">$fi$var(city_population)$if(is_capital)</p></b>$fi</td>
  </tr>
  $pool
</table>

Each city will be represented in one line. In the columns are placed the name and the population of the city. For each city, we check if the city is the capital city of the country by calling '$if' command (lines 8 and 9). If the city has the index of the capital city, then the line containing the capital city is made bold and blue. The end of condition command '$fi' is called at the end.

Result

The output HTML file containing a table with the cities of a specific country looks like this.

Data

Countries and cities are stored in the structs country and city respectively:

struct country
{
  std::string name_;
  std::vector<city> cities_;
  std::size_t capital_index_;
};

struct city
{
  std::string name_;
  int population_;
};

The structs are used in a configuration struct., The data is added manually in this case, but it could be read from file a file, a database, …​

struct config
{
  config();
  std::string template_path_;
  std::string source_template_file_;
  std::string output_file_;
  std::vector<country> countries_;
};
genesis’s callback interface implementation

genesis offers a recipe callback interface which has to be implemented containing the generator logic.

For example, the function for getting the variable contents looks like this:

std::string recipe_callback_impl::get_variable_content( const std::string& _variable_name )
{
    std::string result( "" );
    if( _variable_name == CITY_NAME )
    {
        result = config_.countries_[country_index_].cities_[city_index_].name_;
    }
    else if( _variable_name == CITY_POPULATION )
    {
        result = sxe::to_string( config_.countries_[country_index_].cities_[city_index_].population_ );
    }
    else if( _variable_name == COUNTRY_NAME )
    {
        result = config_.countries_[country_index_].name_;
    }
    return( result );
}

For each (city, population and country) the value is taken from a specific list with a specific index.

In the 'before_loop' method the indexes are set to 0 and in the 'after_loop_iteration' method they get incremented:

void recipe_callback_impl::after_loop_iteration( const std::string& _loop_name )
{
    if( _loop_name == LOOP_COUNTRIES )
    {
        ++country_index_;
    }
    else if( _loop_name == LOOP_CITIES )
    {
        ++city_index_;
    }
}

Checking the condition of the loop is done by checking if the index value is less than the size of the vector containing the data:

if( _loop_name == LOOP_COUNTRIES )
{
	result = country_index_ < config_.countries_.size();
}

Checking the '$if' condition is pretty much the same: indexes are compared.

if( _condition_name == CONDITION_IS_CAPITAL )
{
	result = config_.countries_[country_index_].capital_index_ == city_index_;
}
Generating the HTML page

Generating the HTML page is simple now. The configuration and callback objects are created. The callback is then passed to the recipe. Next, the 'generate' method is called on the recipe object. Finally, the content of the stream with the generated code is written into the output file by calling the 'write_to_file' method.

examples::config configuration;
examples::recipe_callback_impl recipe_callback( configuration );
sx::genesis::recipe source_recipe( configuration.source_template_file_, cb, configuration.template_path_ );
source_recipe.generate();
source_recipe.write_to_file( configuration.output_file_ );
Source code

The source code can be found on GitHub.

MIT License

Copyright (c) 2017-, Seadex GmbH

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Downloads

Download the latest version of the genesis library here.

For older versions, you shall check on the genesis' GitHub.

Changelog

Versions

All notable changes to this project are documented on this page.

[2.0.0]

Changed
  • use essentials 2.0

  • dropped the hermes library dependency

[0.3.2]

Changed
  • use essentials and hermes as libraries

  • CMake: use external CMakeHelpers files

  • CMake: refactoring of build files

Fixed
  • rename private method recipe::create to recipe::create_impl because of bug (warning in clang)

  • added SX_UNUSED_VARIABLE to is_delimiter_char, else a warning is generated in clang as it is not used (SX_ASSERT)

[0.2.0]

Added
  • Support for Visual Studio 2017 builds

Changed
  • rename: condition_block’s private method check_modifier to apply_modifier

  • method create_child of the class recipe_block is now protected

[0.1.0]

  • The very first released version of genesis

Contact & support

Your feedback is very important to and for us!

In case you have questions, suggestions, if you want to file a bug report, or if we can assist you in any other way please send us an email to genesis@seadex.de.

Also, we are very glad if you Show your appreciation!

Commercial support

Seadex GmbH from Trossingen, Germany can provide you with commercial support.

Support is available in the form of (but not limited to) the development of specific tools for your environment, custom development within essentials, consulting, or training.

Also, Seadex can support you with additional developers.

Please contact us if you have a question or require a quote.

Show your appreciation

If you like genesis and find it useful, we would be very happy if you’d show your appreciation in one way or the other. It helps us to attract more attention to genesis. The more attention it gets the more feedback and input we get. And that is the knowledge we need to improve genesis further.

There are multiple ways to show your appreciation:

  • Star genesis on GitHub

  • Contact us (via Contact & support) and allow us to feature you (or your company) as a reference user.