puzzle.json: move Pre and Post out to top-level

This commit is contained in:
Neale Pickett 2021-02-24 16:34:35 -07:00
parent 2e0dfb601a
commit 1fffeb0060
19 changed files with 119 additions and 146 deletions

View File

@ -15,13 +15,12 @@ import (
var testMothYaml = []byte(`--- var testMothYaml = []byte(`---
answers: answers:
- YAML answer - YAML answer
pre: authors:
authors: - Arthur
- Arthur - Buster
- Buster - DW
- DW attachments:
attachments: - filename: moo.txt
- filename: moo.txt
--- ---
YAML body YAML body
`) `)
@ -189,4 +188,4 @@ func TestFilesystem(t *testing.T) {
if !strings.Contains(stdout.String(), "Moo.") { if !strings.Contains(stdout.String(), "Moo.") {
t.Error("Wrong file pulled", stdout.String()) t.Error("Wrong file pulled", stdout.String())
} }
} }

View File

@ -11,10 +11,8 @@ case $1:$2 in
cat <<EOT cat <<EOT
{ {
"Answers": ["$answer"], "Answers": ["$answer"],
"Pre": { "Authors": ["neale"],
"Authors": ["neale"], "Body": "I am a generated puzzle."
"Body": "I am a generated puzzle."
}
} }
EOT EOT
;; ;;

View File

@ -18,10 +18,8 @@ EOT
cat <<EOT cat <<EOT
{ {
"Answers": ["answer1.0"], "Answers": ["answer1.0"],
"Pre": { "Authors": ["author1.0"],
"Authors": ["author1.0"], "Body": "<h1>moo.</h1>"
"Body": "<h1>moo.</h1>"
}
} }
EOT EOT
;; ;;

View File

@ -1,7 +1,6 @@
--- ---
pre: authors:
authors: - neale
- neale
debug: debug:
summary: static puzzles summary: static puzzles
answers: answers:

View File

@ -1,7 +1,6 @@
--- ---
pre: authors:
authors: - neale
- neale
debug: debug:
summary: Making excellent puzzles summary: Making excellent puzzles
answers: answers:

View File

@ -1,11 +1,10 @@
--- ---
pre: authors:
authors: - neale
- neale attachments:
attachments: - filename: salad.jpg
- filename: salad.jpg - filename: s2.jpg
- filename: s2.jpg filesystempath: salad2.jpg
filesystempath: salad2.jpg
debug: debug:
summary: Static puzzle resource files summary: Static puzzle resource files
answers: answers:

View File

