Skip to content

Commit e8b3f45

Browse files
author
Laurent Franceschetti
committed
Document hooks for #237 (register macros/variables/filters)
1 parent c1029d5 commit e8b3f45

File tree

4 files changed

+174
-2
lines changed

4 files changed

+174
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## Cutting Edge (GitHub Only)
7+
## 1.2.0, 2024-09-15
8+
* Added: three hooks `register_variables/macros/filters` to facilitate
9+
cooperation with other MkDocs plugins.
810
* Fixed: `define_env() was always required in module (#191)
911
* Added: trace the case when no module is found (INFO)
1012
* Improved documentation, particularly about HTML pages

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# Initialization
1313
# --------------------
1414

15-
VERSION_NUMBER = '1.1.3'
15+
VERSION_NUMBER = '1.2.0'
1616

1717
# required if you want to run document/test
1818
# pip install 'mkdocs-macros-plugin[test]'

webdoc/docs/registration.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Registering macros/variables/filters in MkDocs-Macros
2+
3+
!!! Info "Important note"
4+
This is technical documentation for writers of MkDocs Plugins.
5+
6+
7+
## Introduction
8+
9+
This is description of how other MkDocs [plugins](https://www.mkdocs.org/dev-guide/plugins/) (see [a list]([existing plugins](https://github.com/mkdocs/catalog)))
10+
can register their macros and variables with MkDocs-Macros.
11+
12+
There can exist two motivations:
13+
14+
1. Provide additional functionality to the plugin, by providing
15+
macros, variables and filters, accessible through MkDocs-Macros.
16+
2. Resolve syntax incompatibility issues, if the plugin uses a syntax
17+
similar to Jinja2 (typically expressions between `{{` and `}}`).
18+
19+
## Syntax Incompatibility between plugins
20+
21+
### Description of the issue
22+
23+
MkDocs-Macros was written so that it does not interact with other plugins;
24+
it interacts only with MkDocs' events.
25+
26+
However, there might be a number of reasons why incompatibilities
27+
could occur.
28+
29+
!!! Note
30+
The most common one derives from the fact that
31+
MkDocs-Macros uses the Jinja2 syntax
32+
(typically expressions between `{{` and `}}`).
33+
34+
For example a plugin might define `foo(x)` as a function,
35+
which might need a call as `{{ foo(x) }}` in a Markdown page.
36+
37+
The plugin might fail
38+
(if declared before MkDocs-Macros in the [config file's list of plugins](https://www.mkdocs.org/user-guide/configuration/#plugins),
39+
because it now sees many calls with the same syntax
40+
that it can't interpret),
41+
or might make MkDocs-Macros fail (if declared later), since
42+
it is very strict and won't accept a non existent macro.
43+
44+
45+
46+
!!! Tip
47+
Workarounds exist to change the way MkDocs-Macros handles syntax.
48+
49+
They are described in the page on
50+
[controlling macros rendering](rendering.md).
51+
52+
They can be useful if MkDocs-Macros is used as a secondary plugin.
53+
They might be inadequate if MkDocs-Macros is considered "core".
54+
55+
56+
### Solutions without plugin
57+
58+
- A [macros module](macros.md) is the simplest a fastest solution,
59+
for solving a specific need that requires a simple function.
60+
- For a solution across several documentation projects,
61+
[pluglets](pluglets.md) were introduced so that a developer
62+
could quickly develop a solution from scratch, that does not
63+
involve a plugin. Pluglets are macros module easily distributable
64+
through Pypi.
65+
66+
67+
!!! Warning "What about rewriting existing a Plugin as an MkDocs-Macros pluglet?"
68+
69+
This could be a solution.
70+
71+
**However, it might not be convenient or desirable for the author of a
72+
plugin to rewrite it as pluglet**.
73+
74+
**A solution had to be found for that case.**
75+
76+
77+
## How to adapt a plugin to register macros, filters and variables
78+
79+
80+
### Theory
81+
82+
Existing MkDocs plugins might find advantage in using MkDocs-Macros's
83+
framework as a support for their own "macros", if they use the same syntax.
84+
85+
This is done extremely easily, with the use of three methods
86+
exported by the `MacrosPlugin` class (itself based on `BasePlugin`).
87+
88+
- `register_macros()`, which takes a dictionary of Python functions
89+
(Callables) as argument. Those functions must return an `str` result,
90+
or some object that can be converted to that type.
91+
- `register_variables()`, which takes a dictionary of Python variables
92+
as argument.
93+
- `register_filters()`, which takes a dictionary of Jinja2 filters
94+
as an argument (see [definition in the official documentation](https://jinja.palletsprojects.com/en/3.0.x/templates/#filters)).
95+
For our purposes,filters are Python callables where the first argument becomes
96+
implicit (it is considered as the input value before the `|` symbol).
97+
98+
99+
!!! Tip "Independence from the declaration order"
100+
These macros are designed to work independently from the order
101+
in which MkDocs plugins are declared.
102+
103+
- If the plugin is declared **before** Mkdocs-Macros, then the
104+
macros/variables/filters will be "kept aside" and registered last,
105+
at the [`on_config`](https://www.mkdocs.org/dev-guide/plugins/#on_config) event.
106+
- If the plugin is declared **after** Mkdocs-Macros, then
107+
the items will be registered immediately.
108+
109+
In both cases, a conflict with a pre-existing macro/variable/filter
110+
name will raise a `KeyError` exception.
111+
112+
113+
### Practice
114+
115+
You want to register those macros/filters/variables
116+
at the `on_config()` method of your plugin, providing
117+
the MkDocs-Macros plugin is declared.
118+
119+
Its argument `config` allows you to access the Mkdocs-Macros plugin (`macros`),
120+
and its three registration methods.
121+
122+
```python
123+
124+
def foo(x:int, y:str):
125+
"First macro"
126+
return f"{x} and {y}"
127+
128+
def bar(x:int, y:int):
129+
"Second macro"
130+
return x + y
131+
132+
def scramble(s:str, length:int=None):
133+
"""
134+
Dummy filter to reverse the string and swap the case of each character.
135+
136+
Usage in Markdown page:
137+
138+
{{ "Hello world" | scramble }} -> DLROw OLLEh
139+
{{ "Hello world" | scramble(6) }} -> DLROw
140+
"""
141+
r = s[::-1].swapcase()
142+
if length is not None:
143+
r = r[:length]
144+
return r
145+
146+
147+
MY_FUNCTIONS = {"foo": foo, "bar": bar}
148+
MY_VARIABLES = {"x1": 5, "x2": 'hello world'}
149+
MY_FILTERS = {"scramble": scramble}
150+
151+
152+
153+
class MyPlugin(BasePlugin):
154+
"Your existing MkDocs plugin"
155+
156+
...
157+
158+
def on_config(self, config, **kwargs):
159+
160+
# get MkdocsMacros plugin, but only if present
161+
macros_plugin = config.plugins.get("macros")
162+
if macros_plugin:
163+
macros_plugin.register_macros(MY_FUNCTIONS)
164+
macros_plugin.register_variables(MY_VARIABLES)
165+
macros_plugin.register_filters(MY_VARIABLES)
166+
```
167+
168+
169+

webdoc/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ nav:
2727
- Controlling macros rendering: rendering.md
2828
- Post-production: post_production.md
2929
- Writing pluglets: pluglets.md
30+
- Registering macros/variables/filters: registration.md
3031
- Faq:
3132
- "Tips and Tricks": tips.md
3233
- "Troubleshooting": troubleshooting.md

0 commit comments

Comments
 (0)