Skip to content

Commit 3ea1819

Browse files
authored
Merge pull request #367 from Kobzol/input-list
Add support for input list questions
2 parents c017c84 + 08e6e54 commit 3ea1819

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

verifier/src/api.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,12 @@ pub enum Question {
193193
description_text: String,
194194
ranking: RankingChoices,
195195
},
196+
#[serde(rename = "input_list")]
197+
InputList {
198+
question_text: String,
199+
description_text: String,
200+
input_list: InputListInputs,
201+
},
196202
}
197203

198204
impl Question {
@@ -203,6 +209,7 @@ impl Question {
203209
Self::ChoiceTable { question_text, .. } => question_text,
204210
Self::RatingScale { question_text, .. } => question_text,
205211
Self::Ranking { question_text, .. } => question_text,
212+
Self::InputList { question_text, .. } => question_text,
206213
})
207214
}
208215

@@ -220,7 +227,12 @@ impl Question {
220227
Self::RatingScale {
221228
description_text, ..
222229
} => description_text,
223-
Self::Ranking { description_text, .. } => description_text,
230+
Self::Ranking {
231+
description_text, ..
232+
} => description_text,
233+
Self::InputList {
234+
description_text, ..
235+
} => description_text,
224236
})
225237
}
226238

@@ -315,7 +327,7 @@ pub struct Settings {
315327

316328
#[derive(Debug, Deserialize)]
317329
pub struct RankingChoices {
318-
choices: Vec<RankingChoice>,
330+
choices: Vec<ChoiceWithLabel>,
319331
}
320332

321333
impl RankingChoices {
@@ -334,10 +346,30 @@ impl RankingChoices {
334346
}
335347

336348
#[derive(Debug, Deserialize)]
337-
pub struct RankingChoice {
349+
pub struct ChoiceWithLabel {
338350
label: String,
339351
}
340352

353+
#[derive(Debug, Deserialize)]
354+
pub struct InputListInputs {
355+
inputs: Vec<ChoiceWithLabel>,
356+
}
357+
358+
impl InputListInputs {
359+
pub fn as_strs(&self) -> impl Iterator<Item = String> + '_ {
360+
self.inputs
361+
.iter()
362+
.map(|c| normalize_surveyhero_text(c.label.as_str()))
363+
}
364+
365+
pub fn mismatched_answers<'a>(&'a self, answers: &'a [&str]) -> Vec<(String, &'a str)> {
366+
self.as_strs()
367+
.zip(answers.iter().map(|s| normalize_markdown_text(s)))
368+
.filter(|(s1, s2)| s1 != s2)
369+
.collect()
370+
}
371+
}
372+
341373
#[derive(Debug, Deserialize)]
342374
pub struct Surveys {
343375
pub surveys: Vec<Survey>,

verifier/src/main.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::api::Question;
2+
use crate::markdown::Answers;
23
use crate::render::render_questions;
34
use anyhow::Context;
45
use clap::Parser;
@@ -200,6 +201,20 @@ impl markdown::Question<'_> {
200201
);
201202
}
202203
}
204+
(Answers::InputList(answers), Question::InputList { input_list, .. }) => {
205+
let mismatched = input_list.mismatched_answers(&answers);
206+
if !mismatched.is_empty() {
207+
return Comparison::AnswersDiffer(
208+
mismatched
209+
.into_iter()
210+
.map(|(s1, s2)| AnswerDiff {
211+
sh: s1,
212+
md: s2.to_string(),
213+
})
214+
.collect(),
215+
);
216+
}
217+
}
203218
_ => {
204219
return Comparison::QuestionTypesDiffer {
205220
question: self.text.to_owned(),
@@ -245,6 +260,7 @@ enum QuestionType {
245260
Matrix,
246261
RatingScale,
247262
Ranking,
263+
InputList,
248264
}
249265

250266
impl<'a> From<&'a Question> for QuestionType {
@@ -262,6 +278,7 @@ impl<'a> From<&'a Question> for QuestionType {
262278
match q {
263279
Question::RatingScale { .. } => QuestionType::RatingScale,
264280
Question::Ranking { .. } => QuestionType::Ranking,
281+
Question::InputList { .. } => QuestionType::InputList,
265282
_ => QuestionType::Matrix,
266283
}
267284
}
@@ -276,6 +293,7 @@ impl From<&markdown::Question<'_>> for QuestionType {
276293
markdown::Answers::Matrix { .. } => Self::Matrix,
277294
markdown::Answers::RatingScale => Self::RatingScale,
278295
markdown::Answers::Ranking(_) => Self::Ranking,
296+
markdown::Answers::InputList(_) => Self::InputList,
279297
}
280298
}
281299
}

verifier/src/markdown.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ pub fn parse(markdown: &str) -> anyhow::Result<Vec<Question<'_>>> {
5959
text,
6060
answers: Answers::Ranking(vec![]),
6161
})
62+
} else if typ.starts_with("input list") {
63+
ParserState::Question(Question {
64+
text,
65+
answers: Answers::InputList(vec![]),
66+
})
6267
} else {
6368
bail!("illegal question type: type='{}' question='{}'", typ, text);
6469
}
@@ -81,6 +86,10 @@ pub fn parse(markdown: &str) -> anyhow::Result<Vec<Question<'_>>> {
8186
| ParserState::Question(Question {
8287
answers: Answers::Ranking(ref mut a),
8388
..
89+
})
90+
| ParserState::Question(Question {
91+
answers: Answers::InputList(ref mut a),
92+
..
8493
}) => a.push(trim_answer(line[1..].trim())),
8594
ParserState::Question(Question {
8695
answers:
@@ -198,6 +207,7 @@ pub enum Answers<'a> {
198207
FreeForm,
199208
RatingScale,
200209
Ranking(Vec<&'a str>),
210+
InputList(Vec<&'a str>),
201211
SelectOne(Vec<&'a str>),
202212
SelectMany(Vec<&'a str>),
203213
Matrix {
@@ -213,6 +223,7 @@ impl Answers<'_> {
213223
Self::SelectOne(a) => a.is_empty(),
214224
Self::SelectMany(a) => a.is_empty(),
215225
Self::Ranking(a) => a.is_empty(),
226+
Self::InputList(a) => a.is_empty(),
216227
Self::Matrix {
217228
answers1, answers2, ..
218229
} => answers1.is_empty() || answers2.is_empty(),

verifier/src/render.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ pub fn render_questions(questions: &[Question], file: &Path) -> io::Result<()> {
5151
writeln!(file, "- {variant}")?;
5252
}
5353
}
54+
Question::InputList { input_list, .. } => {
55+
writeln!(file, "Type: input list\n")?;
56+
for input in input_list.as_strs() {
57+
writeln!(file, "- {input}")?;
58+
}
59+
}
5460
}
5561
writeln!(file)?;
5662
}

0 commit comments

Comments
 (0)