Skip to content

Commit 308db6c

Browse files
committed
Add new koans for control-flow
1 parent da0aa51 commit 308db6c

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

lib/koans/21_control_flow.ex

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
defmodule ControlFlow do
2+
@moduledoc false
3+
use Koans
4+
5+
@intro "Control Flow - Making decisions and choosing paths"
6+
7+
koan "If statements evaluate conditions" do
8+
result = if true, do: "yes", else: "no"
9+
assert result == ___
10+
end
11+
12+
koan "If can be written in block form" do
13+
result =
14+
if 1 + 1 == 2 do
15+
"math works"
16+
else
17+
"math is broken"
18+
end
19+
20+
assert result == ___
21+
end
22+
23+
koan "Unless is the opposite of if" do
24+
result = unless false, do: "will execute", else: "will not execute"
25+
assert result == ___
26+
end
27+
28+
koan "Nil and false are falsy, everything else is truthy" do
29+
assert if(nil, do: "truthy", else: "falsy") == ___
30+
assert if(false, do: "truthy", else: "falsy") == ___
31+
assert if(0, do: "truthy", else: "falsy") == ___
32+
assert if("", do: "truthy", else: "falsy") == ___
33+
assert if([], do: "truthy", else: "falsy") == ___
34+
end
35+
36+
koan "Case matches against patterns" do
37+
result =
38+
case {1, 2, 3} do
39+
{4, 5, 6} -> "no match"
40+
{1, x, 3} -> "matched with x = #{x}"
41+
end
42+
43+
assert result == ___
44+
end
45+
46+
koan "Case can have multiple clauses with different patterns" do
47+
check_number = fn x ->
48+
case x do
49+
0 -> "zero"
50+
n when n > 0 -> "positive"
51+
n when n < 0 -> "negative"
52+
end
53+
end
54+
55+
assert check_number.(5) == ___
56+
assert check_number.(0) == ___
57+
assert check_number.(-3) == ___
58+
end
59+
60+
koan "Case clauses are tried in order until one matches" do
61+
check_list = fn list ->
62+
case list do
63+
[] -> "empty"
64+
[_] -> "one element"
65+
[_, _] -> "two elements"
66+
_ -> "many elements"
67+
end
68+
end
69+
70+
assert check_list.([]) == ___
71+
assert check_list.([:a]) == ___
72+
assert check_list.([:a, :b]) == ___
73+
assert check_list.([:a, :b, :c, :d]) == ___
74+
end
75+
76+
koan "Cond evaluates conditions until one is truthy" do
77+
temperature = 25
78+
79+
weather =
80+
cond do
81+
temperature < 0 -> "freezing"
82+
temperature < 10 -> "cold"
83+
temperature < 25 -> "cool"
84+
temperature < 30 -> "warm"
85+
true -> "hot"
86+
end
87+
88+
assert weather == ___
89+
end
90+
91+
koan "Cond requires at least one clause to be true" do
92+
safe_divide = fn x, y ->
93+
cond do
94+
y == 0 -> {:error, "division by zero"}
95+
true -> {:ok, x / y}
96+
end
97+
end
98+
99+
assert safe_divide.(10, 2) == ___
100+
assert safe_divide.(10, 0) == ___
101+
end
102+
103+
koan "Case can destructure complex patterns" do
104+
parse_response = fn response ->
105+
case response do
106+
{:ok, %{status: 200, body: body}} -> "Success: #{body}"
107+
{:ok, %{status: status}} when status >= 400 -> "Client error: #{status}"
108+
{:ok, %{status: status}} when status >= 500 -> "Server error: #{status}"
109+
{:error, reason} -> "Request failed: #{reason}"
110+
end
111+
end
112+
113+
assert parse_response.({:ok, %{status: 200, body: "Hello"}}) == ___
114+
assert parse_response.({:ok, %{status: 404}}) == ___
115+
assert parse_response.({:error, :timeout}) == ___
116+
end
117+
118+
koan "Guards in case can use complex expressions" do
119+
categorize = fn number ->
120+
case number do
121+
n when is_integer(n) and n > 0 and rem(n, 2) == 0 -> "positive even integer"
122+
n when is_integer(n) and n > 0 and rem(n, 2) == 1 -> "positive odd integer"
123+
n when is_integer(n) and n < 0 -> "negative integer"
124+
n when is_float(n) -> "float"
125+
_ -> "other"
126+
end
127+
end
128+
129+
assert categorize.(4) == ___
130+
assert categorize.(3) == ___
131+
assert categorize.(-5) == ___
132+
assert categorize.(3.14) == ___
133+
assert categorize.("hello") == ___
134+
end
135+
136+
koan "Multiple conditions can be checked in sequence" do
137+
process_user = fn user ->
138+
if user.active do
139+
if user.verified do
140+
if user.premium do
141+
"premium verified active user"
142+
else
143+
"verified active user"
144+
end
145+
else
146+
"unverified active user"
147+
end
148+
else
149+
"inactive user"
150+
end
151+
end
152+
153+
user = %{active: true, verified: true, premium: false}
154+
assert process_user.(user) == ___
155+
end
156+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
defmodule ControlFlowTests do
2+
use ExUnit.Case
3+
import TestHarness
4+
5+
test "Control Flow" do
6+
answers = [
7+
"yes",
8+
"math works",
9+
"will execute",
10+
{:multiple, ["falsy", "falsy", "truthy", "truthy", "truthy"]},
11+
"matched with x = 2",
12+
{:multiple, ["positive", "zero", "negative"]},
13+
{:multiple, ["empty", "one element", "two elements", "many elements"]},
14+
"warm",
15+
{:multiple, [{:ok, 5}, {:error, "division by zero"}]},
16+
{:multiple, ["Success: Hello", "Client error: 404", "Request failed: timeout"]},
17+
{:multiple,
18+
["positive even integer", "positive odd integer", "negative integer", "float", "other"]},
19+
"verified active user"
20+
]
21+
22+
test_all(ControlFlow, answers)
23+
end
24+
end

0 commit comments

Comments
 (0)