Skip to content

Commit d6411d9

Browse files
authored
Merge branch 'main' into isogram
2 parents 67f9480 + 15fe19e commit d6411d9

File tree

321 files changed

+1818
-910
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

321 files changed

+1818
-910
lines changed

.github/workflows/test.yml

+7-7
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@ jobs:
1414
runs-on: ubuntu-22.04
1515
steps:
1616
- name: Checkout
17-
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
17+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
1818
with:
1919
path: main
20-
20+
2121
- name: Checkout test runner
22-
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
22+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
2323
with:
2424
repository: exercism/clojure-test-runner
2525
path: clojure-test-runner
2626

2727
- name: setup babashka
28-
uses: turtlequeue/setup-babashka@2d4df498c7a578b4f3e906283f9af913590bdec7
28+
uses: turtlequeue/setup-babashka@fda33428c8b62fb5bb9802ca7a2c750a6cc11b5a
2929
with:
3030
babashka-version: 0.8.1
31-
31+
3232
- name: babashka script
3333
id: bb_script
3434
run: bb main/test.clj
35-
35+
3636
# Print the output of the babashka script from the
37-
# `bb_script` step
37+
# `bb_script` step
3838
- name: Get the script output
3939
run: echo "${{ steps.bb_script.outputs.bb_out }}"

_generators/list-ops-generator.clj

+19-29
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
(second
1818
(str/split (:metadata data) #"="))
1919

20-
(defn get-meta
20+
(defn get-meta
2121
"Returns a vector containing the exercise title and blurb"
2222
[data]
2323
(mapv last
24-
(map #(map str/trim (str/split % #"="))
25-
(str/split-lines (:metadata data)))))
24+
(map #(map str/trim (str/split % #"="))
25+
(str/split-lines (:metadata data)))))
2626

2727
(defn init-deps! [data]
2828
(fs/create-dirs (fs/path "exercises" "practice"
@@ -38,8 +38,7 @@
3838
:exec-fn cognitect.test-runner.api/test}}}"))
3939

4040
(comment
41-
(init-deps! data)
42-
)
41+
(init-deps! data))
4342

4443
(defn init-lein! [data]
4544
(let [slug (:exercise (:canonical-data data))]
@@ -52,8 +51,7 @@
5251
"))))
5352

5453
(comment
55-
(init-lein! data)
56-
)
54+
(init-lein! data))
5755

5856
(defn test-ns-form [data]
5957
(str "(ns " (:exercise data) "-test
@@ -67,14 +65,13 @@
6765
(let [[args body] (str/split s #"->")
6866
arg-strs (mapv str (edn/read-string args))
6967
[arg1 op arg2] (str/split (str/trim body) #"\s")]
70-
(str "(fn [" (apply str (interpose " " arg-strs)) "] "
68+
(str "(fn [" (apply str (interpose " " arg-strs)) "] "
7169
"(" op " " arg1 " " arg2 "))")))
7270

7371
(comment
74-
(trans-fn "(x) -> x + 1")
72+
(trans-fn "(x) -> x + 1")
7573
(trans-fn "(x, y) -> x * y")
76-
(trans-fn "(acc, el) -> el * acc")
77-
)
74+
(trans-fn "(acc, el) -> el * acc"))
7875

7976
(defn testing-form [slug test-case]
8077
(let [property (symbol (str slug "/" (:property test-case)))
@@ -85,8 +82,7 @@
8582
(reverse (into (list property) args)) ")))")))
8683

8784
(comment
88-
(testing-form "list-ops" (first (:cases (first (:cases (:canonical-data data))))))
89-
)
85+
(testing-form "list-ops" (first (:cases (first (:cases (:canonical-data data)))))))
9086

9187
(defn testing-forms
9288
"Outputs a sequence of the test cases for a given property name
@@ -98,8 +94,7 @@
9894
(map #(testing-form (:exercise (:canonical-data data)) %) test-cases)))
9995

10096
(comment
101-
(testing-forms "append" data)
102-
)
97+
(testing-forms "append" data))
10398

10499
(defn deftest-forms [data]
105100
(for [property (distinct (map :property (mapcat :cases
@@ -110,8 +105,7 @@
110105
")")))
111106

112107
(comment
113-
(deftest-forms data)
114-
)
108+
(deftest-forms data))
115109

116110
(defn init-tests! [data]
117111
(let [path (fs/path "exercises" "practice"
@@ -127,8 +121,7 @@
127121
(deftest-forms data)))))))
128122

129123
(comment
130-
(init-tests! data)
131-
)
124+
(init-tests! data))
132125

133126
(defn init-src! [data]
134127
(spit (str (fs/file "exercises" "practice" (:exercise (:canonical-data data)) "src"
@@ -141,8 +134,7 @@
141134
(str "(defn " property " []\n )")))))))
142135

143136
(comment
144-
(init-src! data)
145-
)
137+
(init-src! data))
146138

147139
(defn init-description! [data]
148140
(let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".docs"]]
@@ -152,26 +144,24 @@
152144
(:description data)))))
153145

