Skip to content

Commit 73161a3

Browse files
authored
1.19 update (#98)
* Update Dockerfile to use Crystal 1.18.2 and enhance run.sh for parallel testing support * Update Dockerfile and changelog for Crystal 1.19.1 and add test for parallism
1 parent 9ad59ae commit 73161a3

8 files changed

Lines changed: 134 additions & 2 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM crystallang/crystal:1.15.1-alpine
1+
FROM crystallang/crystal:1.19.1-alpine
22

33
# install packages required to run the tests
44
RUN apk add --no-cache bash jq coreutils

bin/run.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ echo "${slug}: testing..."
4141

4242
# Run the tests for the provided implementation file and redirect stdout and
4343
# stderr to capture it
44+
45+
if [ "${slug}" = "parallel-letter-frequency" ]; then
46+
crystal spec "${modified_spec_file}" --junit_output="${output_dir}" --tag "~optional" -Dpreview_mt --no-color &> "${capture_file}"
47+
else
4448
crystal spec "${modified_spec_file}" --junit_output="${output_dir}" --tag "~optional" --no-color &> "${capture_file}"
49+
fi
4550

4651
./bin/test_runner "${spec_file}" "${capture_file}" "${junit_file}" "${results_file}"
4752

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 2.2.0
2+
3+
- Move to Crystal 1.19.1
4+
- Add support for parallel testing
5+
16
# 2.1.2
27

38
- Move to Crystal 1.15.1

helpers/setup_test_file.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ def fix_test_file(spec_input, spec_output)
33
spec_file = File.read(spec_input).split("\n")
44
index = spec_file.index {|x| x.includes?("describe")}
55
unless index.nil?
6-
spec_file = spec_file.insert(index + 1, "around_each do |example|\noriginal_stdout = File.open(\"/dev/null\")\noriginal_stdout.reopen(STDOUT)\nIO.pipe do |reader, writer|\nSTDOUT.reopen(writer)\nbegin\nexample.run\nensure\nwriter.close\nSTDOUT.reopen(original_stdout)\nend\nadd = File.exists?(\"/tmp/output.json\") ? JSON.parse(File.read(\"/tmp/output.json\")).to_s[1..-2] + \", \" : \"\"\nFile.write(\"/tmp/output.json\", JSON.parse(\"[\" + add + \"\#{reader.gets_to_end.split(\"\n\")[..-2].join(\"\n\").inspect}]\"))\nend\nend\n")
6+
spec_file = spec_file.insert(index + 1, "around_each do |example|\noriginal_stdout = File.open(\"/dev/null\")\noriginal_stdout.reopen(STDOUT)\nIO.pipe do |reader, writer|\nSTDOUT.reopen(writer)\nbegin\nexample.run\nensure\nwriter.close\nSTDOUT.reopen(original_stdout)\nend\nadd = File.exists?(\"/tmp/output.json\") ? File.read(\"/tmp/output.json\").to_s[1..-2] + \", \" : \"\"\nFile.write(\"/tmp/output.json\", \"[\" + add + \"\#{reader.gets_to_end.split(\"\n\")[..-2].join(\"\n\").inspect}]\")\nend\nend\n")
77
end
88
unless spec_output.nil?
99
File.write(spec_output, "require \"json\"\n" + spec_file.join("\n").gsub("pending", "it"))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"files": {
3+
"solution": [
4+
"src/parallel_letter_frequency.cr"
5+
],
6+
"test": [
7+
"spec/parallel_letter_frequency_spec.cr"
8+
]
9+
},
10+
"blurb": "Create a sentence of the form \"One for X, one for me.\".",
11+
"source_url": "https://github.com/exercism/problem-specifications/issues/757"
12+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"version": 3,
3+
"status": "pass",
4+
"tests": [
5+
{
6+
"name": "ParallelLetterFrequency no texts",
7+
"status": "pass",
8+
"test_code": "input = [] of String\nexpected = {} of String => Int32\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
9+
},
10+
{
11+
"name": "ParallelLetterFrequency one text with one letter",
12+
"status": "pass",
13+
"test_code": "input = [\"a\"]\nexpected = {\"a\" => 1}\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
14+
},
15+
{
16+
"name": "ParallelLetterFrequency one text with multiple letters",
17+
"status": "pass",
18+
"test_code": "input = [\"bbcccd\"]\nexpected = {\"b\" => 2, \"c\" => 3, \"d\" => 1}\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
19+
},
20+
{
21+
"name": "ParallelLetterFrequency two texts with one letter",
22+
"status": "pass",
23+
"test_code": "input = [\"e\", \"f\"]\nexpected = {\"e\" => 1, \"f\" => 1}\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
24+
},
25+
{
26+
"name": "ParallelLetterFrequency two texts with multiple letters",
27+
"status": "pass",
28+
"test_code": "input = [\"ggh\", \"hhi\"]\nexpected = {\"g\" => 2, \"h\" => 3, \"i\" => 1}\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
29+
},
30+
{
31+
"name": "ParallelLetterFrequency ignore letter casing",
32+
"status": "pass",
33+
"test_code": "input = [\"m\", \"M\"]\nexpected = {\"m\" => 2}\nParallelLetterFrequency.calculate_frequencies(input).should eq(expected)"
34+
}
35+
]
36+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
require "spec"
2+
require "../src/*"
3+
4+
describe "ParallelLetterFrequency" do
5+
it "no texts" do
6+
input = [] of String
7+
expected = {} of String => Int32
8+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
9+
end
10+
11+
pending "one text with one letter" do
12+
input = ["a"]
13+
expected = {"a" => 1}
14+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
15+
end
16+
17+
pending "one text with multiple letters" do
18+
input = ["bbcccd"]
19+
expected = {"b" => 2, "c" => 3, "d" => 1}
20+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
21+
end
22+
23+
pending "two texts with one letter" do
24+
input = ["e", "f"]
25+
expected = {"e" => 1, "f" => 1}
26+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
27+
end
28+
29+
pending "two texts with multiple letters" do
30+
input = ["ggh", "hhi"]
31+
expected = {"g" => 2, "h" => 3, "i" => 1}
32+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
33+
end
34+
35+
pending "ignore letter casing" do
36+
input = ["m", "M"]
37+
expected = {"m" => 2}
38+
ParallelLetterFrequency.calculate_frequencies(input).should eq(expected)
39+
end
40+
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
require "sync/shared"
2+
3+
class ParallelLetterFrequency
4+
def self.calculate_frequencies(input : Array(String)) : Hash(String, Int32)
5+
data : Sync::Shared(Hash(String, Int32)) = Sync::Shared.new({} of String => Int32)
6+
channel = Channel(Nil).new
7+
input.each do |text|
8+
spawn do
9+
local = Hash(String, Int32).new(0)
10+
11+
text.each_char do |char|
12+
next unless char.letter?
13+
local[char.downcase.to_s] += 1
14+
end
15+
16+
data.replace do |shared_data|
17+
local.each do |char, count|
18+
shared_data[char] ||= 0
19+
shared_data[char] += count
20+
end
21+
shared_data
22+
end
23+
channel.send(nil) # signal completion
24+
end
25+
end
26+
27+
input.size.times do
28+
channel.receive
29+
end
30+
31+
32+
data.get()
33+
end
34+
end

0 commit comments

Comments
 (0)