View Source FancyFences (fancy_fences v0.3.1)
Post-process code blocks in your markdown docs.
FancyFences is a tiny wrapper around ExDoc.Markdown.Earmark that post processes
fenced markdown code blocks. You can use it to:
- Ensure that the code examples are up to date with your code.
- Automatically inject the output of the code block.
- Enrich your docs with VegaLite plots or mermaid charts.
- Use it in a more hacky way when interpolation is not possible.
Usage
In order to use FancyFences you need to set the :markdown_processor option
in the :docs section as following:
docs: [
markdown_processor: {FancyFences, [fences: processors]}
]where processors is expected to be a map with all processors that will be
applied on code blocks. The keys of the proecessors map are the code
language on which this specific processor will be applied. The values of the
processors map are expected to be mfa tuples with the function that will be
applied. For example the following configuration:
docs: [
markdown_processor: {FancyFences, [fences: fancy_processors()]}
]
defp fancy_processors do
%{
"elixir" => {FancyFences.Processors, :format_code, []},
"elixir::inspect" => FancyFences.Processors, :inspect_code, [])
}
endwill apply two processors:
- Each
elixircode block will be post-processed using theFancyFences.Processors.format_code/1which will format the inline code. - Each
elixir::inspectcode block will be post-processed using theFancyFences.Processors.inspect_code/2which will replace the existing code block with two blocks:- An
:elixircode block including the initial code - A second
:elixirblock with the output of the evaluation of the first block.
- An
This is useful for evaluating during docs generation fenced code blocks, without having to
manually write the expected output, also ensuring that your docs are always up to date, since
if the underlying functions change then mix docs will fail.
Recursive application of fence processors
Norice that fence processors are applied recursively. This means that in the previous example the
elixirinjected code blocks will also be processed by the format processor, ensuring that both the raw code input and the evaluation output will be properly formatted.
Fence processors
Fence processors are simple elixir functions that expect as input a string corresponding to the code in the markdown code block and an optional keyword list and return a markdown that will be injected in the docs.
Writing a custom processor
Let's see a real world example, how Tucan uses
FancyFences in order to render both the sample code and the corresponding vega-lite
specification.
Tucan defines a fence processor that it expects a code blocks that returns a VegaLite
struct and it generates two code blocks:
- The original code formatted.
- The
jsonvega-litespecification of theVegaLitestruct.
def tucan(code, _opts \\ []) do
{%VegaLite{} = plot, _} = Code.eval_string(code, [], __ENV__)
spec = VegaLite.to_spec(plot)
"""
```elixir
#{Code.format_string!(code)}
```
```vega-lite
#{Jason.encode!(spec)}
```
"""
endIn order to enable it you only need to configure to which markdown code language this
will be applied. In the Tucan case it is applied on code blocks marked as tucan:
docs: [
markdown_processor:
{FancyFences,
[
fences: %{
"tucan" => {Tucan.Docs, :tucan, []}
}
]},
]