@ -15,15 +15,13 @@ answer = ' '.join(random.sample(words, 4))
def puzzle(): def puzzle():
number = random.randint(20, 500) number = random.randint(20, 500)
obj = { obj = {
"Pre": { "Authors": ["neale"],
"Authors": ["neale"], "Body": (
"Body": ( "<p>Dynamic puzzles are provided with a JSON-generating <code>mkpuzzles</code> program in the puzzle directory.</p>"
"<p>Dynamic puzzles are provided with a JSON-generating <code>mkpuzzles</code> program in the puzzle directory.</p>" "<p>You can write <code>mkpuzzles</code> in any language you like. This puzzle was written in Python 3.</p>"
"<p>You can write <code>mkpuzzles</code> in any language you like. This puzzle was written in Python 3.</p>" "<p>Here is some salad:<img src='salad.jpg'></p>"
"<p>Here is some salad:<img src='salad.jpg'></p>" ),
), "Attachments": ["salad.jpg"],
"Attachments": ["salad.jpg"],
},
"Answers": [ "Answers": [
answer, answer,
], ],

View File

@ -1,10 +1,9 @@
--- ---
pre: authors:
authors: - neale
- neale scripts:
scripts: - filename: helpers.js
- filename: helpers.js - filename: draggable.js
- filename: draggable.js
answers: answers:
- helper - helper
debug: debug:

View File

@ -1,6 +1,5 @@
--- ---
pre: authors: ["neale"]
authors: ["neale"]
answers: ["6"] answers: ["6"]
--- ---
This category shows off how to use the transpiler from an This category shows off how to use the transpiler from an

View File

@ -1,6 +1,5 @@
--- ---
pre: authors: ["neale"]
authors: ["neale"]
answers: ["C", "c"] answers: ["C", "c"]
--- ---
2 4 6 8 A _ 2 4 6 8 A _

View File

@ -1,6 +1,5 @@
--- ---
pre: authors: ["neale"]
authors: ["neale"]
answers: ["17"] answers: ["17"]
--- ---
1 2 3 5 7 11 13 _ 1 2 3 5 7 11 13 _

View File

@ -59,16 +59,16 @@ func TestOsFsCategory(t *testing.T) {
if p, err := static.Puzzle(1); err != nil { if p, err := static.Puzzle(1); err != nil {
t.Error(err) t.Error(err)
} else if len(p.Pre.Authors) != 1 { } else if len(p.Authors) != 1 {
t.Error("Wrong authors list", p.Pre.Authors) t.Error("Wrong authors list", p.Authors)
} else if p.Pre.Authors[0] != "neale" { } else if p.Authors[0] != "neale" {
t.Error("Wrong authors", p.Pre.Authors) t.Error("Wrong authors", p.Authors)
} }
if p, err := static.Puzzle(3); err != nil { if p, err := static.Puzzle(3); err != nil {
t.Error(err) t.Error(err)
} else if len(p.Pre.Authors) != 1 { } else if len(p.Authors) != 1 {
t.Error("Wrong authors", p.Pre.Authors) t.Error("Wrong authors", p.Authors)
} }
generated := NewFsCategory(fs, "generated") generated := NewFsCategory(fs, "generated")

View File

@ -7,13 +7,12 @@ import (
var testMothYaml = []byte(`--- var testMothYaml = []byte(`---
answers: answers:
- YAML answer - YAML answer
pre: authors:
authors: - Arthur
- Arthur - Buster
- Buster - DW
- DW attachments:
attachments: - moo.txt
- moo.txt
--- ---
YAML body YAML body
`) `)
@ -27,9 +26,8 @@ RFC822 body
var testMothMarkdown = []byte(`--- var testMothMarkdown = []byte(`---
answers: answers:
- answer - answer
pre: authors:
authors: - Fred
- Fred
--- ---
one | two one | two

View File

@ -53,7 +53,7 @@ func Mothball(c Category, w io.Writer) error {
} }
// Write out all attachments and scripts // Write out all attachments and scripts
attachments := append(puzzle.Pre.Attachments, puzzle.Pre.Scripts...) attachments := append(puzzle.Attachments, puzzle.Scripts...)
for _, att := range attachments { for _, att := range attachments {
attPath := fmt.Sprintf("%d/%s", points, att) attPath := fmt.Sprintf("%d/%s", points, att)
aw, err := zf.Create(attPath) aw, err := zf.Create(attPath)

View File

@ -32,28 +32,26 @@ type AnswerResponse struct {
// Puzzle contains everything about a puzzle that a client would see. // Puzzle contains everything about a puzzle that a client would see.
type Puzzle struct { type Puzzle struct {
Pre struct {
Authors []string
Attachments []string
Scripts []string
Body string
AnswerPattern string
AnswerHashes []string
}
Post struct {
Objective string
Success struct {
Acceptable string
Mastery string
}
KSAs []string
}
Debug struct { Debug struct {
Log []string Log []string
Errors []string Errors []string
Hints []string Hints []string
Summary string Summary string
} }
Authors []string
Attachments []string
Scripts []string
Body string
AnswerPattern string
AnswerHashes []string
Objective string
KSAs []string
Success struct {
Acceptable string
Mastery string
}
// Answers will be empty in a mothball
Answers []string Answers []string
} }
@ -61,30 +59,26 @@ func (puzzle *Puzzle) computeAnswerHashes() {
if len(puzzle.Answers) == 0 { if len(puzzle.Answers) == 0 {
return return
} }
puzzle.Pre.AnswerHashes = make([]string, len(puzzle.Answers)) puzzle.AnswerHashes = make([]string, len(puzzle.Answers))
for i, answer := range puzzle.Answers { for i, answer := range puzzle.Answers {
sum := sha256.Sum256([]byte(answer)) sum := sha256.Sum256([]byte(answer))
hexsum := fmt.Sprintf("%x", sum) hexsum := fmt.Sprintf("%x", sum)
puzzle.Pre.AnswerHashes[i] = hexsum puzzle.AnswerHashes[i] = hexsum
} }
} }
// StaticPuzzle contains everything a static puzzle might tell us. // StaticPuzzle contains everything a static puzzle might tell us.
type StaticPuzzle struct { type StaticPuzzle struct {
Pre struct { Authors []string
Authors []string Attachments []StaticAttachment
Attachments []StaticAttachment Scripts []StaticAttachment
Scripts []StaticAttachment AnswerPattern string
AnswerPattern string Objective string
} Success struct {
Post struct { Acceptable string
Objective string Mastery string
Success struct {
Acceptable string
Mastery string
}
KSAs []string
} }
KSAs []string
Debug struct { Debug struct {
Log []string Log []string
Errors []string Errors []string
@ -187,7 +181,7 @@ type FsPuzzle struct {
// Puzzle returns a Puzzle struct for the current puzzle. // Puzzle returns a Puzzle struct for the current puzzle.
func (fp FsPuzzle) Puzzle() (Puzzle, error) { func (fp FsPuzzle) Puzzle() (Puzzle, error) {
var puzzle Puzzle puzzle := Puzzle{}
static, body, err := fp.staticPuzzle() static, body, err := fp.staticPuzzle()
if err != nil { if err != nil {
@ -195,20 +189,21 @@ func (fp FsPuzzle) Puzzle() (Puzzle, error) {
} }
// Convert to an exportable Puzzle // Convert to an exportable Puzzle
puzzle.Post = static.Post
puzzle.Debug = static.Debug puzzle.Debug = static.Debug
puzzle.Answers = static.Answers puzzle.Answers = static.Answers
puzzle.Pre.Authors = static.Pre.Authors puzzle.Authors = static.Authors
puzzle.Pre.Body = string(body) puzzle.Body = string(body)
puzzle.Pre.AnswerPattern = static.Pre.AnswerPattern puzzle.AnswerPattern = static.AnswerPattern
puzzle.Pre.Attachments = make([]string, len(static.Pre.Attachments)) puzzle.Attachments = make([]string, len(static.Attachments))
for i, attachment := range static.Pre.Attachments { for i, attachment := range static.Attachments {
puzzle.Pre.Attachments[i] = attachment.Filename puzzle.Attachments[i] = attachment.Filename
} }
puzzle.Pre.Scripts = make([]string, len(static.Pre.Scripts)) puzzle.Scripts = make([]string, len(static.Scripts))
for i, script := range static.Pre.Scripts { for i, script := range static.Scripts {
puzzle.Pre.Scripts[i] = script.Filename puzzle.Scripts[i] = script.Filename
} }
empty := Puzzle{}
puzzle.Debug = empty.Debug
puzzle.computeAnswerHashes() puzzle.computeAnswerHashes()
return puzzle, nil return puzzle, nil
@ -223,7 +218,7 @@ func (fp FsPuzzle) Open(name string) (ReadSeekCloser, error) {
} }
var fsPath string var fsPath string
for _, attachment := range append(static.Pre.Attachments, static.Pre.Scripts...) { for _, attachment := range append(static.Attachments, static.Scripts...) {
if attachment.Filename == name { if attachment.Filename == name {
if attachment.FilesystemPath == "" { if attachment.FilesystemPath == "" {
fsPath = attachment.Filename fsPath = attachment.Filename
@ -337,13 +332,13 @@ func rfc822HeaderParser(r io.Reader) (StaticPuzzle, error) {
key = strings.ToLower(key) key = strings.ToLower(key)
switch key { switch key {
case "author": case "author":
p.Pre.Authors = val p.Authors = val
case "pattern": case "pattern":
p.Pre.AnswerPattern = val[0] p.AnswerPattern = val[0]
case "script": case "script":
p.Pre.Scripts = legacyAttachmentParser(val) p.Scripts = legacyAttachmentParser(val)
case "file": case "file":
p.Pre.Attachments = legacyAttachmentParser(val) p.Attachments = legacyAttachmentParser(val)
case "answer": case "answer":
p.Answers = val p.Answers = val
case "summary": case "summary":
@ -353,13 +348,13 @@ func rfc822HeaderParser(r io.Reader) (StaticPuzzle, error) {
case "solution": case "solution":
p.Debug.Hints = val p.Debug.Hints = val
case "ksa": case "ksa":
p.Post.KSAs = val p.KSAs = val
case "objective": case "objective":
p.Post.Objective = val[0] p.Objective = val[0]
case "success.acceptable": case "success.acceptable":
p.Post.Success.Acceptable = val[0] p.Success.Acceptable = val[0]
case "success.mastery": case "success.mastery":
p.Post.Success.Mastery = val[0] p.Success.Mastery = val[0]
default: default:
return p, fmt.Errorf("Unknown header field: %s", key) return p, fmt.Errorf("Unknown header field: %s", key)
} }

View File

@ -23,11 +23,11 @@ func TestPuzzle(t *testing.T) {
if (len(p.Answers) == 0) || (p.Answers[0] != "YAML answer") { if (len(p.Answers) == 0) || (p.Answers[0] != "YAML answer") {
t.Error("Answers are wrong", p.Answers) t.Error("Answers are wrong", p.Answers)
} }
if (len(p.Pre.Authors) != 3) || (p.Pre.Authors[1] != "Buster") { if (len(p.Authors) != 3) || (p.Authors[1] != "Buster") {
t.Error("Authors are wrong", p.Pre.Authors) t.Error("Authors are wrong", p.Authors)
} }
if p.Pre.Body != "<p>YAML body</p>\n" { if p.Body != "<p>YAML body</p>\n" {
t.Errorf("Body parsed wrong: %#v", p.Pre.Body) t.Errorf("Body parsed wrong: %#v", p.Body)
} }
f, err := pd.Open("moo.txt") f, err := pd.Open("moo.txt")
@ -52,11 +52,11 @@ func TestPuzzle(t *testing.T) {
if (len(p.Answers) == 0) || (p.Answers[0] != "RFC822 answer") { if (len(p.Answers) == 0) || (p.Answers[0] != "RFC822 answer") {
t.Error("Answers are wrong", p.Answers) t.Error("Answers are wrong", p.Answers)
} }
if (len(p.Pre.Authors) != 3) || (p.Pre.Authors[1] != "Arthur") { if (len(p.Authors) != 3) || (p.Authors[1] != "Arthur") {
t.Error("Authors are wrong", p.Pre.Authors) t.Error("Authors are wrong", p.Authors)
} }
if p.Pre.Body != "<p>RFC822 body</p>\n" { if p.Body != "<p>RFC822 body</p>\n" {
t.Errorf("Body parsed wrong: %#v", p.Pre.Body) t.Errorf("Body parsed wrong: %#v", p.Body)
} }
} }
@ -66,9 +66,9 @@ func TestPuzzle(t *testing.T) {
if puzzle, err := NewFsPuzzlePoints(catFs, 4).Puzzle(); err != nil { if puzzle, err := NewFsPuzzlePoints(catFs, 4).Puzzle(); err != nil {
t.Error("Markdown test file:", err) t.Error("Markdown test file:", err)
} else if !strings.Contains(puzzle.Pre.Body, "<table>") { } else if !strings.Contains(puzzle.Body, "<table>") {
t.Error("Markdown table extension isn't making tables") t.Error("Markdown table extension isn't making tables")
} else if !strings.Contains(puzzle.Pre.Body, "<dl>") { } else if !strings.Contains(puzzle.Body, "<dl>") {
t.Error("Markdown dictionary extension isn't making tables") t.Error("Markdown dictionary extension isn't making tables")
} }
@ -110,7 +110,7 @@ func TestFsPuzzle(t *testing.T) {
if puzzle, err := NewFsPuzzlePoints(catFs, 2).Puzzle(); err != nil { if puzzle, err := NewFsPuzzlePoints(catFs, 2).Puzzle(); err != nil {
t.Error(err) t.Error(err)
} else if !strings.Contains(puzzle.Pre.Body, "class=\"moo\"") { } else if !strings.Contains(puzzle.Body, "class=\"moo\"") {
t.Error("Raw HTML didn't make it through") t.Error("Raw HTML didn't make it through")
} }
@ -150,11 +150,10 @@ func TestFsPuzzle(t *testing.T) {
func TestAttachment(t *testing.T) { func TestAttachment(t *testing.T) {
buf := bytes.NewBufferString(` buf := bytes.NewBufferString(`
pre: attachments:
attachments: - simple
- simple - filename: complex
- filename: complex filesystempath: backingfile
filesystempath: backingfile
`) `)
p, err := yamlHeaderParser(buf) p, err := yamlHeaderParser(buf)
if err != nil { if err != nil {
@ -162,7 +161,7 @@ pre:
return return
} }
att := p.Pre.Attachments att := p.Attachments
if len(att) != 2 { if len(att) != 2 {
t.Error("Wrong number of attachments", att) t.Error("Wrong number of attachments", att)
} }

View File

@ -18,10 +18,8 @@ EOT
cat <<EOT cat <<EOT
{ {
"Answers": ["answer1.0"], "Answers": ["answer1.0"],
"Pre": { "Authors": ["author1.0"],
"Authors": ["author1.0"], "Body": "<h1>moo.</h1>"
"Body": "<h1>moo.</h1>"
}
} }
EOT EOT
;; ;;

View File

@ -1,7 +1,6 @@
--- ---
pre: authors:
authors: - neale
- neale
answers: answers:
- moo - moo
--- ---

View File

@ -10,10 +10,8 @@ case $1:$2 in
cat <<'EOT' cat <<'EOT'
{ {
"Answers": ["answer"], "Answers": ["answer"],
"Pre": { "Authors": ["neale"],
"Authors": ["neale"], "Body": "I am a generated puzzle."
"Body": "I am a generated puzzle."
}
} }
EOT EOT
;; ;;