summaryrefslogtreecommitdiff
path: root/subplot.md
blob: 59e973613e6796a0c2e83ef2f1911c32367bc147 (plain)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
---
title: "Subplot"
author: The Subplot project
date: work in progress
bindings: subplot.yaml
functions: subplot.py
...


Introduction
=============================================================================

Subplot is software to help capture and communicate acceptance
criteria for software and systems, and how they are verified, in a way
that's understood by all project stakeholders. The current document
contains the acceptance criteria for Subplot itself, and its
architecture.

The acceptance criteria are expressed as _scenarios_, which roughly
correspond to use cases. The scenario as accompanied by explanatory
text to explain things to the reader. Scenarios use a given/when/then
sequence of steps, where each step is implemented by code provided by
the developers of the system under test. This is very similar to the
[Cucumber][] tool, but with more emphasis of producing a standalone
document.

[Cucumber]: https://en.wikipedia.org/wiki/Cucumber_(software)

### Subplot architecture

Subplot reads an input document, in Markdown, and generates a typeset
output document, as PDF or HTML, for all stakeholders to understand.
Subplot also generates a test program, in Python, that verifies the
acceptance criteria are met, for developers and testers and auditors
to verify the sustem under test meets its acceptance criteria. The
generated program uses code written by the Subplot user to implement
the verification steps. The graph below illustrates this and shows how
data flows through the system.

```dot
digraph "architecture" {
md [label="foo.md \n (document, Markdown)"];
md [shape=box];

bindings [label="foo.myaml \n (bindings, YAML)"];
bindings [shape=box];

impl [label="foo.py \n (step implemenations, Python)"]
impl [shape=box];

subplot [label="Subplot"];
subplot [shape=ellipse];

pdf [label="foo.pdf \n PDF (generated)"]
pdf [shape=note];

html [label="foo.html \n HTML (generated)"]
html [shape=note];

testprog [label="test.py \n test program\n(generated)"]
testprog [shape=note];

report [label="Test report \n (stdout of test.py)"]
report [shape=note];

md -> subplot;
bindings -> subplot;
impl -> subplot;
subplot -> pdf;
subplot -> html;
subplot -> testprog;
testprog -> report;
}
```

[Pandoc]: https://pandoc.org/

Subplot uses the [Pandoc][] software for generating PDF and HTML
output documents. In fact, any output format supported by Pandoc can
be requested by the user. Depending on the output format, Pandoc may
use, for example, LaTeX. Subplot interprets parts of the Markdown
input file itself.

Subplot actually consists mainly of two separate programs: 
**sp-docgen** for generating output documents, and **sp-codegen** for
generating the test program. There are a couple of additional tools
(**sp-meta** for reporting meta data about a Subplot document, and
**sp-filter** for doing the document generation as a Pandoc filter).

Thus a more detailed architecture view is shown below.

```dot
digraph "architecture2" {
md [label="foo.md \n (document, Markdown)"];
md [shape=box];

bindings [label="foo.myaml \n (bindings, YAML)"];
bindings [shape=box];

impl [label="foo.py \n (step implemenations, Python)"]
impl [shape=box];

docgen [label="sp-docgen"];
docgen [shape=ellipse];

codegen [label="sp-codegen"];
codegen [shape=ellipse];

pdf [label="foo.pdf \n PDF (generated)"]
pdf [shape=note];

html [label="foo.html \n HTML (generated)"]
html [shape=note];

testprog [label="test.py \n test program\n(generated)"]
testprog [shape=note];

report [label="Test report \n (stdout of test.py)"]
report [shape=note];

md -> docgen;
bindings -> docgen;
md -> codegen;
bindings -> codegen;
impl -> codegen;
docgen -> pdf;
docgen -> html;
codegen -> testprog;
testprog -> report;
}
```

A fairy tale of acceptance testing
-----------------------------------------------------------------------------

The king was upset. This naturally meant the whole court was in a
tizzy and chattering excitedly at each other, while trying to avoid
the royal wrath.

"Who will rid me of this troublesome chore?" shouted the king, and
quaffed a flagon of wine. "And no killing of priests, this time!"

