diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-05-09 09:34:36 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-05-09 11:07:37 +0300 |
commit | a21ba1f5fcc9b03f7657c5b00c4c215286b06341 (patch) | |
tree | a64b77067ca53d8cf32482b8ab1b64ad7687f711 | |
parent | aefd93fb14b4781deca481d2a21953c9fd30f361 (diff) | |
download | subplot-a21ba1f5fcc9b03f7657c5b00c4c215286b06341.tar.gz |
Change: keep actual text of keyword from scenario
The typesetting should preserve the actual keyword or alias in the
source. Previously, if source had this:
```
given foo
and bar
```
it got typeset as if were:
```
given foo
given bar
```
Also, change subplot.md to use alias when possible.
-rw-r--r-- | src/ast.rs | 7 | ||||
-rw-r--r-- | src/bindings.rs | 16 | ||||
-rw-r--r-- | src/error.rs | 10 | ||||
-rw-r--r-- | src/scenarios.rs | 2 | ||||
-rw-r--r-- | src/steps.rs | 32 | ||||
-rw-r--r-- | subplot.md | 204 |
6 files changed, 158 insertions, 113 deletions
@@ -785,12 +785,7 @@ fn step( // Typeset first word, which is assumed to be a keyword, of a scenario // step. fn keyword(step: &ScenarioStep) -> Inline { - let word = match step.kind() { - StepKind::Given => "given", - StepKind::When => "when", - StepKind::Then => "then", - }; - let word = inlinestr(word); + let word = inlinestr(step.keyword()); Inline::Emph(vec![word]) } diff --git a/src/bindings.rs b/src/bindings.rs index d53df23..30e7df9 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -163,21 +163,21 @@ mod test_binding { #[test] fn does_not_match_with_wrong_kind() { - let step = ScenarioStep::new(StepKind::Given, "yo"); + let step = ScenarioStep::new(StepKind::Given, "given", "yo"); let b = Binding::new(StepKind::When, "yo", "do_yo").unwrap(); assert!(b.match_with_step(&step).is_none()); } #[test] fn does_not_match_with_wrong_text() { - let step = ScenarioStep::new(StepKind::Given, "foo"); + let step = ScenarioStep::new(StepKind::Given, "given", "foo"); let b = Binding::new(StepKind::Given, "bar", "yo").unwrap(); assert!(b.match_with_step(&step).is_none()); } #[test] fn match_with_fixed_pattern() { - let step = ScenarioStep::new(StepKind::Given, "foo"); + let step = ScenarioStep::new(StepKind::Given, "given", "foo"); let b = Binding::new(StepKind::Given, "foo", "do_foo").unwrap(); let m = b.match_with_step(&step).unwrap(); assert_eq!(m.kind(), StepKind::Given); @@ -189,7 +189,7 @@ mod test_binding { #[test] fn match_with_regex() { - let step = ScenarioStep::new(StepKind::Given, "I am Tomjon, I am"); + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon, I am"); let b = Binding::new(StepKind::Given, r"I am (?P<who>\S+), I am", "set_name").unwrap(); let m = b.match_with_step(&step).unwrap(); assert_eq!(m.kind(), StepKind::Given); @@ -388,7 +388,7 @@ mod test_bindings { #[test] fn does_not_find_match_for_unmatching_kind() { - let step = ScenarioStep::new(StepKind::Given, "I am Tomjon"); + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); let binding = Binding::new(StepKind::When, r"I am Tomjon", "set_foo").unwrap(); let mut bindings = Bindings::new(); bindings.add(&binding); @@ -397,7 +397,7 @@ mod test_bindings { #[test] fn does_not_find_match_for_unmatching_pattern() { - let step = ScenarioStep::new(StepKind::Given, "I am Tomjon"); + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); let binding = Binding::new(StepKind::Given, r"I am Tomjon of Lancre", "set_foo").unwrap(); let mut bindings = Bindings::new(); bindings.add(&binding); @@ -406,7 +406,7 @@ mod test_bindings { #[test] fn finds_match_for_fixed_string_pattern() { - let step = ScenarioStep::new(StepKind::Given, "I am Tomjon"); + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); let binding = Binding::new(StepKind::Given, r"I am Tomjon", "set_name").unwrap(); let mut bindings = Bindings::new(); bindings.add(&binding); @@ -423,7 +423,7 @@ mod test_bindings { #[test] fn finds_match_for_regexp_pattern() { - let step = ScenarioStep::new(StepKind::Given, "I am Tomjon"); + let step = ScenarioStep::new(StepKind::Given, "given", "I am Tomjon"); let binding = Binding::new(StepKind::Given, r"I am (?P<name>\S+)", "set_name").unwrap(); let mut bindings = Bindings::new(); bindings.add(&binding); diff --git a/src/error.rs b/src/error.rs index 3d28d3b..0a79cf6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -89,15 +89,19 @@ pub enum SubplotError { #[error("first scenario is before first heading")] ScenarioBeforeHeading, - /// Unknown scenario step keyword + /// Step does not have a keyword. + #[error("step has no keyword: {0}")] + NoStepKeyword(String), + + /// Unknown scenario step keyword. /// /// Each scenario step must start with a known keyword (given, /// when, then, and, but), but Subplot didn't find one it /// recognized. /// /// This is usually due to a typing mistake or similar. - #[error("unknown step keyword")] - UnknownStepKind, + #[error("unknown step keyword: {0}")] + UnknownStepKind(String), /// Scenario step uses continuation keyword too early /// diff --git a/src/scenarios.rs b/src/scenarios.rs index 569d33a..bb1e3df 100644 --- a/src/scenarios.rs +++ b/src/scenarios.rs @@ -94,7 +94,7 @@ mod test { #[test] fn adds_step() { let mut scen = Scenario::new("title"); - let step = ScenarioStep::new(StepKind::Given, "foo"); + let step = ScenarioStep::new(StepKind::Given, "and", "foo"); scen.add(&step); assert_eq!(scen.steps(), &[step]); } diff --git a/src/steps.rs b/src/steps.rs index 2c6f34f..1cbdfe5 100644 --- a/src/steps.rs +++ b/src/steps.rs @@ -14,14 +14,16 @@ use std::fmt; #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct ScenarioStep { kind: StepKind, + keyword: String, text: String, } impl ScenarioStep { /// Construct a new step. - pub fn new(kind: StepKind, text: &str) -> ScenarioStep { + pub fn new(kind: StepKind, keyword: &str, text: &str) -> ScenarioStep { ScenarioStep { kind, + keyword: keyword.to_owned(), text: text.to_owned(), } } @@ -31,6 +33,11 @@ impl ScenarioStep { self.kind } + /// Return the actual textual keyword of a step. + pub fn keyword(&self) -> &str { + &self.keyword + } + /// Return the text of a step. pub fn text(&self) -> &str { &self.text @@ -43,13 +50,18 @@ impl ScenarioStep { pub fn new_from_str(text: &str, default: Option<StepKind>) -> Result<ScenarioStep> { let mut words = text.split_whitespace(); - let kind = match words.next() { - Some("given") => StepKind::Given, - Some("when") => StepKind::When, - Some("then") => StepKind::Then, - Some("and") => default.ok_or(SubplotError::ContinuationTooEarly)?, - Some("but") => default.ok_or(SubplotError::ContinuationTooEarly)?, - _ => return Err(SubplotError::UnknownStepKind), + let keyword = match words.next() { + Some(s) => s, + _ => return Err(SubplotError::NoStepKeyword(text.to_string())), + }; + + let kind = match keyword { + "given" => StepKind::Given, + "when" => StepKind::When, + "then" => StepKind::Then, + "and" => default.ok_or(SubplotError::ContinuationTooEarly)?, + "but" => default.ok_or(SubplotError::ContinuationTooEarly)?, + _ => return Err(SubplotError::UnknownStepKind(keyword.to_string())), }; let mut joined = String::new(); @@ -60,13 +72,13 @@ impl ScenarioStep { if joined.len() > 1 { joined.pop(); } - Ok(ScenarioStep::new(kind, &joined)) + Ok(ScenarioStep::new(kind, keyword, &joined)) } } impl fmt::Display for ScenarioStep { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} {}", self.kind(), self.text()) + write!(f, "{} {}", self.keyword(), self.text()) } } @@ -518,18 +518,18 @@ program, and examining the output. ~~~scenario given file simple.md -given file b.yaml -given file f.py +and file b.yaml +and 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 +and step "given precondition foo" was run +and step "when I do bar" was run +and step "then bar was done" was run +and program finished successfully ~~~ @@ -545,16 +545,16 @@ combinations. ~~~scenario given file allkeywords.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen allkeywords.md -o foo.pdf then file foo.pdf exists when I run sp-codegen --run allkeywords.md -o test.py then scenario "All keywords" 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 +and step "given precondition foo" was run +and step "when I do bar" was run +and step "then bar was done" was run +and program finished successfully ~~~ ~~~{#allkeywords.md .file .markdown .numberLines} @@ -577,6 +577,39 @@ but foobar was done ``` ~~~ +### Keyword aliases + +~~~scenario +given file aliases.md +and file b.yaml +and file f.py +when I run sp-docgen aliases.md -o aliases.html +then file aliases.html matches /given<[^>]*> precondition foo/ +and file aliases.html matches /when<[^>]*> I do bar/ +and file aliases.html matches /and<[^>]*> I do foobar/ +and file aliases.html matches /then<[^>]*> bar was done/ +and file aliases.html matches /but<[^>]*> foobar was done/ +and program finished successfully +~~~ + +~~~{#aliases.md .file .markdown .numberLines} +--- +title: Keyword aliasesG +bindings: b.yaml +functions: f.py +... + +# Aliases + +```scenario +given precondition foo +when I do bar +and I do foobar +then bar was done +but foobar was done +``` +~~~ + ### Misuse of continuation keywords When continuation keywords (`and` and `but`) are used, they have to not be @@ -586,8 +619,8 @@ be continuing. ~~~scenario given file continuationmisuse.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen continuationmisuse.md -o foo.pdf then file foo.pdf exists when I try to run sp-codegen --run continuationmisuse.md -o test.py @@ -620,18 +653,18 @@ This scenario verifies that empty lines in scenarios are ignored. ~~~scenario given file emptylines.md -given file b.yaml -given file f.py +and file b.yaml +and 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 +and step "given precondition foo" was run +and step "when I do bar" was run +and step "then bar was done" was run +and program finished successfully ~~~ @@ -746,27 +779,27 @@ programs that monitor the output file for changes. ~~~scenario given file simple.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen simple.md -o simple.pdf then file simple.pdf exists when I remember the metadata for simple.pdf -when I run sp-docgen simple.md -o simple.pdf +and I run sp-docgen simple.md -o simple.pdf then simple.pdf has the same metadata as before -then only files simple.md, b.yaml, f.py, simple.pdf exist +and only files simple.md, b.yaml, f.py, simple.pdf exist ~~~ ### Do typeset if output is older than markdown ~~~scenario given file simple.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen simple.md -o simple.pdf then file simple.pdf exists when I remember the metadata for simple.pdf -when I touch simple.md -when I run sp-docgen simple.md -o simple.pdf +and I touch simple.md +and I run sp-docgen simple.md -o simple.pdf then simple.pdf has changed from before ~~~ @@ -774,13 +807,13 @@ then simple.pdf has changed from before ~~~scenario given file simple.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen simple.md -o simple.pdf then file simple.pdf exists when I remember the metadata for simple.pdf -when I touch f.py -when I run sp-docgen simple.md -o simple.pdf +and I touch f.py +and I run sp-docgen simple.md -o simple.pdf then simple.pdf has changed from before ~~~ @@ -788,13 +821,13 @@ then simple.pdf has changed from before ~~~scenario given file simple.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-docgen simple.md -o simple.pdf then file simple.pdf exists when I remember the metadata for simple.pdf -when I touch b.yaml -when I run sp-docgen simple.md -o simple.pdf +and I touch b.yaml +and I run sp-docgen simple.md -o simple.pdf then simple.pdf has changed from before ~~~ @@ -811,11 +844,11 @@ higher level starts a new scenario. ~~~scenario given file scenarioislowest.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-codegen --run scenarioislowest.md -o test.py then scenario "heading 1.1.1" was run -then program finished successfully +and program finished successfully ~~~ ~~~~{#scenarioislowest.md .file .markdown .numberLines} @@ -839,11 +872,11 @@ given precondition foo ~~~scenario given file subisnotnewscenario.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-codegen --run subisnotnewscenario.md -o test.py then scenario "heading 1.1a" was run -then program finished successfully +and program finished successfully ~~~ ~~~~{#subisnotnewscenario.md .file .markdown .numberLines} @@ -870,12 +903,12 @@ given precondition foo ~~~scenario given file samelevelisnewscenario.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-codegen --run samelevelisnewscenario.md -o test.py then scenario "heading 1.1.1" was run -then scenario "heading 1.1.2" was run -then program finished successfully +and scenario "heading 1.1.2" was run +and program finished successfully ~~~ ~~~~{#samelevelisnewscenario.md .file .markdown .numberLines} @@ -905,12 +938,12 @@ given precondition foo ~~~scenario given file higherisnewscenario.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-codegen --run higherisnewscenario.md -o test.py then scenario "heading 1.1.1" was run -then scenario "heading 1.2" was run -then program finished successfully +and scenario "heading 1.2" was run +and program finished successfully ~~~ ~~~~{#higherisnewscenario.md .file .markdown .numberLines} @@ -951,12 +984,12 @@ chosen scenarios. ~~~scenario given file twoscenarios-python.md -given file b.yaml -given file f.py +and file b.yaml +and file f.py when I run sp-codegen twoscenarios-python.md -o test.py and I run python3 test.py on then scenario "One" was run -then scenario "Two" was not run +and scenario "Two" was not run and program finished successfully ~~~ @@ -991,12 +1024,12 @@ chosen scenarios. ~~~scenario given file twoscenarios-bash.md -given file b.yaml -given file f.sh +and file b.yaml +and file f.sh when I run sp-codegen twoscenarios-bash.md -o test.sh and I run bash test.sh on then scenario "One" was run -then scenario "Two" was not run +and scenario "Two" was not run and program finished successfully ~~~ @@ -1119,10 +1152,10 @@ specified. given file metadate.md when I run sp-docgen metadate.md -o metadate.html then file metadate.html exists -then file metadate.html contains "<title>The Fabulous Title</title>" -then file metadate.html contains "Alfred Pennyworth" -then file metadate.html contains "Geoffrey Butler" -then file metadate.html contains "WIP" +and file metadate.html contains "<title>The Fabulous Title</title>" +and file metadate.html contains "Alfred Pennyworth" +and file metadate.html contains "Geoffrey Butler" +and file metadate.html contains "WIP" ~~~ ~~~{#metadate.md .file .markdown .numberLines} @@ -1145,10 +1178,10 @@ This scenario tests that the `--date` command line option is used. given file dateless.md when I run sp-docgen dateless.md -o dateoption.html --date=FANCYDATE then file dateoption.html exists -then file dateoption.html contains "<title>The Fabulous Title</title>" -then file dateoption.html contains "Alfred Pennyworth" -then file dateoption.html contains "Geoffrey Butler" -then file dateoption.html contains "FANCYDATE" +and file dateoption.html contains "<title>The Fabulous Title</title>" +and file dateoption.html contains "Alfred Pennyworth" +and file dateoption.html contains "Geoffrey Butler" +and file dateoption.html contains "FANCYDATE" ~~~ ~~~{#dateless.md .file .markdown .numberLines} @@ -1171,13 +1204,13 @@ modification time of the input file, and shall have the date in ISO ~~~scenario given file dateless.md -given file dateless.md has modification time 2020-02-26 07:53:17 +and file dateless.md has modification time 2020-02-26 07:53:17 when I run sp-docgen dateless.md -o mtime.html then file mtime.html exists -then file mtime.html contains "<title>The Fabulous Title</title>" -then file mtime.html contains "Alfred Pennyworth" -then file mtime.html contains "Geoffrey Butler" -then file mtime.html contains "2020-02-26 07:53" +and file mtime.html contains "<title>The Fabulous Title</title>" +and file mtime.html contains "Alfred Pennyworth" +and file mtime.html contains "Geoffrey Butler" +and file mtime.html contains "2020-02-26 07:53" ~~~ ### Using as a Pandoc filter @@ -1237,19 +1270,19 @@ or functions files. ~~~scenario given file images.md -given file b.yaml -given file f.py -given file foo.bib -given file bar.bib +and file b.yaml +and file f.py +and file foo.bib +and file bar.bib when I run sp-meta images.md then output matches /source: images.md/ -then output matches /source: b.yaml/ -then output matches /source: f.py/ -then output matches /source: foo.bib/ -then output matches /source: bar.bib/ -then output matches /source: image.gif/ -then output matches /bindings: b.yaml/ -then output matches /functions: f.py/ +and output matches /source: b.yaml/ +and output matches /source: f.py/ +and output matches /source: foo.bib/ +and output matches /source: bar.bib/ +and output matches /source: image.gif/ +and output matches /bindings: b.yaml/ +and output matches /functions: f.py/ ~~~ @@ -1317,7 +1350,7 @@ This is the embedded file. given file onefiletwice.md when I try to run sp-docgen onefiletwice.md -o onefiletwice.html then exit code is non-zero -then file onefiletwice.html does not exist +and file onefiletwice.html does not exist ~~~ ~~~~{#onefiletwice.md .file .markdown .numberLines} @@ -1341,7 +1374,7 @@ This is another embedded file, and has the same name. given file casediff.md when I try to run sp-docgen casediff.md -o casediff.html then exit code is non-zero -then file casediff.html does not exist +and file casediff.html does not exist ~~~ ~~~~{#casediff.md .file .markdown .numberLines} @@ -1381,7 +1414,7 @@ HTML output, not referenced as an external image. ~~~scenario given file dot.md -given file b.yaml +and 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,/ ~~~ @@ -1422,7 +1455,7 @@ the HTML output, not referenced as an external image. ~~~scenario given file plantuml.md -given file b.yaml +and file b.yaml when I run pandoc --filter sp-filter plantuml.md -o plantuml.html then file plantuml.html matches /img src="data:image/svg\+xml;base64,/ ~~~ @@ -1502,7 +1535,7 @@ HTML output, not referenced as an external image. ~~~scenario given file roadmap.md -given file b.yaml +and 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,/ ~~~ @@ -1556,6 +1589,7 @@ blocked: ~~~ ~~~~~~~~ + ### Class name validation When Subplot loads a document it will validate that the block classes |