-
Notifications
You must be signed in to change notification settings - Fork 2
/
README.mdt
191 lines (125 loc) · 7.94 KB
/
README.mdt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# ![license_markplates](https://raw.githubusercontent.com/jima80525/markplates/master/license_markplates.jpg)
# MarkPlates
> A templating utility for keeping code included in Markdown documents in sync with the original source.
[![CircleCI](https://circleci.com/gh/jima80525/markplates.svg?style=svg)](https://circleci.com/gh/jima80525/markplates) ![black](https://img.shields.io/badge/code%20style-black-000000.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![pyup.io](https://pyup.io/repos/github/jima80525/markplates/shield.svg)](https://pyup.io/account/repos/github/jima80525/markplates/) [![PyPI version](https://badge.fury.io/py/markplates.svg)](https://badge.fury.io/py/markplates) [![Coverage Status](https://coveralls.io/repos/github/jima80525/markplates/badge.svg?branch=master)](https://coveralls.io/github/jima80525/markplates?branch=master)
The problem I hope to solve is to simplify keeping external files up to date with markdown documents that contain them. This happens to me frequently when an editor makes a suggestion to an article that will modify the underlying code it is quoting.
## Installing
You can download and install the latest version of MarkPlates from the PyPI with this command:
```bash
$ python3 -m pip install --upgrade markplates
```
MarkPlates is currently tested against Python 3.6, 3.7, 3.8, and 3.9.
## Usage
Running `markplates` is as simple as handing it a file:
```bash
$ markplates template.mdt
```
This will process the template in `template.mdt`, filling it in with data specified in the template.
The `examples` directory has the `simple.mdt` template:
```markdown
{{set_path("./examples")}}{{import_source("simple.mdt", ["1-$",])}}
```
This demonstrates setting the path and pulling in some of the lines of a file. You can also examine the `README.mdt` file in this library which is used to create this `README.md`.
To use on your own project create a markdown document with special tags to indicate a `markplates` function call. The delimiter for these tags is {{ '`{{` function goes here `}}`' }}.
> **Note:** if you need to add {{ '`{{`'}} characters which should not be processed as a template, you can put them in a {{ "`{{ '" "' }}` " }} block to escape them. Template processing is done with `Jinja2` so Markplates uses the same escape sequences.
`Markplates` supports these functions:
* `set_path("path/to/source/files", [show_skipped_section_marker])`
* `import_source("source_file_name", [list of line number ranges], language=None, filename=False)`
* `import_function("source_file_name", "function_name", language=None, filename=False)`
* `import_repl("code to run in repl")`
### `set_path()`
The `set_path()` function allows you to specify the base directory to use when searching for source files. Each call to this function will apply from that point in the template down.
The path must be included in single or double qoutes. If not specified, the path defaults to ".", the current directory.
Examples:
{{ '
```
{{set_path(".")}} #sets path to the default
{{set_path("/home/user/my/project")}} # points the path to your project
```
' }}
The `set_path()` command is not required as all other functions will take full paths to files.
This command takes an optional `show_skipped_section_marker` parameter which defaults to `False`. When set to true, if a template expansion shows disjoint sections of a file which are separated by 2 or more lines, that gap will be shown in the output with a marker line:
`# ...`
This option defaults to false to not break backward compatibility.
### `import_source()`
The `import_source()` function will pull in the contents of a source file. Optional line number ranges can be specified (see description below). The filename must be in quotes.
If no line number ranges are specified, the first line of the file will be omitted. This is to prevent the `#!/usr/bin/env python` line from cluttering the markdown article. If you want to include the first line, use the range: `1-$`.
Examples:
{{ '
```
{{import_source("__main__.py")}} # includes all but line 1 from `__main__.py` file
{{import_source("__main__.py", ["1-$",])}} # imports all lines from `__main__.py`
{{import_source("__main__.py", [1, "3", "5-$"])}} # imports all lines except lines 2 and 4 from `__main__.py`
{{import_source("__main__.py", language="python", filename=True)}}
# includes all but line 1 from `__main__.py` file, puts the
# contents in a python block with the filename as a comment in
# the first line of the block.
```
' }}
`MarkPlates` will display an error message to `stderr` if a file is not found.
### `import_function()`
The `import_function` function searches a source file for the named function, class, class method or assigned variable. The function name supports dot-references, for example to get at the class method `area()` inside the class `Sqaure`, the function name would be "Square.area". To retrieve a nested function, name both the parent and child function, for example "outer.inner".
The first piece of code matching the given name is returned, (and you shouldn't have multiple things with the same name anyway!). The source file is parsed, not loaded, so no import side-effects take place.
Whitespace following the function will not be included.
Examples:
{{ '
```
{{import_function("__main__.py", "condense_ranges")}} # imports the function named `condense_ranges` from `__main__.py`
```
' }}
The `language` and `filename` parameters are treated the same way they are in `import_source()`.
### `import_repl()`
The `import_repl` function takes the input parameter and splits it into separate lines. Each line of the input will be run in a REPL with the `stdout` and `stderr` captured to insert into the final output. The result should appear similar to a copy-paste from running the same commands manually.
There is an exception, however. Blank input lines are used for spacing and will not display the `>>>` prompt one would normally see in the REPL.
Example:
{{ '
```
{{import_repl(
"""
def func(x):
if x:
print(x)
func(True)
func(False) """) }}
```
' }}
Output:
```
>>> def func(x):
... if x:
... print(x)
>>> func(True)
True
>>> func(False)
```
### Line Number Ranges
Line number ranges allow you to specify which lines you want to include from the source file. Ranges can be in the following form:
* 3 or "3" : an integer adds just that line from the input
* "5-7" : a range adds lines between start and end inclusive (so 5, 6, 7)
* "10-$" : an unlimited range includes start line to the end of the file
* "$" : the last line
* "$-3" : negative indexing, the last line and the three lines that proceed it
> **Note:** LINE NUMBERING STARTS AT 1!
### Copy to Clipboard
The `-c` option will copy most of the output to the clipboard. The first two lines are skipped, which generally are the `h1` title and the following blank line. This is done to simplify copying the output to the Real Python CMS system.
### Square Brackets
The `-s` / `--square` option tells the parser to use `[[` and `]]` as the
function delimiters. Instead of `{{ ' {{ import_function("foo", "bar")
}} ' }}`, use `[[ import_function("foo", "bar") ]]`.
## Features to Come
I'd like to add:
* Developer Instructions
* Capturing the results of a shell command and inserting into the file
* Running `black` over the included Python source
* Windows and Mac testing/support
## Interested?
Let me know! If you're interested in the results or would like to help out, please raise an issue and I'll be in touch!
## Release History
* 1.6.0 Add `show_skipped` option to `set_path()` and improved error reporting
* 1.5.0 Added `$` and `$-n` as valid line ranges. Fixed several bugs
* 1.4.0 Added -c option, bug fixes
* 1.3.0 Minor bug fixes
* 1.2.0 Added `language` and `filename` options for `import_source` and `import_repl` methods
* 1.1.0 Added `import_repl` functionality
* 1.0.0 Initial release
License plate graphic thanks to [ACME License Maker](https://www.acme.com/licensemaker/)