154146
(comment
155-
(init-description! data)
156-
)
147+
(init-description! data))
157148

158149
(defn config [data author blurb]
159150
(let [slug (:exercise (:canonical-data data))]
160151
{:authors [author],
161152
:contributors [],
162-
:files {:solution [(str "src/" (str/replace slug "-" "_") ".clj")],
163-
:test [(str "test/" (str/replace slug "-" "_") "_test.clj")],
164-
:example [".meta/src/example.clj"]},
153+
:files {:solution [(str "src/" (str/replace slug "-" "_") ".clj")],
154+
:test [(str "test/" (str/replace slug "-" "_") "_test.clj")],
155+
:example [".meta/example.clj"]},
165156
:blurb blurb}))
166157

167158
(defn init-config! [data]
168159
(let [path ["exercises" "practice" (:exercise (:canonical-data data)) ".meta"]]
169160
(when-not (fs/directory? (apply fs/path path))
170-
(fs/create-dirs (apply fs/path (conj path "src")))
161+
(fs/create-dirs (apply fs/path (conj path "src")))
171162
(spit (str (apply fs/file (conj path "config.json")))
172163
(json/generate-string (config data "porkostomus" (last (get-meta data)))
173164
{:pretty true})))))
174165

175166
(comment
176-
(init-config! data)
177-
)
167+
(init-config! data))

_generators/zipper-generator.clj

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
(:exercise (:canonical-data data)) "project.clj"))
4343
(str "(defproject " slug " \"0.1.0-SNAPSHOT\"
4444
:description \"" slug " exercise.\"
45-
:url \"https://github.com/exercism/clojure/tree/master/exercises/" slug "\"
45+
:url \"https://github.com/exercism/clojure/tree/main/exercises/practice/" slug "\"
4646
:dependencies [[org.clojure/clojure \"1.10.0\"]])
4747
"))))
4848

@@ -124,7 +124,7 @@
124124
:contributors [],
125125
:files {:solution [(str "src/" (str/replace slug "-" "_") ".clj")],
126126
:test [(str "test/" (str/replace slug "-" "_") "_test.clj")],
127-
:example [".meta/src/example.clj"]},
127+
:example [".meta/example.clj"]},
128128
:blurb blurb}))
129129

