Skip to content

Commit 6ee4d95

Browse files
authored
Scripts for creating an exercise (exercism#173)
* Scripts for creating an exercise, and validating one * the ci scripts takes a slug name to validate one exercise * review suggestions
1 parent e511583 commit 6ee4d95

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

bin/create-exercise

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
die() { echo "$*" >&2; exit 1; }
5+
6+
if [[ $PWD != $(realpath "$(dirname "$0")/..") ]]; then
7+
die "You must be in the track root directory."
8+
fi
9+
if [[ -z $1 ]]; then
10+
die "usage: $0 exercise_slug"
11+
fi
12+
13+
slug=$1
14+
15+
existing=$( jq --arg slug "${slug}" '.exercises.practice[] | select(.slug == $slug)' config.json )
16+
if [[ -n ${existing} ]]; then
17+
die "${slug} already exists in config.json"
18+
fi
19+
20+
pascal=${slug^}
21+
while [[ ${pascal} =~ (.*)-(.*) ]]; do
22+
pascal=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}
23+
done
24+
25+
bin/fetch-configlet
26+
bin/configlet create --practice-exercise "${slug}"
27+
28+
shDir=./exercises/shared/new-exercise-templates
29+
exDir=./exercises/practice/${slug}
30+
31+
############################################################
32+
cat <<'__LICENSE__' > "${exDir}/LICENSE"
33+
MIT License
34+
35+
Copyright (c) 2024 Exercism
36+
37+
Permission is hereby granted, free of charge, to any person obtaining a copy
38+
of this software and associated documentation files (the "Software"), to deal
39+
in the Software without restriction, including without limitation the rights
40+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41+
copies of the Software, and to permit persons to whom the Software is
42+
furnished to do so, subject to the following conditions:
43+
44+
The above copyright notice and this permission notice shall be included in all
45+
copies or substantial portions of the Software.
46+
47+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53+
SOFTWARE.
54+
__LICENSE__
55+
56+
############################################################
57+
sed -e "s/%{slug}/${slug}/g" <<'__PACKAGE_WREN__' > "${exDir}/package.wren"
58+
import "wren-package" for WrenPackage, Dependency
59+
import "os" for Process
60+
61+
class Package is WrenPackage {
62+
construct new() {}
63+
name { "exercism/%{slug}" }
64+
dependencies {
65+
return [
66+
Dependency.new("wren-testie", "0.3.0", "https://github.com/joshgoebel/wren-testie.git")
67+
]
68+
}
69+
}
70+
71+
Package.new().default()
72+
__PACKAGE_WREN__
73+
74+
############################################################
75+
sed -e "s/%{slug}/${slug}/g" \
76+
-e "s/%{PascalSlug}/${pascal}/g" <<'__STUB_WREN__' > "${exDir}/${slug}.wren"
77+
class %{PascalSlug} {
78+
construct new() {
79+
Fiber.abort("Remove this statement and implement this function")
80+
}
81+
}
82+
__STUB_WREN__
83+
84+
############################################################
85+
sed -e "s/%{slug}/${slug}/g" \
86+
-e "s/%{PascalSlug}/${pascal}/g" <<'__SPEC_WREN__' > "${exDir}/${slug}.spec.wren"
87+
import "./%{slug}" for %{PascalSlug}
88+
import "wren-testie/testie" for Testie, Expect
89+
90+
Testie.test("%{PascalSlug}") { |do, skip|
91+
do.test("first test") {
92+
// "someFunction" can be a static method on %{PascalSlug}
93+
// or create an instance and use an instance method.
94+
var actual = someFunction(inputData)
95+
var expected = "some value"
96+
Expect.value(actual).toEqual(expected)
97+
}
98+
99+
skip.test("subsequent tests are skipped") {
100+
var actual = someFunction(otherInputData)
101+
var expected = "some other value"
102+
Expect.value(actual).toEqual(expected)
103+
}
104+
}
105+
__SPEC_WREN__
106+
107+
# throw the canonical data into the spec
108+
specDir=${XDG_CACHE_DIR:-${HOME}/.cache}/exercism/configlet/problem-specifications
109+
cat "${specDir}/exercises/${slug}/canonical-data.json" >> "${exDir}/${slug}.spec.wren"
110+
111+
############################################################
112+
sed -e "s/%{slug}/${slug}/g" \
113+
-e "s/%{PascalSlug}/${pascal}/g" <<'__PROOF_WREN__' > "${exDir}/.meta/proof.ci.wren"
114+
class %{PascalSlug} {
115+
// implement me!
116+
}
117+
__PROOF_WREN__
118+
119+
############################################################
120+
121+
read -p "What's your GitHub handle? "
122+
if [[ -n ${REPLY} ]]; then
123+
conf=${exDir}/.meta/config.json
124+
tmp=$(mktemp)
125+
jq --arg who "${REPLY}" '.authors += [$who]' "${conf}" > "${tmp}" \
126+
&& mv "${tmp}" "${conf}"
127+
fi
128+
129+
read -p "What's the (likely) difficult for ${slug}? "
130+
if [[ -n ${REPLY} && ${REPLY} == +([0-9]) ]]; then
131+
tmp=$(mktemp)
132+
jq --argjson diff "${REPLY}" --arg slug "${slug}" '
133+
.exercises.practice |= map(
134+
if (.slug == $slug)
135+
then .difficulty = $diff
136+
else .
137+
end
138+
)
139+
' config.json > "${tmp}" \
140+
&& mv "${tmp}" config.json
141+
fi

0 commit comments

Comments
 (0)