diff options
Diffstat (limited to 'subplot.md')
-rw-r--r-- | subplot.md | 789 |
1 files changed, 538 insertions, 251 deletions
@@ -20,20 +20,20 @@ document. We define the various concepts relevant to Subplot as follows: -* **Acceptance criteria**: What the stakeholders require of the system +* **Acceptance criteria:** What the stakeholders require of the system for them to be happy with it and use it. -* **Stakeholder**: Someone with a keen interest in the success of a +* **Stakeholder:** Someone with a keen interest in the success of a system. They might be a paying client, someone who uses the system, or someone involved in developing the system. Depending on the system and project, some stakeholders may have a bigger say than others. -* **Acceptance test**: How stakeholders verify that the system +* **Acceptance test:** How stakeholders verify that the system fulfills the acceptance criteria, in an automated way. Some criteria may not be possible to verify automatically. -* **Scenario**: In Subplot, the acceptance criteria are written as +* **Scenario:** In Subplot, the acceptance criteria are written as freeform prose, with diagrams, etc. The scenarios, which are embedded blocks of Subplot scenario language, capture the mechanisms of verifying that criteria are met - the acceptance tests - showing @@ -63,7 +63,7 @@ technical text that's aimed at all your stakeholders. ## Subplot architecture Subplot reads an input document, in Markdown, and generates a typeset -output document, as PDF or HTML, for all stakeholders to understand. +output document, as 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 system under test meets its acceptance criteria. The @@ -85,9 +85,6 @@ 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]; @@ -100,20 +97,13 @@ 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 generated HTML itself. Subplot actually consists mainly of two separate programs: **subplot docgen** for generating output documents, and **subplot codegen** for @@ -140,9 +130,6 @@ docgen [shape=ellipse]; codegen [label="subplot codegen"]; codegen [shape=ellipse]; -pdf [label="foo.pdf \n PDF (generated)"] -pdf [shape=note]; - html [label="foo.html \n HTML (generated)"] html [shape=note]; @@ -157,7 +144,6 @@ bindings -> docgen; md -> codegen; bindings -> codegen; impl -> codegen; -docgen -> pdf; docgen -> html; codegen -> testprog; testprog -> report; @@ -315,56 +301,56 @@ tests for Subplot](#acceptance). Each requirement here is given a unique mnemonic id for easier reference in discussions. -**UnderstandableTests** +* **UnderstandableTests** -: Acceptance tests should be possible to express in a way that's - easily understood by all stakeholders, including those who are - not software developers. + Acceptance tests should be possible to express in a way that's + easily understood by all stakeholders, including those who are not + software developers. _Done_ but requires the Subplot document to be written with care. -**EasyToWriteDocs** +* **EasyToWriteDocs** -: The markup language for writing documentation should be easy to + The markup language for writing documentation should be easy to write. _Done_ by using Markdown. -**AidsComprehension** +* **AidsComprehension** -: The formatted human-readable documentation should use good layout + The formatted human-readable documentation should use good layout and typography to enhance comprehension. - _In progress_ — typesetting via Pandoc works, but may need - review and improvement. + _In progress_ — we currently only output HTML, but may add + PDF output back later. -**CodeSeparately** +* **CodeSeparately** -: The code to implement the acceptance criteria should not be + 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** +* **AnyProgammingLanguage** -: The developers implementing the acceptance tests should be free to + 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** +* **FastTestExecution** -: Executing the acceptance tests should be fast. + Executing the acceptance tests should be fast. _Not done_ — the generated Python test program is simplistic and linear. -**NoDeployment** +* **NoDeployment** -: The acceptance test tooling should assume the system under test is + 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. @@ -372,9 +358,9 @@ reference in discussions. _Done_ by virtue of letting those who implement the scenario steps worry about it. -**MachineParseableResults** +* **MachineParseableResults** -: The tests should produce a machine parseable result that can be + 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, @@ -387,16 +373,13 @@ reference in discussions. Subplot reads three input files, each in a different format: -* The document file, which uses the Markdown dialects understood by - Pandoc. +* The document file in [GitHub Flavored Markdown](https://github.github.com/gfm/). * The bindings file, in YAML. * The functions file, in Bash or Python. Subplot interprets 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. +specially. These are fenced code blocks tagged with the `sceanrio`, +`file`, or `example` classes. ## Scenario language @@ -521,14 +504,9 @@ will deal with formatting that nicely for you. ## Document markup -[Pandoc]: https://pandoc.org/ +Subplot parses Markdown input files using GitHub-flavored Markdown. -Subplot uses [Pandoc][], the universal document converter, to parse -the Markdown file, and thus understands the variants of Markdown that -Pandoc supports. This includes traditional Markdown, CommonMark, and -GitHub-flavored Markdown. - -[fenced code blocks]: https://pandoc.org/MANUAL.html#fenced-code-blocks +[fenced code blocks]: https://github.github.com/gfm/#fenced-code-blocks Subplot extends Markdown by treating certain certain tags for [fenced code blocks][] specially. A scenario, for example, would look like @@ -550,6 +528,11 @@ 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 `scenario` blocks you may not use any attributes. All attributes +are reserved for Subplot. Subplot doesn't define any attributes yet, +but by reserving all of them, it can add them later without it being +a breaking change. + For embedding test data files in the Markdown document, Subplot understands the `file` tag: @@ -561,11 +544,7 @@ 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. +identifier (without the #). Subplot also understands the `dot` and `roadmap` tags, and can use the Graphviz dot program, or the [roadmap][] Rust crate, to produce @@ -621,31 +600,23 @@ given file not-numbered-lines.txt ## 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 +Document metadata is read from a YAML file. This can used to set the +document title, authors, date (version), and more. Crucially for +Subplot, the bindings and functions files are named in the metadata +block, rather than Subplot deriving them from the input file name. -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} ---- +~~~{.file .yaml .numberLines} title: "Subplot" authors: - The Subplot project date: work in progress +markdowns: +- subplot.md bindings: - subplot.yaml impls: python: - subplot.py -... ~~~ There can be more than one bindings or functions file: use a YAML @@ -716,6 +687,24 @@ implementation functions: * A binding for a "then everything is OK" step, which captures nothing, and calls the `check_everything_is_ok` function. +## Step functions and cleanup + +A step function must be atomic: either it completes successfully, or +it cleans up any changes it made before returning an indication of +failure. + +A cleanup function is only called for successfully executed step +functions. + +For example, consider a step that creates and starts a virtual +machine. The step function creates the VM, then starts it, and if both +actions succeeds, the step succeeds. A cleanup function for that step +will stop and delete the VM. The cleanup is only called if the step +succeeded. If the step function manages to create the VM, but not +start it, it's the step function's responsibility to delete the VM, +before it signals failure. The cleanup function won't be called in +that case. + ### Simple patterns The simple patterns are of the form `{name}` and match a single word @@ -772,7 +761,7 @@ will emit a warning if the file is not found, and subplot codegen will emit an e Bindings can contain an `impl` map which connects the binding with zero or more language templates. If a binding has no `impl` entries then it can still be -used to `docgen` a PDF or HTML document from a subplot document. This permits a +used to `docgen` a HTML document from a subplot document. This permits a workflow where requirements owners / architects design the validations for a project and then engineers implement the step functions to permit the validations to work. @@ -802,8 +791,6 @@ given file badfilename.md and file b.yaml and file f.py and an installed subplot -when I run subplot docgen --merciful badfilename.subplot -o foo.pdf -then file foo.pdf exists when I try to run subplot codegen --run badfilename.md -o test.py then command fails ``` @@ -825,6 +812,74 @@ given file missing.md ~~~ +### Bindings file strictness - given when then + +The bindings file is semi-strict. For example you must have only one +of `given`, `when`, or `then` in your binding. + + +```scenario +given file badbindingsgwt.subplot +and file badbindingsgwt.md +and file badbindingsgwt.yaml +and an installed subplot +when I try to run subplot docgen --output ignored.html badbindingsgwt.subplot +then command fails +and stderr contains "binding has more than one keyword" +``` + +~~~{#badbindingsgwt.subplot .file .yaml .numberLines} +title: Bad bindings cause everything to fail +markdowns: [badbindingsgwt.md] +bindings: [badbindingsgwt.yaml] +~~~ + +~~~{#badbindingsgwt.md .file .markdown .numberLines} +# Bad bindings +```scenario +given we won't reach here +``` +~~~ + +~~~{#badbindingsgwt.yaml .file .yaml .numberLines} +- given: we won't reach here + then: we won't reach here +~~~ + +### Bindings file strictness - unknown field + +The bindings file is semi-strict. For example, you must not have keys +in the bindings file which are not known to Subplot. + + +```scenario +given file badbindingsuf.subplot +and file badbindingsuf.md +and file badbindingsuf.yaml +and an installed subplot +when I try to run subplot docgen --output ignored.html badbindingsuf.subplot +then command fails +and stderr contains "unknown field `function`" +``` + +~~~{#badbindingsuf.subplot .file .yaml .numberLines} +title: Bad bindings cause everything to fail +markdowns: [badbindingsuf.md] +bindings: [badbindingsuf.yaml] +~~~ + +~~~{#badbindingsuf.md .file .markdown .numberLines} +# Bad bindings +```scenario +given we won't reach here +``` +~~~ + +~~~{#badbindingsuf.yaml .file .yaml .numberLines} +- given: we won't reach here + function: old_school_function +~~~ + ## Functions file Functions implementing steps are supported in Bash and Python. The @@ -1074,7 +1129,7 @@ def foobar_was_done(ctx): ### Smoke test The scenario below uses the input files defined above to run some tests -to verify that Subplot can build a PDF and an HTML document, and +to verify that Subplot can build 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. @@ -1085,8 +1140,6 @@ given file simple.md and file b.yaml and file f.py and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists when I run subplot docgen simple.subplot -o simple.html then file simple.html exists when I run subplot codegen --run simple.subplot -o test.py @@ -1097,6 +1150,92 @@ and step "then bar was done" was run and command is successful ~~~ +## Indented scenario steps are not allowed + +_Requirement: A scenario step starts at the beginning of the line._ + +Justification: We may want to allow continuing a step to the next +line, but as of June, 2023, we haven't settled on a syntax for this. +However, whatever syntax we do eventually choose, it will be easier +to add that if scenario steps start at the beginning of a line, +without making a breaking change. + +~~~scenario +given file indented-step.subplot +given file indented-step.md +given file b.yaml +given an installed subplot +when I try to run subplot docgen indented-step.subplot -o foo.html +then command fails +and stderr contains "indented" +~~~ + +~~~{#indented-step.subplot .file .yaml .numberLines} +title: Indented scenario step +markdowns: + - indented-step.md +bindings: + - b.yaml +~~~ + +~~~~~~{#indented-step.md .file .markdown .numberLines} +# This is a title + +~~~scenario + given precondition +~~~ +~~~~~~ + +## Named code blocks must have an appropriate class + +_Requirement: Named code blocks must carry an appropriate class such as file or example_ + +Justification: Eventually we may want to add other meanings to named blocks, +currently the identifier cannot be used except to refer to the block as a named file, +but we may want to in the future so this is here to try and prevent any future +incompatibilities. + +~~~scenario +given file named-code-blocks-appropriate.subplot +given file named-code-blocks-appropriate.md +given file b.yaml +given an installed subplot +when I try to run subplot docgen named-code-blocks-appropriate.subplot -o foo.html +then command fails +and stderr contains "#example-1 at named-code-blocks-appropriate.md:7:1" +and stderr doesn't contain "example-2" +and stderr doesn't contain "example-3" +~~~ + +~~~{#named-code-blocks-appropriate.subplot .file .yaml .numberLines} +title: Named code blocks carry appropriate classes step +markdowns: + - named-code-blocks-appropriate.md +bindings: + - b.yaml +~~~ + +~~~~~~{#named-code-blocks-appropriate.md .file .markdown .numberLines} +# This is a title + +~~~scenario +given precondition +~~~ + +~~~{#example-1 .numberLines} +This example is bad +~~~ + +~~~{#example-2 .file .numberLines} +This example is OK because of .file +~~~ + +~~~{#example-3 .example .numberLines} +This example is OK because of .example +~~~ + +~~~~~~ + ## No scenarios means codegen fails If you attempt to `subplot codegen` on a document which contains no scenarios, the @@ -1174,8 +1313,6 @@ given file allkeywords.md and file b.yaml and file f.py and an installed subplot -when I run subplot docgen allkeywords.subplot -o foo.pdf -then file foo.pdf exists when I run subplot codegen --run allkeywords.subplot -o test.py then scenario "All keywords" was run and step "given precondition foo" was run @@ -1207,6 +1344,7 @@ but foobar was done ``` ~~~ +<!-- disabled until Lars fixes typesetting of scenarios ### Keyword aliases in output We support **and** and **but** in input lines, and we always render @@ -1248,6 +1386,7 @@ then bar was done then foobar was done ``` ~~~ +--> ### Misuse of continuation keywords @@ -1262,8 +1401,6 @@ given file continuationmisuse.md and file b.yaml and file f.py and an installed subplot -when I run subplot docgen continuationmisuse.subplot -o foo.pdf -then file foo.pdf exists when I try to run subplot codegen --run continuationmisuse.subplot -o test.py then command fails ~~~ @@ -1300,8 +1437,8 @@ section. This scenario verifies that all markup works. given file title-markup.subplot given file title-markup.md given an installed subplot -when I run subplot docgen title-markup.subplot -o foo.pdf -then file foo.pdf exists +when I run subplot docgen title-markup.subplot -o foo.html +then file foo.html exists ~~~ ~~~~{#title-markup.subplot .file .yaml .numberLines} @@ -1315,6 +1452,82 @@ impls: { python: [] } # Introduction ~~~~ +## Scenario titles + +A scenario gets its title from the lowest level of section heading +that applies to it. The heading can use markup. + +~~~scenario +given file scenario-titles.subplot +given file scenario-titles.md +given file b.yaml +given file f.py +given an installed subplot +when I run subplot metadata scenario-titles.subplot +then stdout contains "My fun scenario title" +~~~ + +~~~~{#scenario-titles.subplot .file .yaml .numberLines} +title: Test scenario +markdowns: +- scenario-titles.md +bindings: [b.yaml] +impls: + python: [f.py] +~~~~ + +~~~~{#scenario-titles.md .file .markdown .numberLines} +# My **fun** _scenario_ `title` + +```scenario +given precondition foo +when I do bar +then bar was done +``` +~~~~ + +## Duplicate scenario titles + +_Requirement: Subplot treats it as an error if two scenarios have the +same title._ + +Justification: the title is how a scenario is identified, and the user +needs to be able to do so unambiguously. + +~~~scenario +given file duplicate-scenario-titles.subplot +given file duplicate-scenario-titles.md +given file b.yaml +given file f.py +given an installed subplot +when I try to run subplot metadata duplicate-scenario-titles.subplot +then command fails +then stderr contains "duplicate" +~~~ + +~~~~{#duplicate-scenario-titles.subplot .file .yaml .numberLines} +title: Test scenario +markdowns: +- duplicate-scenario-titles.md +bindings: [b.yaml] +impls: + python: [f.py] +~~~~ + +~~~~{#duplicate-scenario-titles.md .file .markdown .numberLines} +# My sceanrio + +```scenario +when I do bar +``` + +# My sceanrio + +```scenario +when I do bar +``` +~~~~ + ## Empty lines in scenarios This scenario verifies that empty lines in scenarios are OK. @@ -1325,8 +1538,6 @@ given file emptylines.md and file b.yaml and file f.py and an installed subplot -when I run subplot docgen emptylines.subplot -o emptylines.pdf -then file emptylines.pdf exists when I run subplot docgen emptylines.subplot -o emptylines.html then file emptylines.html exists when I run subplot codegen --run emptylines.subplot -o test.py @@ -1942,98 +2153,6 @@ def is_set_to(ctx, name=None, value=None): -## Avoid changing typesetting output file needlessly - -### Avoid typesetting if output is newer than source files - -This scenario make sure that if docgen generates the bitwise identical -output to the existing output file, it doesn't actually write it to -the output file, including its timestamp. This avoids triggering -programs that monitor the output file for changes. - -~~~scenario -given file simple.subplot -given file simple.md -and file b.yaml -and file f.py -and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists -when I remember metadata for file simple.pdf -and I wait until 1 second has passed -and I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf has same metadata as before -and only files simple.subplot, simple.md, b.yaml, f.py, simple.pdf exist -~~~ - -### Do typeset if output is older than subplot - -~~~scenario -given file simple.subplot -given file simple.md -and file b.yaml -and file f.py -and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists -when I remember metadata for file simple.pdf -and I wait until 1 second has passed -and I touch file simple.subplot -and I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf has changed from before -~~~ - -### Do typeset if output is older than markdown - -~~~scenario -given file simple.subplot -given file simple.md -and file b.yaml -and file f.py -and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists -when I remember metadata for file simple.pdf -and I wait until 1 second has passed -and I touch file simple.md -and I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf has changed from before -~~~ - -### Do typeset if output is older than functions - -~~~scenario -given file simple.subplot -given file simple.md -and file b.yaml -and file f.py -and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists -when I remember metadata for file simple.pdf -and I wait until 1 second has passed -and I touch file f.py -and I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf has changed from before -~~~ - -### Do typeset if output is older than bindings - -~~~scenario -given file simple.subplot -given file simple.md -and file b.yaml -and file f.py -and an installed subplot -when I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf exists -when I remember metadata for file simple.pdf -and I wait until 1 second has passed -and I touch file b.yaml -and I run subplot docgen simple.subplot -o simple.pdf -then file simple.pdf has changed from before -~~~ - ## Document structure Subplot uses chapters and sections to keep together scenario snippets @@ -2192,9 +2311,7 @@ given precondition foo 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. +good documents. #### Document generator gives an error if input document lacks title @@ -2277,6 +2394,7 @@ This is a very simple Markdown file that uses every kind of inline markup in the title and chapter heading. To satisfy codegen, we *MUST* have a scenario here + ~~~~scenario when I do bar then bar was done @@ -2513,32 +2631,6 @@ and file mtime.html contains "Geoffrey Butler" and file mtime.html contains "2020-02-26 07:53" ~~~ -### Pandoc metadata - -~~~scenario -given file pandoc.subplot -given file pandoc.md -and an installed subplot -when I run subplot docgen pandoc.subplot -o pandoc.html -when I run cat pandoc.html -then file pandoc.html exists -and file pandoc.html contains "<title>The Fabulous Title</title>" -and file pandoc.html contains "Superlative Subtitle" -~~~ - -~~~{#pandoc.subplot .file .yaml .numberLines} -title: The Fabulous Title -markdowns: -- pandoc.md -pandoc: - subtitle: Superlative Subtitle -~~~ - -~~~{#pandoc.md .file .markdown .numberLines} -# Introduction -This is a test document. That's all. -~~~ - ### Missing bindings file If a bindings file is missing, the error message should name the @@ -2620,8 +2712,6 @@ and file b.yaml and file other.yaml and file f.py and file other.py -and file foo.bib -and file bar.bib and file expected.json and an installed subplot when I run subplot metadata images.subplot @@ -2630,8 +2720,6 @@ and stdout contains "source: b.yaml" and stdout contains "source: other.yaml" and stdout contains "source: f.py" and stdout contains "source: other.py" -and stdout contains "source: foo.bib" -and stdout contains "source: bar.bib" and stdout contains "source: image.gif" and stdout contains "bindings: b.yaml" and stdout contains "bindings: other.yaml" @@ -2652,7 +2740,6 @@ impls: python: - f.py - other.py -bibliography: [foo.bib, bar.bib] ~~~ ~~~{#images.md .file .markdown .numberLines} @@ -2666,34 +2753,12 @@ bibliography: [foo.bib, bar.bib] ~~~{#other.py .file .python .numberLines} ~~~ -~~~{#foo.bib .file .numberLines} -@book{foo2020, - author = "James Random", - title = "The Foo book", - publisher = "The Internet", - year = 2020, - address = "World Wide Web", -} -~~~ - -~~~{#bar.bib .file .numberLines} -@book{foo2020, - author = "James Random", - title = "The Bar book", - publisher = "The Internet", - year = 2020, - address = "World Wide Web", -} -~~~ - ~~~{#expected.json .file .json} { "title": "Document refers to external images", "sources": [ "b.yaml", - "bar.bib", "f.py", - "foo.bib", "image.gif", "images.md", "images.subplot", @@ -2710,27 +2775,60 @@ bibliography: [foo.bib, bar.bib] "other.py" ] }, - "bibliographies": [ - "bar.bib", - "foo.bib" - ], "files": [], "scenarios": [] } ~~~ +### Multiple markdown files + +This scenario tests that the `markdowns` field in metadata can specify +more than one markdown file. + +~~~scenario +given file multimd.subplot +given file md1.md +given file md2.md +given an installed subplot +when I run subplot docgen multimd.subplot -o multimd.html +when I run cat multimd.html +then file multimd.html exists +and file multimd.html contains "<title>The Fabulous Title</title>" +and file multimd.html contains "First markdown file." +and file multimd.html contains "Second markdown file." +~~~ + +~~~{#multimd.subplot .file .yaml .numberLines} +title: The Fabulous Title +authors: +- Alfred Pennyworth +- Geoffrey Butler +date: WIP +markdowns: +- md1.md +- md2.md +~~~ + +~~~{#md1.md .file .markdown .numberLines} +First markdown file. +~~~ + +~~~{#md2.md .file .markdown .numberLines} +Second markdown file. +~~~ + + ## Embedded files Subplot allows data files to be embedded in the input document. This is handy for small test files and the like. -Handling of a newline character on the last line is tricky. Pandoc -doesn't include a newline on the last line. Sometimes one is -needed—but sometimes it's not wanted. A newline can be added by -having an empty line at the end, but that is subtle and easy to miss. -Subplot helps the situation by allowing a `add-newline=` class to be added -to the code blocks, with one of three allowed cases: +Handling of a newline character on the last line is tricky. The block +ends in a newline on the last line. Sometimes one is needed—but +sometimes it's not wanted. Subplot helps the situation by allowing a +`add-newline=` class to be added to the code blocks, with one of three +allowed cases: * no `add-newline` class—default handling: same as `add-newline=auto` * `add-newline=auto`—add a newline, if one isn't there @@ -3187,7 +3285,7 @@ into SVGs such as this one. ~~~pikchr arrow right 200% "Markdown" "Source" box rad 10px "Subplot" "Document Generator" "(subplot docgen)" fit -arrow right 200% "HTML+SVG/PDF" "Output" +arrow right 200% "HTML+SVG" "Output" arrow <-> down 70% from last box.s box same "Pikchr" "Formatter" "(docs.rs/pikchr)" fit ~~~ @@ -3203,7 +3301,7 @@ when I run subplot docgen pikchr.subplot -o pikchr.html then file pikchr.html matches regex /src="data:image/svg\+xml;base64,/ ~~~ -The sample input file **pikchr.md**: +The sample input file **pikchr.md:** ~~~~~~~~{#pikchr.md .file .markdown .numberLines} --- @@ -3250,7 +3348,7 @@ when I run subplot docgen dot.subplot -o dot.html then file dot.html matches regex /src="data:image/svg\+xml;base64,/ ~~~ -The sample input file **dot.md**: +The sample input file **dot.md:** ~~~~~~~~{#dot.md .file .markdown .numberLines} This is an example Markdown file, which embeds a diagram using dot markup. @@ -3299,7 +3397,7 @@ when I run subplot docgen plantuml.subplot -o plantuml.html then file plantuml.html matches regex /src="data:image/svg\+xml;base64,/ ~~~ -The sample input file **plantuml.md**: +The sample input file **plantuml.md:** ~~~~~~~~{#plantuml.md .file .markdown .numberLines} This is an example Markdown file, which embeds a diagram using @@ -3387,7 +3485,7 @@ when I run subplot docgen roadmap.subplot -o roadmap.html then file roadmap.html matches regex /src="data:image/svg\+xml;base64,/ ~~~ -The sample input file **roadmap.md**: +The sample input file **roadmap.md:** ~~~~~~~~{#roadmap.md .file .markdown .numberLines} This is an example Markdown file, which embeds a roadmap. @@ -3447,7 +3545,7 @@ markdowns: When Subplot loads a document it will validate that the block classes match a known set. Subplot has a built-in set which it treats as special, -and it knows some pandoc-specific classes and a number of file type classes. +and it knows some custom classes and a number of file type classes. If the author of a document wishes to use additional class names then they can include a `classes` list in the document metadata which subplot will treat @@ -3522,3 +3620,192 @@ This is a test file. ~~~{#expected.txt .file} This is a test file. ~~~ +## Mistakes in markdown + +When there are mistakes in the markdown input, Subplot should report +the location (filename, line, column) where the mistake is, and what +the mistake is. The scenarios in this section verify that. + +### Scenario before the first heading + +_Requirement: A scenario must follow a heading._ + +Justification: the heading can be used as the title for the scenario. + +~~~scenario +given an installed subplot +given file scenario-before-heading.subplot +given file scenario-before-heading.md +when I try to run subplot docgen scenario-before-heading.subplot -o /dev/null +then command fails +then stderr contains "ERROR: scenario-before-heading.md:1:1: first scenario is before first heading" +~~~ + +~~~{#scenario-before-heading.subplot .file .yaml} +title: Foo +markdowns: + - scenario-before-heading.md +~~~ + +~~~~~~{#scenario-before-heading.md .file .markdown} +~~~scenario +~~~ +~~~~~~ + +### Attempt to use definition list + +_Requirement: Attempt to use definition lists is reported._ + +Justification: the markdown parser we use in Subplot doesn't support +them, and it would be unhelpful to not tell the user if they try to +use them. + +~~~scenario +given an installed subplot +given file dl.subplot +given file dl.md +when I try to run subplot docgen dl.subplot -o /dev/null +then command fails +then stderr contains "ERROR: dl.md:3:1: attempt to use definition lists in Markdown" +~~~ + +~~~{#dl.subplot .file .yaml} +title: Foo +markdowns: + - dl.md +~~~ + +~~~~~~{#dl.md .file .markdown} +# Foo + +Some term +: Definition of term. +~~~~~~ + +### Bad "add-newline" value + +_Requirement: Only specific values for the "add-newline" attribute are +allowed for an embedded file._ + +~~~scenario +given an installed subplot +given file add-newline.subplot +given file add-newline.md +when I try to run subplot docgen add-newline.subplot -o /dev/null +then command fails +then stderr contains "ERROR: add-newline.md:1:1: value of add-newline attribute is not understood: xyzzy" +~~~ + +~~~{#add-newline.subplot .file .yaml} +title: Foo +markdowns: + - add-newline.md +~~~ + +~~~~~~{#add-newline.md .file .markdown} +~~~{#foo.txt .file add-newline=xyzzy} +~~~ +~~~~~~ + +## HTML output + +### Embedded CSS + +_Requirement:_ The user can specify CSS files to embed in the HTML +output. + +Justification: We want to allow production of self-standing output +with user-defined styling. + +~~~scenario +given file embedded-css.subplot +given file embedded-css.md +given file embedded-css.css +given file b.yaml +given an installed subplot +when I run subplot docgen embedded-css.subplot -o foo.html +then file foo.html contains "silly: property;" +~~~ + +~~~{#embedded-css.subplot .file .yaml .numberLines} +title: Embedded CSS +markdowns: + - embedded-css.md +bindings: + - b.yaml +css_embed: + - embedded-css.css +~~~ + +~~~~~~{#embedded-css.md .file .markdown .numberLines} +# This is a title + +~~~scenario +given precondition +~~~ +~~~~~~ + +~~~{#embedded-css.css .file .css .numberLines} +html { + silly: property; +} +~~~ + +### CSS URLs + +_Requirement:_ The user can specify CSS URLs to add in the HTML +output. + +Justification: We want to allow users to specify non-embedded CSS. + +~~~scenario +given file css-urls.subplot +given file css-urls.md +given file b.yaml +given an installed subplot +when I run subplot docgen css-urls.subplot -o foo.html +then file foo.html contains "https://example.com/flushing.css" +~~~ + +~~~{#css-urls.subplot .file .yaml .numberLines} +title: Embedded CSS +markdowns: + - css-urls.md +bindings: + - b.yaml +css_urls: + - https://example.com/flushing.css +~~~ + +~~~~~~{#css-urls.md .file .markdown .numberLines} +# This is a title + +~~~scenario +given precondition +~~~ +~~~~~~ + + +## Running Subplot + +The scenarios in this section verify that the Subplot tool can be run +in various specific ways. + +### Files not in current working directory + +_Requirement: Subplot can process a subplot that is not in the current +working directory._ + +~~~scenario +given file x/simple.subplot from simple.subplot +given file x/simple.md from simple.md +given file x/b.yaml from b.yaml +given file x/f.py from f.py +given an installed subplot +when I run subplot metadata x/simple.subplot +then command is successful +when I run subplot codegen x/simple.subplot -o test.py +then file test.py exists +when I run subplot docgen x/simple.subplot -o simple.html +then file simple.html exists +~~~ |