130130
(defn init-config! [data]

_test/check_exercises.clj

-15
This file was deleted.

bin/add-practice-exercise

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#!/usr/bin/env bash
2+
3+
# Synopsis:
4+
# Scaffold the files for a new practice exercise.
5+
# After creating the exercise, follow the instructions in the output.
6+
7+
# Example:
8+
# bin/add-practice-exercise two-fer
9+
10+
# Example with difficulty:
11+
# bin/add-practice-exercise -d 5 two-fer
12+
13+
# Example with author and difficulty:
14+
# bin/add-practice-exercise -a foo -d 3 two-fer
15+
16+
set -euo pipefail
17+
scriptname=$0
18+
19+
help_and_exit() {
20+
echo >&2 "Scaffold the files for a new practice exercise."
21+
echo >&2 "Usage: ${scriptname} [-h] [-a author] [-d difficulty] <exercise-slug>"
22+
echo >&2 "Where: author is the GitHub username of the exercise creator."
23+
echo >&2 "Where: difficulty is between 1 (easiest) to 10 (hardest)."
24+
exit 1
25+
}
26+
27+
die() { echo >&2 "$*"; exit 1; }
28+
29+
required_tool() {
30+
command -v "${1}" >/dev/null 2>&1 ||
31+
die "${1} is required but not installed. Please install it and make sure it's in your PATH."
32+
}
33+
34+
require_files_template() {
35+
jq -e --arg key "${1}" '.files[$key] | length > 0' config.json > /dev/null ||
36+
die "The '.files.${1}' array in the 'config.json' file is empty. Please add at least one file. See https://exercism.org/docs/building/tracks/config-json#h-files for more information."
37+
}
38+
39+
required_tool jq
40+
41+
require_files_template "solution"
42+
require_files_template "test"
43+
require_files_template "example"
44+
45+
[[ -f ./bin/fetch-configlet ]] || die "Run this script from the repo's root directory."
46+
47+
author=''
48+
difficulty='1'
49+
while getopts :ha:d: opt; do
50+
case $opt in
51+
h) help_and_exit ;;
52+
a) author=$OPTARG ;;
53+
d) difficulty=$OPTARG ;;
54+
?) echo >&2 "Unknown option: -$OPTARG"; help_and_exit ;;
55+
esac
56+
done
57+
shift "$((OPTIND - 1))"
58+
59+
(( $# >= 1 )) || help_and_exit
60+
61+
slug="${1}"
62+
63+
if [[ -z "${author}" ]]; then
64+
read -rp 'Your GitHub username: ' author
65+
fi
66+
67+
./bin/fetch-configlet
68+
./bin/configlet create --practice-exercise "${slug}" --author "${author}" --difficulty "${difficulty}"
69+
70+
exercise_dir="exercises/practice/${slug}"
71+
config_json_file="${exercise_dir}/.meta/config.json"
72+
files=$(jq -r --arg dir "${exercise_dir}" '.files | to_entries | map({key: .key, value: (.value | map("'"'"'" + $dir + "/" + . + "'"'"'") | join(" and "))}) | from_entries' "${config_json_file}")
73+
74+
sample_exercise_dir="exercises/practice/acronym"
75+
for sample_file in deps.edn project.clj; do
76+
if [[ ! -f "${sample_exercise_dir}/${sample_file}" ]]; then
77+
die "The sample exercise directory is missing the '${sample_file}' file."
78+
fi
79+
80+
cp "${sample_exercise_dir}/${sample_file}" "${exercise_dir}/${sample_file}"
81+
done
82+
83+
sed -i "s/acronym/${slug}/g" "${exercise_dir}/project.clj"
84+
85+
test_file=$(jq -r '.files.test[0]' "${config_json_file}")
86+
cat >"${exercise_dir}/${test_file}" << TEST_FILE
87+
(ns ${slug}-test
88+
(:require [clojure.test :refer [deftest testing is]]
89+
${slug}))
90+
TEST_FILE
91+
92+
for file_type in solution example; do
93+
solution_file=$(jq -r --arg file_type "${file_type}" '.files[$file_type][0]' "${config_json_file}")
94+
cat >"${exercise_dir}/${solution_file}" << FILE
95+
(ns ${slug})
96+
FILE
97+
done
98+
99+
cat << NEXT_STEPS
100+
Your next steps are:
101+
- Create the test suite in $(jq -r '.test' <<< "${files}")
102+
- The tests should be based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json'
103+
- Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false"
104+
- Create the example solution in $(jq -r '.example' <<< "${files}")
105+
- Verify the example solution passes the tests by running 'bin/verify-exercises ${slug}'
106+
- Create the stub solution in $(jq -r '.solution' <<< "${files}")
107+
- Update the 'difficulty' value for the exercise's entry in the 'config.json' file in the repo's root
108+
- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt'
109+
NEXT_STEPS

bin/restructure.clj

-13
This file was deleted.

bin/verify-exercises

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
3+
# Synopsis:
4+
# Verify that each exercise's example/exemplar solution passes the tests.
5+
# You can either verify all exercises or a single exercise.
6+
7+
# Example: verify all exercises
8+
# bin/verify-exercises
9+
10+
# Example: verify single exercise
11+
# bin/verify-exercises two-fer
12+
13+
set -eo pipefail
14+
15+
die() { echo "$*" >&2; exit 1; }
16+
17+
required_tool() {
18+
command -v "${1}" >/dev/null 2>&1 ||
19+
die "${1} is required but not installed. Please install it and make sure it's in your PATH."
20+
}
21+
22+
required_tool bb
23+
24+
bb test.clj "$@"

0 commit comments

Comments
 (0)