diff --git a/config.json b/config.json
index 38b9a735..5e5ef8d4 100644
--- a/config.json
+++ b/config.json
@@ -735,6 +735,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 1
+ },
+ {
+ "slug": "proverb",
+ "name": "Proverb",
+ "uuid": "ef243fad-2ac8-4313-a484-1c28a6d7ab21",
+ "practices": [],
+ "prerequisites": [],
+ "difficulty": 1
}
]
},
diff --git a/exercises/practice/proverb/.docs/instructions.md b/exercises/practice/proverb/.docs/instructions.md
new file mode 100644
index 00000000..f6fb8593
--- /dev/null
+++ b/exercises/practice/proverb/.docs/instructions.md
@@ -0,0 +1,19 @@
+# Instructions
+
+For want of a horseshoe nail, a kingdom was lost, or so the saying goes.
+
+Given a list of inputs, generate the relevant proverb.
+For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme:
+
+```text
+For want of a nail the shoe was lost.
+For want of a shoe the horse was lost.
+For want of a horse the rider was lost.
+For want of a rider the message was lost.
+For want of a message the battle was lost.
+For want of a battle the kingdom was lost.
+And all for the want of a nail.
+```
+
+Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content.
+No line of the output text should be a static, unchanging string; all should vary according to the input given.
diff --git a/exercises/practice/proverb/.meta/config.json b/exercises/practice/proverb/.meta/config.json
new file mode 100644
index 00000000..962abc34
--- /dev/null
+++ b/exercises/practice/proverb/.meta/config.json
@@ -0,0 +1,19 @@
+{
+ "authors": [
+ "habere-et-dispertire"
+ ],
+ "files": {
+ "solution": [
+ "lib/Proverb.rakumod"
+ ],
+ "test": [
+ "t/proverb.rakutest"
+ ],
+ "example": [
+ ".meta/solutions/lib/Proverb.rakumod"
+ ]
+ },
+ "blurb": "For want of a horseshoe nail, a kingdom was lost, or so the saying goes. Output the full text of this proverbial rhyme.",
+ "source": "Wikipedia",
+ "source_url": "https://en.wikipedia.org/wiki/For_Want_of_a_Nail"
+}
diff --git a/exercises/practice/proverb/.meta/solutions/lib/Proverb.rakumod b/exercises/practice/proverb/.meta/solutions/lib/Proverb.rakumod
new file mode 100644
index 00000000..64d7cf72
--- /dev/null
+++ b/exercises/practice/proverb/.meta/solutions/lib/Proverb.rakumod
@@ -0,0 +1,13 @@
+unit module Proverb;
+
+multi recite ( $noun where $_ eq '' ) is export { }
+multi recite ( $noun where $_ ne '' ) {
+ "And all for the want of a $noun."
+}
+multi recite ( @nouns ) {
+ join "\n",
+ @nouns
+ .rotor(2=>-1)
+ .map( { "For want of a {.head} the {.tail} was lost." } ),
+ recite @nouns.head
+}
diff --git a/exercises/practice/proverb/.meta/solutions/t/proverb.rakutest b/exercises/practice/proverb/.meta/solutions/t/proverb.rakutest
new file mode 120000
index 00000000..7b98c3b9
--- /dev/null
+++ b/exercises/practice/proverb/.meta/solutions/t/proverb.rakutest
@@ -0,0 +1 @@
+../../../t/proverb.rakutest
\ No newline at end of file
diff --git a/exercises/practice/proverb/.meta/template-data.yaml b/exercises/practice/proverb/.meta/template-data.yaml
new file mode 100644
index 00000000..db54d937
--- /dev/null
+++ b/exercises/practice/proverb/.meta/template-data.yaml
@@ -0,0 +1,30 @@
+properties:
+ recite:
+ test: |-
+ sprintf(q :to 'END', %case.Array.raku, %case.join("\n").raku, %case.raku);
+ cmp-ok(
+ recite(%s),
+ "eq",
+ %s,
+ %s,
+ );
+ END
+
+
+unit: module
+example: |-
+ multi recite ( $noun where $_ eq '' ) is export { }
+ multi recite ( $noun where $_ ne '' ) {
+ "And all for the want of a $noun."
+ }
+ multi recite ( @nouns ) {
+ join "\n",
+ @nouns
+ .rotor(2=>-1)
+ .map( { "For want of a {.head} the {.tail} was lost." } ),
+ recite @nouns.head
+ }
+
+stub: |-
+ sub proverb (@nouns) is export {
+ }
diff --git a/exercises/practice/proverb/.meta/tests.toml b/exercises/practice/proverb/.meta/tests.toml
new file mode 100644
index 00000000..dc92a0c9
--- /dev/null
+++ b/exercises/practice/proverb/.meta/tests.toml
@@ -0,0 +1,28 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[e974b73e-7851-484f-8d6d-92e07fe742fc]
+description = "zero pieces"
+
+[2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4]
+description = "one piece"
+
+[d9d0a8a1-d933-46e2-aa94-eecf679f4b0e]
+description = "two pieces"
+
+[c95ef757-5e94-4f0d-a6cb-d2083f5e5a83]
+description = "three pieces"
+
+[433fb91c-35a2-4d41-aeab-4de1e82b2126]
+description = "full proverb"
+
+[c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7]
+description = "four pieces modernized"
diff --git a/exercises/practice/proverb/lib/Proverb.rakumod b/exercises/practice/proverb/lib/Proverb.rakumod
new file mode 100644
index 00000000..61202808
--- /dev/null
+++ b/exercises/practice/proverb/lib/Proverb.rakumod
@@ -0,0 +1,4 @@
+unit module Proverb;
+
+sub proverb (@nouns) is export {
+}
diff --git a/exercises/practice/proverb/t/proverb.rakutest b/exercises/practice/proverb/t/proverb.rakutest
new file mode 100755
index 00000000..1bedca1a
--- /dev/null
+++ b/exercises/practice/proverb/t/proverb.rakutest
@@ -0,0 +1,48 @@
+#!/usr/bin/env raku
+use Test;
+use lib $?FILE.IO.parent(2).add('lib');
+use Proverb;
+
+cmp-ok( # begin: e974b73e-7851-484f-8d6d-92e07fe742fc
+ recite([]),
+ "eq",
+ "",
+ "zero pieces",
+); # end: e974b73e-7851-484f-8d6d-92e07fe742fc
+
+cmp-ok( # begin: 2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4
+ recite(["nail"]),
+ "eq",
+ "And all for the want of a nail.",
+ "one piece",
+); # end: 2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4
+
+cmp-ok( # begin: d9d0a8a1-d933-46e2-aa94-eecf679f4b0e
+ recite(["nail", "shoe"]),
+ "eq",
+ "For want of a nail the shoe was lost.\nAnd all for the want of a nail.",
+ "two pieces",
+); # end: d9d0a8a1-d933-46e2-aa94-eecf679f4b0e
+
+cmp-ok( # begin: c95ef757-5e94-4f0d-a6cb-d2083f5e5a83
+ recite(["nail", "shoe", "horse"]),
+ "eq",
+ "For want of a nail the shoe was lost.\nFor want of a shoe the horse was lost.\nAnd all for the want of a nail.",
+ "three pieces",
+); # end: c95ef757-5e94-4f0d-a6cb-d2083f5e5a83
+
+cmp-ok( # begin: 433fb91c-35a2-4d41-aeab-4de1e82b2126
+ recite(["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]),
+ "eq",
+ "For want of a nail the shoe was lost.\nFor want of a shoe the horse was lost.\nFor want of a horse the rider was lost.\nFor want of a rider the message was lost.\nFor want of a message the battle was lost.\nFor want of a battle the kingdom was lost.\nAnd all for the want of a nail.",
+ "full proverb",
+); # end: 433fb91c-35a2-4d41-aeab-4de1e82b2126
+
+cmp-ok( # begin: c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7
+ recite(["pin", "gun", "soldier", "battle"]),
+ "eq",
+ "For want of a pin the gun was lost.\nFor want of a gun the soldier was lost.\nFor want of a soldier the battle was lost.\nAnd all for the want of a pin.",
+ "four pieces modernized",
+); # end: c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7
+
+done-testing;