The grand hall's doors were thrown open. The grand wizard stood in the
doorway, robe, hat, and staff everything, but quite still. After the
court became silent, the wizard strode confidently to stand before the
king.

"What ails you, my lord?"

The king looked upon the wizard, and took a deep breath. It does not
do to shout at wizards, for they control dragons, and even kings are
tasty morsels to the great beasts.

"I am tired of choosing what to wear every day. Can't you do
something?"

The wizard stoke his long, grey beard. He turned around, looked at the
magnificent outfits worn by members of the court. He turned back, and
looked at the king.

"I believe I can fix this. Just to be clear, your beef is with having
to choose clothing, yes?"

"Yes", said the king, "that's what I said. When will you be done?"

The wizard raised his staff and brought it back down again, with a
loud bang.

"Done" said the wizard, smugly.

The king was amazed and started smiling, until he noticed that
everyone, including himself, was wearing identical burlap sacks and
nothing on their feet. His voice was high, whiny, like that of a
little child.

"Oh no, that's not at all what I wanted! Change it back! Change it
back now!"

The morale of this story is to be clear and precise in your acceptance
criteria, or you might get something other than what you really, really
wanted.


Motivation for Subplot
-----------------------------------------------------------------------------

Keeping track of requirements and acceptance criteria is necessary for
all but the simplest of software projects. Having all stakeholders in
a project agree to them is crucial, as is that all agree how it is
verified that the software meets the acceptance criteria. Subplot
provides a way for documenting the shared understanding of what the
acceptance criteria are and how they can be checked automatically.

Stakeholders in a project may include:

* those who pay for the work to be done; this may be the employer of
  the developers for in-house projects ("*customer*")
* those who use the resulting systems, whether they pay for it or not
  ("*user*")
* those who install and configure the systems and keep them functional
  ("*sysadmin*")
* those who support the users ("*support*")
* those who test the project for acceptability ("*tester*")
* those who develop the system in the first place ("*developer*")

The above list is incomplete and simplistic, but suffices as an
example.

All stakeholders need to understand the acceptance criteria, and how
the system is evaluated against the criteria. In the simplest case,
the customer and the developer need to both understand and agree so
that the developer knows when the job is done, and the customer knows
when they need to pay their bill.

However, even when the various stakeholder roles all fall upon the
same person, or only on people who act as developers, the Subplot
tooling can be useful. A developer would understand acceptance
criteria expressed only in code, but doing so may take time and energy
that are not always available. The Subplot approach aims to encourage
hiding unnecessary detail and documenting things in a way that is easy
to understand with little effort.

Unfortunately, this does mean that for a Subplot output document to
be good and helpful, writing it will require effort and skill. No tool
can replace that.


Requirements
=============================================================================

