Creación masiva de clases de C++ (u otros lenguajes) mediante plantillas

Esta tarde estaba haciendo pruebas y he tenido que crear unas 30 o 40 clases, por tanto, necesitaba automatizar y mejorar el proceso. Con Visual Studio el tema de crear clases lo veo un infierno, con eclipse la cosa mejora, pero sigue existiendo el problema.

Por tanto os pongo este script que con solo preguntaros 2 cosas por clase, podeis crear clases a gran velocidad. Es obligatorio que cambieis las plantillas a vuestras necesidades. Se podría uasar para cualquier lenguaje, ya que la generación del nombre del fichero es otra plantilla en sí. Queda pendiente sacar la plantilla a un archivo externo. Hay que decir que lo he hecho en menos de 1 hora.

Aquí lo pego, aunque por si se ve mal también dejo un pastebin:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
# 
# Script para generar clases de C++ agilmente
# Requerido: Python 3.x
#
# 1ª vez de uso se creará un script que debe de configurarse según las necesidades
# Esta configuración es global: directorio de salida, autor y formato fecha
# En siguientes ejecuciones solo preguntará interacticamente y en bucle:
# - Nombre de clase
# - Proposito
#
# Para dejar de crear clases poner un nombre de clase en blanco
#
# Las plantillas deben modificarse y adaptarse a las necesidades de cada uno.
# Queda pendiente sacar las plantillas a fichero
#

import os, sys
import configparser
from datetime import date
d = date.today()

# global
TODIR = "."
NAMESPACE = "Dune"
AUTOR = "Ricardo Marmolejo García"
FORMAT_FECHA = "%d/%m/%y"
config_file = "create_class.cfg"

if(not os.path.exists(config_file)):
    # escribir una config por defecto
    config = configparser.ConfigParser()
    config.add_section('create_class')
    config.set('create_class', 'TODIR', "%s" % TODIR)
    config.set('create_class', 'NAMESPACE', "%s" % NAMESPACE)
    config.set('create_class', 'AUTOR', "%s" % AUTOR)
    config.set('create_class', 'FORMAT_FECHA', "%s" % FORMAT_FECHA)

    f = open(config_file, 'w')
    config.write(f)
    f.close()
    
    print("Se ha creado una configuración por defecto en %s." % config_file)
    print("Condigurelo, y vuelva a ejecutar el script.")
    sys.exit(1)

else:
    
    config = configparser.ConfigParser()
    config.read(config_file)
    
    TODIR = config.get('create_class', 'TODIR')
    NAMESPACE = config.get('create_class', 'NAMESPACE')
    AUTOR = config.get('create_class', 'AUTOR')
    FORMAT_FECHA = config.get('create_class', 'FORMAT_FECHA')

# obtener fecha, en el formato especificado
FECHA = d.strftime(FORMAT_FECHA)

salir = False

while not salir:
    
    CLASSNAME = input("Escribe el nombre de la clase (dejelo en blanco si quiere terminar): \n")
    
    if CLASSNAME == "":
        salir = True
        break
    
    PROPOSITO = input("Escriba el propósito de esta clase: \n")
    print("\n")

    '''
    Plantillas:
    
        - template_cpp_namefile: Plantilla que genera el nombre del archivo cpp
        - template_h_namefile: Plantilla que genera el nombre del archivo .h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    '''
    template_cpp_namefile = "__CLASSNAME__.cpp"
    template_h_namefile = "__CLASSNAME__.h"

    '''
    
    Plantillas:
    
        - template_cpp: Plantilla que genera el contenido del cpp
        - template_h: Plantilla que genera el contenido del h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    __FILE__ = Nombre del archivo original
    __FILE_UPPER__ = Nombre del archivo en mayusculas (puntos pasan a ser guiones bajos)
    __FILE_LOWER__ = Nombre del archivo en minusculas (puntos pasan a ser guiones bajos)
    __PROPOSITO__ = Proposito de la clase
    __AUTOR__ = Autor de la clase
    __FECHA__ = Dia, Mes y año del momento de la creación
    '''

    template_h = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#ifndef __FILE_UPPER__
