From 1f93e3d1064a87e5ab551c4ee0b2bcc8e6152bad Mon Sep 17 00:00:00 2001 From: Laurent Franceschetti Date: Wed, 16 Sep 2020 09:53:48 +0200 Subject: [PATCH] Add reference page for variables and macros (#1917) --- docs/reference/variables-macros.md | 332 +++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 333 insertions(+) create mode 100644 docs/reference/variables-macros.md diff --git a/docs/reference/variables-macros.md b/docs/reference/variables-macros.md new file mode 100644 index 000000000..205224ea3 --- /dev/null +++ b/docs/reference/variables-macros.md @@ -0,0 +1,332 @@ +--- +template: overrides/main.html +--- + +# Variables and Macros + +The power of the Markdown language comes from its simplicity and +visual clarity. Its downside is that it far more limited than HTML. +That is the reason why Markdown extensions have been developed, +such as [Footnotes](../Footnotes) or [Admonition](../Admonition) +(for notes and tips). + +Sometimes, however, one wishes to add more customization +to Markdown pages, to perform tasks that are +specific to the documentation project. +This is the purpose of **variables** and **macros**, provided +by the [macros plugin](https://github.com/fralau/mkdocs_macros_plugin). + +!!! Note "Example" + + ``` + The unit price of product A is {{ unit_price }} EUR. + The sale price of {{ no }} units is {{ price(no, unit_price) }} EUR. + ``` + + If you defined a variable `no`w with a value of 50, + a variable `unit_price` with a value of 10, + and a macro `price()` (which multiplies the two), this could translate into: + + ``` + The unit price of product A is 10.00 EUR, + and the sale price of 50 units is 500.00 EUR. + ``` + + +Those who have used **wikis** engines (user-editable websites) +in the past are probably already familiar with those notions. + +!!!Tip + You may also use this + plugin to add **buttons** or other advanced functionality + (e.g. pulling data from a database) that is ordinarily + not provided by Markdown or one of its extensions. + + + +## Configuration + +The [macros plugin](https://github.com/fralau/mkdocs_macros_plugin) +makes it easier for contributors of an MkDocs website to produce richer and more beautiful pages. It enriches pages with calls to variables and macros. + + +!!! Note + This plugin has been tested to work with the **Material** theme. + It is also compatible with most other themes. + + +See the [installations instructions](https://mkdocs-macros-plugin.readthedocs.io/en/latest/#installation) for the plugin. + + +In order to make it work with your MkDocs project, +declare it in the config file: + +```yaml +plugins: + - search + - macros +``` + + +!!!Tip + The recommended way to check that the plugin works properly is to add the following line in one of the pages of your site + (typically `index.md`): + + ``` + {{ macros_info() }} + ``` + + If the plugin is properly installed, this will display + a test page with lots of information, especially predefined + variables and macros. + + +## Usage + +### Variables + +**Variables** are names with an attached value +(Markdown, HTML, ...), which can be reused anywhere in the pages. +Changing the value of the variable, will +change the text displayed, in all markdown pages +where this variable is called; this is useful for consistency. + + + +#### Predefined Variables + +With the macros plugin, a large set of predefined variables +are available out of the box, e.g. : + +Example | Description +--- | --- +`{{ config.site_name }}` | main title of the website +`{{ environment.system }}`| name of the OS +`{{ page.title }}` | title of the page +`{{ git.short_commit}} ({{ git.date}}) by {{ git.author}}` | **git information** (if applicable) + + +!!! Tip "Discoverability" + To explore the possibilities, just insert the + following code into one of the Markdown pages: + + ``` + {{ macros_info() }} + ``` + +#### Defining Variables + +All variables defined under `extra` in your config file become +available: + +```yaml +extra: + price: 12.50 + company: + name: Acme + address: .... + website: www.acme.com +``` + +This becomes available as, e.g.: + +```html +The price of the product is {{ price }}. + +See [more information on the website]({{ company.website }}). + +See more information on the website. +``` + +### Macros + +**Macros** are Python functions that return a value (Markdown, HTML...) +which depends on something else. + +A macro may have arguments, +or depend on conditions that change every time MkDocs +is run again (e.g. time or version number, etc.). + +Writing a macro is very easy: it requires only basic knowledge of Python, +and clear idea of what string result (Markdown, HTML, ...) +you want to produce. + +!!! Note + In principle the result must be a string, + but it could be _any type or class_ + as long it is translatable into a string. + + +#### Location of the Macros' Code + +By default, your macros are defined in a `main.py` file, +which is located in website's project directory +(generally beside the `mkdocs.yml` file). +You may [change that location and name](https://mkdocs-macros-plugin.readthedocs.io/en/latest/python/#location-of-the-module). + +#### Example 1: Arithmetics + +Imagine you want to calculate the cost of a batch, with +the unit price and the no of items, plus a 10% shipping costs: + +``` +This will cost {{ total_price(4, 12.50)}} dollars. +``` + +Which will be translated into: + +``` +This will cost 55 dollars. +``` + +But if `unit_price` and `quantity` have been defined under `extra`: + +```yaml +extra: + quantity: 4 + unit_price: 12.50 +``` + +``` +This will cost {{ total_price(quantity, unit_price)}} dollars. +``` + +??? Tip "Module content" + The module will look as follows: + + ```python + """ + Basic example of a Mkdocs-macros module + """ + + import math + + def define_env(env): + """ + This is the hook for defining macros + """ + + @env.macro + def total_price(quantity, unit_price): + "Calculate the price plus shipping costs + price = quantity * unit_price + shipping_costs = price * 10% + return price + shipping_costs + ``` + +#### Guidelines + +1. All you need to define is a `define_env(env)` function. + +2. To declare a Python function as a macro, just precede it by the +`@env.macro` decorator. +It will appear in the documentation produced by `{{ macros_info() }}` + +3. You may define as many macros as needed under `define_env()`. + +4. Write a macro's docstring from the viewpoint of the users who will + use it (it will be displayed in the macro's description). + +#### Example 2: Creating a Button + +This function is alternative, more flexible way to generate a button +(see [Buttons](../buttons#adding-buttons)): + +In your markdown page: + +``` +{{ button('Try this', 'https://your.website.com/page') }} +``` + +Result: + + + +[Try this](https://your.website.com/page){: .md-button } + + +??? Tip "Module content" + + In your Python module: + + ```python + def define_env(env): + """ + This is the hook for defining macros + """ + # Optional: a special function for making relative urls point to root + fix_url = env.variables.fix_url + + @env.macro + def button(label, url): + "Add a button" + url = fix_url(url) + HTML = """%s""" + return HTML % (url, label) + ``` + + + + +## Advanced Usage: Jinja2 Constructs + +The macros plugin relies on the [Jinja2](https://jinja.palletsprojects.com/en/2.11.x/templates/) template engine. + +This makes the facilities of that template engine available +within a Markdown page. + + + +!!! Note + Not that this is distinct from the standard, low-level use of Jinja2 by + MkDocs to convert the Markdown pages into HTML. + In principle this will **not** interfere with it. + +### Conditions and Loops +Most of what is described in its documentation, +including constructs such as + +- [conditions](https://jinja.palletsprojects.com/en/2.11.x/templates/#if): + `{% if ... %}` +- [loops](https://jinja.palletsprojects.com/en/2.11.x/templates/#for): + `{% for ... %} ` + + +will work out of the box. + +!!! Tip + Instead of using Jinja2 constructs to generate pure HTML + as in the examples shown, + you could use them to generate Markdown, + or whichever mix of Markdown, HTML, CSS + or even Javascript that might be required for your needs. + +### Filters + +Jinja2's [built-in filters](https://jinja.palletsprojects.com/en/2.11.x/templates/#list-of-builtin-filters) are available e.g. : + +`{{ "HELLO WORLD" | lower }}` results in `hello world` + +You may [write your own filters in the Python module](https://mkdocs-macros-plugin.readthedocs.io/en/latest/python/#defining-macros-and-filters-as-well-as-variables), +using the `@env.filter` decorator. + +### Including External Files + +Quite aside from variables and macros, you may include external files +containing snippets (typically, Markdown files). + +You may use the include directive from jinja2, directly in your markdown code e.g.: + + ## Paragraph + {% include 'snippet.md' %} + +Including another markdown file will therefore execute the macros. + +By default, the relative path for included files starts from `docs`, +but [this can be changed](https://mkdocs-macros-plugin.readthedocs.io/en/latest/advanced/#changing-the-directory-of-the-includes). + +## More Information on the Macros Plugin + +* [Main documentation page](https://mkdocs-macros-plugin.readthedocs.io/en/latest/) +* [Including git information in a page](https://mkdocs-macros-plugin.readthedocs.io/en/latest/git_info/) +* [Writing macros and filters](https://mkdocs-macros-plugin.readthedocs.io/en/latest/python/) diff --git a/mkdocs.yml b/mkdocs.yml index 8245583eb..27026050e 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -178,6 +178,7 @@ nav: - Lists: reference/lists.md - MathJax: reference/mathjax.md - Meta tags: reference/meta-tags.md + - Variables and macros: reference/variables-macros.md - Changelog: - Release notes: changelog.md - Upgrading: upgrading.md