This chapter lists requirements for Subplot. These requirements are
not meant to be automatically verifiable. For specific, automatically
testable acceptance criteria, see the later [chapter with acceptance
tests for Subplot](#acceptance).

Each requirement here is given a unique mnemnoic id for easier
reference in discussions.

**UnderstandableTests**

:   Acceptance tests should be possible to express in a way that's
    easily understood by all stakeholders, includcing those who are
    not software developers.

    _Done_ but requires the Subplot document to be written with care.

**EasyToWriteDocs**

:   The markup language for writing documentation should be easy to
    write.

    _Done_ by using Markdown.

**AidsComprehension**

:   The formatted human-readable documentation should use good layout
    and typography to enhance comprension.

    _In progress_ — typesetting via Pandoc works, but may need
    review and improvement.

**CodeSeparately**

:   The code to implement the acceptance criteria should not be
    embedded in the documentation source, but be in separate files.
    This makes it easier to edit without specialised tooling.

    _Done_ by keeping scenario step implementations in a separate
    file.

**AnyProgammingLanguage**

:   The developers implementing the acceptance tests should be free to
    use a language they're familiar and comfortable with. Subplot
    should not require them to use a specific language.

    _Not done_ — only Python supported at the moment.

**FastTestExecution**

:   Executing the acceptance tests should be fast.

    _Not done_ &mash; the generated Python test program is simplistic
    and linear.

**NoDeployment**

:   The acceptance test tooling should assume the system under test is
    already deployed and available. Deploying is too big of a problem
    space to bring into the scope of acceptance testing, and there are
    already good tools for deployment.

    _Done_ by virtue of letting those who implement the scenario steps
    worry about it.

**MachineParseableResults**

:   The tests should produce a machine parseable result that can be
    archived, post-processed, and analyzed in ways that are of
    interest to the project using Subplot. For example, to see trends
    in how long tests take, how often tests fail, to find regressions,
    and to find tests that don't provide value.

    _Not done_ — the generated test program is simplistic.


Subplot input language
=============================================================================

Subplot reads three input files, each in a different format:

* The document file, which uses the Markdown dialect understood by
  Pandoc.
* The bindings file, in YAML.
* The functions file, in Python.

Subplot interprets specially marked parts of the input document
specially. It does this via the Pandoc abstract syntax tree, rather
than text manipulation, and thus anything that Pandoc understands is
understood by Subplot. We will not specify Pandoc's dialect of
Markdown here, only the parts Subplot pays attention to.


Document metadata
-----------------------------------------------------------------------------

Pandoc supports, and Subplot makes use of, a [YAML metadata block][] in a
Markdown document. This can and should be used to set the document
title, authors, date (version), and can be used to control some of the
typesetting. Crucially for Subplot, the bindings and functions files
are named in the metadata block, rather than Subplot deriving them
from the input file name.

[YAML metadata block]: https://pandoc.org/MANUAL.html#extension-yaml_metadata_block

As an example, the metadata block for the Subplot document might look
as follows. The `---` before and `...` after the block are mandatory:
they are how Pandoc recongizes the block.

~~~{.yaml .numberLines}
---
title: "Subplot"
author: The Subplot project
date: work in progress
bindings: subplot.yaml
functions: subplot.py
...
~~~


Document markup
-----------------------------------------------------------------------------

[fenced code blocks]: https://pandoc.org/MANUAL.html#fenced-code-blocks

Subplot understands certain tags for [fenced code blocks][] specially.
A scenario, for example, would look like this:

~~~~~~{.markdown .numberLines}
```scenario
given a standard setup
when peace happens
then everything is OK
```
~~~~~~

The `scenario` tag on the code block is recognized by Subplot, which
will typeset the scenario (in output documents) or generate code (for
the test program) accordingly. Scenario blocks do not need to be
complete scenario. Subplot will collect all the snippets into one
block for the test program. Snippets under the same heading belong
together; the next heading of the same or a higher level ends the
scenario.

For embedding test data files in the Markdown document, Subplot
understands the `file` tag:

~~~~~~~~markdown
~~~{.file #filename}
This data is accessible to the test program as 'filename'.
~~~
~~~~~~~~

The `.file` attribute is necessary, as is the identifier, here
`#filename`. The generated test program can access the data using the
identifier (without the #). The mechanism used is generic to Pandoc,
and can be used to affect the typesetting by adding more attributes.
For example, Pandoc can typeset the data in the code block using
syntax highlighting, if the language is specified: `.markdown`,
`.yaml`, or `.python`, for example.

Subplot also understands the `dot` and `roadmap` tags, and can use the
Graphviz dot program, or the [roadmap][] Rust crate, to produce
graphs. These can useful for describing things visually.

[roadmap]: https://crates.io/search?q=roadmap


Bindings file
-----------------------------------------------------------------------------

The bindings file binds scenario steps to Python functions that
implement the steps. The YAML file is a list of objects (also known as
dicts or hashmaps or key/value pairs), specifying a step kind (given,
when, then), a regular expression matching the text of the step and
optionally capturing interesting parts of the text, and the name of a
function that implements the step.

~~~{.yaml .numberLines}
- given: a standard setup
  function: create_standard_setup
- when: (?<thing>\S+) happens
  function: make_thing_happen
- then: everything is OK
  function: check_everything_is_ok
~~~

In the example above, there are three bindings:

* A binding for a "given a standard setup" step. The binding captures
  no part of the text, and causes the `create_standard_setup` function
  to be called.
* A binding for a "when" step consisting of one word followed by
  "happens". For example, "peace", as in "then peace happens". The
  word is captured as "thing", and given to the `make_thing_happen`
  function as an argument when it is called.
* A binding for a "then everthing is OK" step, which captures nothing,
  and calls the `check_everything_is_ok` function.

The regular expressions use [PCRE][] syntax as implemented by the Rust
[regex][] crate. The `(?P<name>pattern)` syntax is used to capture
parts of the step. The captured parts are given to the bound function
as arguments, when it's called.

[PCRE]: https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions
[regex]: https://crates.io/crates/regex



Functions file
-----------------------------------------------------------------------------

The functions file is not parsed by Subplot at all. Subplot merely
copies it to the output. All parsing and validation of the file is
done by the Python implementation.

The Python functions must accept a "context" argument, and a keyword
argument for each part of the step the corresponding regular
expression captures. The capture name and the keyword argument name
must be the same.

The context argument is a dict-like object, which the generated
program creates automatically. The context is carried from function
call to function call, to allow functions to manage state between
themselves. Typically, one step might do something, and record the
results into the context, and another step might check the results by
inspecting the context. This decouples functions from each other, and
avoids having them use global variables for state.



Acceptance criteria for Subplot {#acceptance}
=============================================================================


Add the acceptance criteria test scenarios for Subplot here.

Test data shared between scenarios
-----------------------------------------------------------------------------

The scenarios below test Subplot by running it against specific input
files. This section specifies the bindings and functions files.
They're separate from the scenarios so that the scenarios are shorter
and clearer, but also so that the input files do no need to be
duplicated for each scenario.



### A simple scenario (simple.md)

~~~~{.file #simple.md .markdown .numberLines}
---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# Simple
This is the simplest possible test scenario

```scenario
given precondition foo
when I do bar
then bar was done
```
~~~~


### Bindings file (b.yaml)

~~~{.file #b.yaml .yaml .numberLines}
- given: precondition foo
  function: precond_foo
- when: I do bar
  function: do_bar
- then: bar was done
  function: bar_was_done
~~~

### Python functions (f.py)

~~~{.file #f.py .python .numberLines}
def precond_foo(ctx):
    ctx['bar_done'] = False
def do_bar(ctx):
    ctx['bar_done'] = True
def bar_was_done(ctx):
    assert_eq(ctx['bar_done'], True)
~~~


Smoke test
-----------------------------------------------------------------------------

This tests that Subplot can build a PDF and an HTML document, and
execute a simple scenario successfully. The test is based on
generating the test program from an input file, running the test
program, and examining the output.

~~~scenario
given file simple.md
given file b.yaml
given file f.py
when I run sp-docgen simple.md -o simple.pdf
then file simple.pdf exists
when I run sp-docgen simple.md -o simple.html
then file simple.html exists
when I run sp-codegen --run simple.md -o test.py
then scenario "Simple" was run
then step "given precondition foo" was run
then step "when I do bar" was run
then step "then bar was done" was run
then program finished successfully
~~~


Empty lines in scenarios
-----------------------------------------------------------------------------

This scenario verifies that empty lines in scenarios are ignored.

~~~scenario
given file emptylines.md
given file b.yaml
given file f.py
when I run sp-docgen emptylines.md -o emptylines.pdf
then file emptylines.pdf exists
when I run sp-docgen emptylines.md -o emptylines.html
then file emptylines.html exists
when I run sp-codegen --run emptylines.md -o test.py
then scenario "Simple" was run
then step "given precondition foo" was run
then step "when I do bar" was run
then step "then bar was done" was run
then program finished successfully
~~~


### A document with a scenario with empty lines (emptylines.md)

~~~~{.file #emptylines.md .markdown .numberLines}
---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# Simple
This is the simplest possible test scenario

```scenario
given precondition foo

when I do bar

then bar was done

```
~~~~


Document structure
-----------------------------------------------------------------------------

Subplot uses chapters and sections to keep together scenario snippets
that form a complete scenario. The lowest level heading before a
snippet starts a scenario and is the name of the scenario. If there's
subheadings, they divide the description of the scenario into parts,
but don't start a new scenario. The next heading at the same or a
higher level starts a new scenario.

### Lowest level heading is name of scenario

~~~scenario
given file h1h2h3.md
given file b.yaml
given file f.py
when I run sp-codegen --run h1h2h3.md -o test.py
then scenario "heading1.1.1" was run
then program finished successfully
~~~

The test document **h1h2h3.md**:

~~~~{.file #h1h2h3.md .markdown .numberLines}

---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# heading 1
## heading 1.1
### heading 1.1.1

```scenario
given precondition foo
```
~~~~

### Subheadings don't start new scenario

~~~scenario
given file h1h2h3h3.md
given file b.yaml
given file f.py
when I run sp-codegen --run h1h2h3h3.md -o test.py
then scenario "heading1.1a" was run
then program finished successfully
~~~

The test document **h1h2h3h3.md**:

~~~~{.file #h1h2h3.md .markdown .numberLines}

---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# heading 1
## heading 1.1a

```scenario
given precondition foo
```

### heading 1.1.1
### heading 1.1.2

~~~~

### Next heading at same level starts new scenario

~~~scenario
given file h1h2h3h3.md
given file b.yaml
given file f.py
when I run sp-codegen --run h1h2h3h3.md -o test.py
then scenario "heading1.1.1" was run
then scenario "heading1.1.2" was run
then program finished successfully
~~~

The test document **h1h2h3h3.md**:

~~~~{.file #h1h2h3h3.md .markdown .numberLines}

---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# heading 1
## heading 1.1
### heading 1.1.1

```scenario
given precondition foo
```
### heading 1.1.2

```scenario
given precondition foo
```
~~~~


### Next heading at higher level starts new scenario

~~~scenario
given file h1h2h3h2.md
given file b.yaml
given file f.py
when I run sp-codegen --run h1h2h3h2.md -o test.py
then scenario "heading1.1.1" was run
then scenario "heading1.2" was run
then program finished successfully
~~~

The test document **h1h2h3h2.md**:

~~~~{.file #h1h2h3h2.md .markdown .numberLines}

---
title: Test scenario
bindings: b.yaml
functions: f.py
...

# heading 1
## heading 1.1
### heading 1.1.1

```scenario
given precondition foo
```
## heading 1.2

```scenario
given precondition foo
```
~~~~


### Document titles

The document and code generators require a document title, because
it's a common user error to not have one, and Subplot should help make
good documents. The Pandoc filter, however, mustn't require a document
title, because it's used for things like formatting websites using
ikiwiki, and ikiwiki has a different way of specifying page titles.

#### Document generator gives an error if input document lacks title

~~~scenario
given file notitle.md
when I try to run sp-docgen notitle.md -o foo.md
then exit code is non-zero
~~~

~~~{.file #notitle.md .markdown .numberLines}
---
bindings: b.yaml
functions: f.py
...


# Introduction

This is a very simple Markdown file without a YAML metadata block,
and thus also no document title.

```scenario
given precondition foo
when I do bar
then bar was done
~~~

#### Code generator gives an error if input document lacks title

~~~scenario
given file notitle.md
when I try to run sp-codegen --run notitle.md -o test.py
then exit code is non-zero
~~~


Using a Pandoc filter
-----------------------------------------------------------------------------

Subplot can be used as a Pandoc _filter_, which means Pandoc can allow
Subplot to modify the document while it is being converted or typeset.
This can useful in a variety of ways, such as when using Pandoc to
improve Markdown processing in the [ikiwiki][] blog engine.

[ikiwiki]: http://ikiwiki.info/

The way filters work is that Pandoc parses the input document into an
abstract syntax tree, serializes that into JSON, gives that to the
filter (via the standard input), gets a modified abstract syntax tree
(again as JSON, via the filter's standard output).

Subplot supports this via the **sp-filter** executable. It is built
using the same internal logic as Subplot's docgen. The interface is
merely different to be usable as a Pandoc filter.

This scenarios verifies that the filter works at all. More
importantly, it does that by feeding the filter a Markdown file that
does not have a YAML metadata block. For the ikiwiki use case, that's
what the input files are like.

~~~scenario
given file justdata.md
when I run pandoc --filter sp-filter justdata.md -o justdata.html
then file justdata.html matches /does not have a YAML metadata/
~~~

The input file **justdata.md**:

~~~~~~~~{.file #justdata.md .markdown .numberLines}
This is an example Markdown file.
It does not have a YAML metadata block.
~~~~~~~~


Extracting metadata from a document
-----------------------------------------------------------------------------

The **sp-meta** program extracts metadata from a document. It is
useful to see the scenarios, for example. For example, given a
document like this:

sp-meta would extract this information from the **simple.md** example:

~~~
title: Test scenario
bindings: b.yaml
functions: f.py
scenario Simple
~~~

This scenario check sp-meta works. Note that it requires the bindings
or functions files.

~~~scenario
given file simple.md
given file b.yaml
given file f.py
when I run sp-meta simple.md
then output matches /title: Test scenario/
then output matches /bindings: b.yaml/
then output matches /functions: f.py/
then output matches /scenario Simple/
~~~


Embedded graphs
-----------------------------------------------------------------------------

Subplot allows embedding markup to generate graphs into the Markdown document.

### Dot

[Graphviz]: http://www.graphviz.org/

Dot is a program from the [Graphviz][] suite to generate directed
graphs, such as this one.

~~~dot
digraph "example" {
thing -> other
}
~~~

The scenario checks that a graph is generated and embedded into the
HTML output, not referenced as an external image.

~~~scenario
given file dot.md
given file b.yaml
when I run pandoc --filter sp-filter dot.md -o dot.html
then file dot.html matches /img src="data:image/svg\+xml;base64,/
~~~

The sample input file **dot.md**:

~~~~~~~~{.file #dot.md .markdown .numberLines}
This is an example Markdown file, which embeds a graph using dot markup.

~~~dot
digraph "example" {
thing -> other
}
~~~
~~~~~~~~


### Roadmap

[roadmap]: http://git.liw.fi/roadmap/tree/

Subplot supports visual roadmaps using a YAML based markup language,
implemnted by the [roadmap][] Rust library. The library converts the
roadmap into dot, and that gets rendered as SVG and embedded in the
output document by Subplot.

An example:

~~~roadmap
goal:
  label: |
    This is the end goal:
    if we reach here, there
    is nothing more to be
    done in the project
  depends:
  - finished
  - blocked

finished:
  status: finished
  label: |
    This task is finished;
    the arrow indicates what
    follows this task (unless
    it's blocked)

ready:
  status: ready
  label: |
    This task is ready 
    to be done: it is not
    blocked by anything

next:
  status: next
  label: |
    This task is chosen 
    to be done next

blocked:
  status: blocked
  label: |
    This task is blocked
    and can't be done until
    something happens
  depends:
  - ready
  - next
~~~

This scenario checks that a graph is generated and embedded into the
HTML output, not referenced as an external image.

~~~scenario
given file roadmap.md
given file b.yaml
when I run pandoc --filter sp-filter roadmap.md -o roadmap.html
then file roadmap.html matches /img src="data:image/svg\+xml;base64,/
~~~

The sample input file **roadmap.md**:

~~~~~~~~{.file #roadmap.md .markdown .numberLines}
This is an example Markdown file, which embeds a roadmap.

~~~roadmap
goal:
  label: |
    This is the end goal:
    if we reach here, there
    is nothing more to be
    done in the project
  depends:
  - finished
  - blocked

finished:
  status: finished
  label: |
    This task is finished;
    the arrow indicates what
    follows this task (unless
    it's blocked)

ready:
  status: ready
  label: |
    This task is ready 
    to be done: it is not
    blocked by anything

next:
  status: next
  label: |
    This task is chosen 
    to be done next

blocked:
  status: blocked
  label: |
    This task is blocked
    and can't be done until
    something happens
  depends:
  - ready
  - next
~~~
~~~~~~~~