summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-05-09 09:34:36 +0300
committerLars Wirzenius <liw@liw.fi>2020-05-09 11:07:37 +0300
commita21ba1f5fcc9b03f7657c5b00c4c215286b06341 (patch)
treea64b77067ca53d8cf32482b8ab1b64ad7687f711
parentaefd93fb14b4781deca481d2a21953c9fd30f361 (diff)
downloadsubplot-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.rs7
-rw-r--r--src/bindings.rs16
-rw-r--r--src/error.rs10
-rw-r--r--src/scenarios.rs2
-rw-r--r--src/steps.rs32
-rw-r--r--subplot.md204
6 files changed, 158 insertions, 113 deletions
diff --git a/src/ast.rs b/src/ast.rs
index 27401ad..962aa21 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -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())
}
}
diff --git a/subplot.md b/subplot.md
index 7b42dea..b73effa 100644
--- a/subplot.md
+++ b/subplot.md
@@ -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