#define __FILE_UPPER__

#include "../Component.h"

namespace __NAMESPACE__ {

class __CLASSNAME__ : public Component
{
public:
    __CLASSNAME__();
    virtual ~__CLASSNAME__();
    
public:

    // SERVICIOS DE LA COMPONENTE
    

public:

    /**
    Ejecutado en su primer tick
    */
    virtual void OnCreate();

    /**
    Actualizado intensivamente
    */
    virtual void Update();

    /**
    Actualizado en una frecuencia fija
    */
    virtual void UpdateFixed();

    /**
    Ejecutado antes de su destrucción
    */
    virtual void OnDestroy();

};

} // end namespace __NAMESPACE_UPPER__

#endif __FILE_UPPER__
"""

    template_cpp = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#include "../Common.h"
#include "__CLASSNAME__.h"
#include "../Entity.h"

namespace __NAMESPACE__ {

__CLASSNAME__::__CLASSNAME__()
{
    
}

__CLASSNAME__::~__CLASSNAME__()
{
    
}

void __CLASSNAME__::OnCreate()
{
    
}

void __CLASSNAME__::Update()
{
    
}

void __CLASSNAME__::UpdateFixed()
{
    
}

void __CLASSNAME__::OnDestroy()
{
    
}

} // end namespace __NAMESPACE_UPPER__
"""

    # init vars
    NAMESPACE_UPPER = NAMESPACE.upper()
    NAMESPACE_LOWER = NAMESPACE.lower()
    CLASSNAME_UPPER = CLASSNAME.upper()
    CLASSNAME_LOWER = CLASSNAME.lower()
    NAMESPACE_UPPER = NAMESPACE_UPPER.replace(".", "_")
    NAMESPACE_LOWER = NAMESPACE_LOWER.replace(".", "_")
    CLASSNAME_UPPER = CLASSNAME_UPPER.replace(".", "_")
    CLASSNAME_LOWER = CLASSNAME_LOWER.replace(".", "_")

    for newfile in [    [template_cpp_namefile, template_cpp],
                        [template_h_namefile, template_h]       ]:

        FILE = newfile[0]
        FILE = FILE.replace("__NAMESPACE__", NAMESPACE)
        FILE = FILE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
        FILE = FILE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
        FILE = FILE.replace("__CLASSNAME__", CLASSNAME)
        FILE = FILE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
        FILE = FILE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
        FILE_UPPER = FILE.upper()
        FILE_LOWER = FILE.lower()
        FILE_UPPER = FILE_UPPER.replace(".", "_")
        FILE_LOWER = FILE_LOWER.replace(".", "_")

        generated_file = os.path.join(TODIR, FILE)
        
        if not os.path.exists(generated_file):

            VALUE = newfile[1]
            VALUE = VALUE.replace("__NAMESPACE__", NAMESPACE)
            VALUE = VALUE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
            VALUE = VALUE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
            VALUE = VALUE.replace("__CLASSNAME__", CLASSNAME)
            VALUE = VALUE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
            VALUE = VALUE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
            VALUE = VALUE.replace("__FILE__", FILE)
            VALUE = VALUE.replace("__FILE_UPPER__", FILE_UPPER)
            VALUE = VALUE.replace("__FILE_LOWER__", FILE_LOWER)
            VALUE = VALUE.replace("__PROPOSITO__", PROPOSITO)
            VALUE = VALUE.replace("__AUTOR__", AUTOR)
            VALUE = VALUE.replace("__FECHA__", FECHA)

            file_cpp = open(generated_file, "w", encoding='utf-8')
            file_cpp.write(VALUE)
            file_cpp.close()
            
            print("%s se ha creado correctamente" % FILE)
            
        else:
            
            print("%s ya existe!, no se ha creado." % FILE)
            
    print("\n")