1
1
[ ![ Build Status] ( https://img.shields.io/endpoint?url=https%3A%2F%2Fci.ocamllabs.io%2Fbadge%2Frealworldocaml%2Fmdx%2Fmain&logo=ocaml )] ( https://ci.ocamllabs.io/github/realworldocaml/mdx )
2
2
3
- ## mdx -- executable code blocks inside markdown files
3
+ ## MDX
4
4
5
- ` mdx ` allows to execute code blocks inside markdown files.
6
- There are (currently) two sub-commands, corresponding
7
- to two modes of operations: pre-processing (` ocaml-mdx pp ` )
8
- and tests (` ocaml-mdx test ` ).
5
+ MDX allows to execute code blocks inside markdown and mli documentation
6
+ to help keeping them up to date.
9
7
10
- The pre-processor mode allows to mix documentation and code,
11
- and to practice "literate programming" using markdown and OCaml.
8
+ Use the
9
+ [ dune stanza] ( https://dune.readthedocs.io/en/latest/dune-files.html#mdx-since-2-4 )
10
+ to enable it on your documentation.
12
11
13
- The test mode allows to ensure that shell scripts and OCaml fragments
14
- in the documentation always stays up-to-date.
15
-
16
- ` mdx ` is released as a single binary (called ` ocaml-mdx ` ) and
17
- can be installed using opam:
12
+ ` mdx ` is released on opam and can be installed by running:
18
13
19
14
``` sh
20
15
$ opam install mdx
21
16
```
22
17
23
- If you want to contribute or hack on the project, please see the
18
+ If you want to contribute to the project, please see the
24
19
[ CONTRIBUTING.md] ( CONTRIBUTING.md ) .
25
20
21
+ ### Basic Usage
22
+
23
+ You can use MDX with your Markdown or ` .mli ` documentation, which ensures
24
+ code in multi-line or verbatim code blocks is correct.
25
+
26
+ To enable MDX on specific files you must first enable it for your project by
27
+ adding the following stanza to your ` dune-project ` :
28
+ ```
29
+ (using mdx 0.2)
30
+ ```
31
+
32
+ Note that version ` 0.2 ` of the MDX stanza is only available in dune ` 3.0 ` or
33
+ higher. You can use the first, ` 0.1 ` version with dune ` 2.4 ` or higher.
34
+
35
+ Then add the following in the relevant ` dune ` file:
36
+ ```
37
+ (mdx)
38
+ ```
39
+ That enables MDX on all markdown files in the folder.
40
+ The MDX stanza can be further configured. Please visit the relevant section of
41
+ [ dune's manual] ( https://dune.readthedocs.io/en/latest/dune-files.html#mdx-since-2-4 )
42
+ for more information.
43
+
44
+ MDX supports various type of code blocks but the most common are OCaml toplevel
45
+ blocks. We illustrate one in our example below. In a Markdown file, you
46
+ would write something similar to this:
47
+
48
+ ```` markdown
49
+ Let's look at how good OCaml is with integers and strings:
50
+ ```ocaml
51
+ # 1 + 2;;
52
+ - : int = 2
53
+ # "a" ^ "bc";;
54
+ - : string = "ab"
55
+ ```
56
+ ````
57
+ or in an ` mli ` file:
58
+ ``` ocaml
59
+ (** Let's look at how good OCaml is with integers and strings:
60
+ {@ocaml[
61
+ # 1 + 2;;
62
+ - : int = 2
63
+ # "a" ^ "bc";;
64
+ - : string = "ab"
65
+ ]}
66
+ *)
67
+ ```
68
+
69
+ The content of the toplevel blocks looks just like an interactive toplevel
70
+ session. Phrases, i.e., the toplevel "input", start with a ` # ` and end with ` ;; ` .
71
+ The toplevel evaluation, or "output" follows each phrase.
72
+
73
+ Now you probably have noticed that ` 1 + 2 ` is not equal to ` 2 ` nor is ` "a" ^ "bc" `
74
+ to ` "ab" ` . Somebody must have updated the phrases, but then forgot to update
75
+ the evaluation.
76
+
77
+ That's exactly why MDX is here!
78
+
79
+ If you enable MDX for this file and then ran ` dune runtest ` , this would be the
80
+ result:
81
+
82
+ ````
83
+ $ dune runtest
84
+ File "README.md", line 1, characters 0-0:
85
+ git (internal) (exit 1)
86
+ (cd _build/default && /usr/bin/git --no-pager diff --no-index --color=always -u README.md .mdx/README.md.corrected)
87
+ diff --git a/README.md b/.mdx/README.md.corrected
88
+ index 181b86f..458ecec 100644
89
+ --- a/README.md
90
+ +++ b/.mdx/README.md.corrected
91
+ @@ -1,13 +1,13 @@
92
+ Let's look at how good OCaml is with integers and strings:
93
+ ```ocaml
94
+ # 1 + 2;;
95
+ -- : int = 2
96
+ +- : int = 3
97
+ # "a" ^ "bc";;
98
+ -- : string = "ab"
99
+ +- : string = "abc"
100
+ ```
101
+ ````
102
+
103
+ The test run just failed and dune is showing the diff between what we have
104
+ locally and what should be, according to MDX.
105
+ This uses dune's promotion workflow so at this point you can either investigate
106
+ it further if you're surprised by this diff or if you're happy with it, simply
107
+ accept it by running:
108
+
109
+ ```
110
+ dune promote
111
+ ```
112
+
113
+ Now the documentation is up-to-date and running ` dune runtest ` again should be
114
+ successful!
115
+
26
116
### Supported Extensions
27
117
28
118
#### Labels
29
119
30
- The blocks in markdown files can be parameterized by ` mdx ` -specific labels, that
120
+ The blocks can be parameterized by ` mdx ` -specific labels, that
31
121
will change the way ` mdx ` interprets the block.
32
122
33
- The syntax is: ` <!-- $MDX LABELS --> ` , where ` LABELS ` is a list of valid labels
34
- separated by a comma. This line has to immediately precede the block it is
35
- attached to.
123
+ The markdown syntax is: ` <!-- $MDX LABELS --> ` , where ` LABELS ` is a list of
124
+ valid labels separated by a comma. This line has to immediately precede the
125
+ block it is attached to.
36
126
37
127
<!-- $MDX LABELS -->
38
128
```ocaml
39
129
```
40
130
41
- This syntax is the recommended way to define labels since ` mdx ` 1.7.0, to use
42
- the previous syntax please refer to the
43
- [ mdx 1.6.0 README] ( https://github.com/realworldocaml/mdx/blob/1.6.0/README.md ) .
44
-
45
- It is also possible to use labels in OCaml interface files (` mli ` ), the syntax
46
- for this is is slightly different to match the conventions of OCaml
47
- documentation comments:
131
+ The ` .mli ` syntax for this is is slightly different to match the conventions of
132
+ OCaml documentation comments:
48
133
49
134
(** This is an documentation comment with an ocaml block
50
135
{@ocaml LABELS [
@@ -93,7 +178,7 @@ with a padding of 3:
93
178
10
94
179
```
95
180
96
- ` ocaml-mdx ` will also consider exit codes when the syntax ` [<exit code>] ` is used:
181
+ MDX will also consider exit codes when the syntax ` [<exit code>] ` is used:
97
182
98
183
```sh
99
184
$ exit 1
@@ -105,7 +190,7 @@ of success).
105
190
106
191
#### OCaml Code
107
192
108
- ` ocaml-mdx ` interprets OCaml fragments. It understands _ normal_ code fragments and
193
+ MDX interprets OCaml fragments. It understands _ normal_ code fragments and
109
194
_ toplevel_ code fragments (starting with a ` # ` sign and optionally ending with
110
195
` ;; ` ). Arbitrary whitespace padding is supported, at long as it stays
111
196
consistent within a code block.
@@ -126,7 +211,8 @@ Here is an examples of toplevel OCaml code:
126
211
```
127
212
128
213
### File sync
129
- ` mdx ` is also capable of including content from files in fenced code blocks
214
+
215
+ MDX is also capable of including content from files in fenced code blocks
130
216
using the label ` file ` . OCaml files can be sliced using named blocks:
131
217
132
218
``` ocaml
@@ -149,38 +235,6 @@ Non-OCaml files can also be read and included in a block:
149
235
```
150
236
However, part splitting is only supported for OCaml files.
151
237
152
- ### Pre-processing
153
-
154
- ` ocaml-mdx pp ` allows to transform a markdown file into a valid
155
- OCaml file, which can be passed to OCaml using the ` -pp `
156
- option.
157
-
158
- For instance, given the following ` file.md ` document:
159
-
160
- ```ocaml
161
- # print_endline "42"
162
- 42
163
- ```
164
-
165
- Can be compiled and executed using:
166
-
167
- ``` sh
168
- $ ocamlc -pp ' ocaml-mdx pp' -impl file.md -o file.exe
169
- $ ./file.exe
170
- 42
171
- ```
172
-
173
- This can be automated using ` dune ` :
174
-
175
- ```
176
- (rule
177
- ((targets (file.ml))
178
- (deps (file.md))
179
- (action (with-stdout-to ${@} (run ocaml-mdx pp ${<})))))
180
-
181
- (executable ((name file)))
182
- ```
183
-
184
238
### Tests
185
239
186
240
#### Cram Tests
@@ -209,51 +263,6 @@ To execute OCaml code and toplevel fragments, uses `ocaml-mdx test <file.md>`.
209
263
If the output is not consistent with what is expected
210
264
` <file.md>.corrected ` is generated.
211
265
212
- #### Integration with Dune
213
-
214
- To test that the code blocks of ` file.md ` stay consistent, one can use
215
- dune's ` mdx ` stanza:
216
-
217
- ```
218
- (mdx
219
- (files file.md))
220
- ```
221
-
222
- This allows to test the consistency of a markdown file using the normal dev
223
- workflow:
224
-
225
- ```
226
- $ dune runtest
227
- ```
228
-
229
- will display a diff of the output if something has changed. For instance:
230
-
231
- ```
232
- $ dune runtest
233
- ------ file.md
234
- ++++++ file.md.corrected
235
- File "file.md", line 23, characters 0-1:
236
- |
237
- |```sh
238
- -| $ for i in `seq 1 3`; do echo $i; done
239
- +| $ for i in `seq 1 4`; do echo $i; done
240
- | 1
241
- | 2
242
- | 3
243
- +| 4
244
- |```
245
- ```
246
-
247
- And the changes can then be accepted using:
248
-
249
- ```
250
- $ dune promote
251
- ```
252
-
253
- For further details about the mdx stanza you should read the
254
- [ according section] ( https://dune.readthedocs.io/en/latest/dune-files.html#mdx-since-2-4 )
255
- in the dune documentation.
256
-
257
266
#### Non-deterministic Tests
258
267
259
268
** Non-deterministic Outputs**
@@ -373,10 +382,3 @@ Those variables are then available in the subsequent blocks
373
382
bar
374
383
- : unit = ()
375
384
```
376
-
377
- ### Sections
378
-
379
- It is possible to test or execute only a subset of the file using
380
- sections using the ` --section ` option (short name is ` -s ` ). For
381
- instance ` ocaml-mdx pp -s foo ` will only consider the section matching the
382
- perl regular expression ` foo ` .
0 commit comments