Writing your own template

Starting

Writing your own template is as easy as creating a .mrbob.ini that may contain questions. Everything else is extra. To start quickly, use the template starter that ships with mr.bob:

$ mrbob mrbob:template_starter/
Welcome to mr.bob interactive mode. Before we generate directory structure, some questions need to be answered.

Answer with a question mark to display help.
Value in square brackets at the end of the questions present default value if there is no answer.


--> How old are you? [24]:

--> What is your name?: Foobar

--> Enter password:


Generated file structure at /home/ielectric/code/mr.bob

See .mrbob.ini for sample questions and sample.txt.bob for sample rendering.

How it works

Files inside the structure can be just copied to destination, or they can be suffixed with .bob and the templating engine will be used to render them.

By default a slightly customized Jinja2 templating is used. The big differences are that variables are referenced with {{{ variable }}} instead of {{ variable }} and blocks are {{% if variable %}} instead of {% if variable %}. To read more about templating see Jinja2 documentation.

Variables can also be used on folder and file names. Surround variables with plus signs. For example foo/+author+/+age+.bob given variables author being Foo and age being 12, foo/Foo/12 will be rendered.

Templating engine can be changed by specifying renderer in mr.bob config section in dotted notation. It must be a callable that expects a text source as the first parameter and a dictionary of variables as the second.

When rendering the structure, permissions will be preserved for files.

Writing Questions

[question] section in .mrbob.ini specifies a schema for how [variables] are validated. Example speaks for itself:

[questions]
author.name.question = What is your name?
author.name.required = True

author.age.question = How old are you?
author.age.help = We need your age information to render the template
author.age.default = 24

author.password.question = Enter password
author.password.command_prompt = getpass:getpass

Questions will be asked in the order written in .mrbob.ini.

questions section reference

Parameter Default Explanation
name   Required. Unique identifier for the question
question   Required. Question given interactively to a user when generating structure
default None Default value when no answer is given. Can be a dotted notation
required False Specify if question must be answered
command_prompt raw_input() Function that accepts a question and asks user for the answer
help “” Extra help returned when user inputs a question mark
pre_ask_question None dotted notation function to run before asking the question
post_ask_question None dotted notation function to run after asking the question (also does validation)

Common needs for templating

Default value of the question is dynamic

Use something like:

[questions]
author.name.question = What's your name?
author.name.pre_ask_question = bobtemplates.mytemplate.hooks:pre_author

Where pre_author function will modify the question and provide new mrbob.configurator.Question.default.

Conditionally render a file

Use something like:

[template]
post_render = bobtemplates.mytemplate.hooks:delete_readme

And based on mrbob.Configurator.variables answers, delete a file or add one.

Based on the answer of the question do something

Use something like:

[questions]
author.name.question = What's your name?
author.name.post_ask_question = bobtemplates.mytemplate.hooks:post_author

Where post_author function will take mrbob.configurator.Configurator, question and it’s answer.

Ask a question based on answer of previous question

use post_ask_question and add another question (is that possible if we are looping through questions? -> While questions: questions.pop())

Hooks

A list of places where you can hook into the process flow and provide your custom code. All hooks can have multiple entries limited by whitespace.

Post render hook

If you would like to execute a custom Python script after rendering is complete, you can use post_render hook in your .mrbob.ini.

[template]
post_render = bobtemplates.mytemplate.hooks:my_post_render_function

This assumes you have a bobtemplate.mytemplate egg with a hooks.py module. This module contains a my_post_render_hook function, which gets called after mr.bob has finished rendering your template.

The function expects one argument (mrbob.configurator.Configurator) and looks something like this:

def my_post_render_function(configurator):
    if configurator.variables['author.email']:
        # do something here

Pre render hook

Much like the Post render hook example above, you can use pre_render variable in your .mrbob.ini to specify a function to call before rendering starts.

[template]
pre_render = bobtemplates.mytemplate.hooks:my_pre_render_function

Pre question hook

For maximum flexibility, mr.bob allows you to set hooks to questions. Using pre_ask_question in your .mrbob.ini allows you to run custom code before a certain question.

The function expects two arguments:
[questions]
author.name.question = What's your name?
author.name.pre_ask_question = bobtemplates.mytemplate.hooks:pre_author
def set_fullname(configurator, question):
    question.default = 'foobar'

If you want question to be skipped, simply raise mrbob.bobexceptions.SkipQuestion inside your hook.

Post question hook

Similar to Pre question hook example above, you can use post_ask_question variable in your .mrbob.ini to specify a function to call after a question has been asked. Post question hook must return the answer of the question.

The function expects three arguments:
[questions]
author.firstname.question = What's your name?
author.lastname.question = What's your surname?
author.lastname.post_ask_question = bobtemplates.mytemplate.hooks:set_fullname
def set_fullname(configurator, question, answer):
    configurator.variables['author.fullname'] =
        configurator.variables['author.firstname'] + ' ' +
        answer
    return answer

Raise mrbob.bobexceptions.ValidationError to re-ask the question.

Hooks shipped with mr.bob

See mrbob.hooks.

template section reference

Parameter Default Explanation
renderer mrbob.rendering:jinja2_renderer Function for rendering templates in dotted notation
pre_render None dotted notation function to run before rendering the templates
post_render None dotted notation function to run after rendering the templates