Skip to content

Commit 8bef437

Browse files
author
Edwin Wu
committed
Kotlin Koans Introduction
1 parent ce412e8 commit 8bef437

File tree

3 files changed

+286
-0
lines changed

3 files changed

+286
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ hs_err_pid*
2424
# Intellij
2525
*.iml
2626
.idea
27+
28+
# Generated files
29+
bin/
30+
gen/
31+
out/
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
package kotlins.koans.introduction
2+
3+
import org.junit.Assert
4+
import org.junit.Test
5+
import java.util.*
6+
7+
/**
8+
*
9+
*
10+
* @author Edwin.Wu
11+
* @version 2018/2/6 下午2:42
12+
* @since JDK1.8
13+
*/
14+
fun main(args: Array<String>) {
15+
16+
println(start())
17+
}
18+
19+
class Simple {
20+
21+
@Test
22+
fun testOk() {
23+
Assert.assertEquals("OK", start())
24+
}
25+
26+
@Test
27+
fun collection() {
28+
Assert.assertEquals("toJSON", "[1, 2, 3, 42, 555]", toJSON(listOf(1, 2, 3, 42, 555)))
29+
}
30+
31+
@Test
32+
fun testJoinToString() {
33+
Assert.assertEquals("joinOptions", "[yes, no, may be]", joinOptions(listOf("yes", "no", "may be")))
34+
}
35+
36+
@Test
37+
fun testDefaultAndNamedParams() {
38+
Assert.assertEquals(listOf("a42", "b1", "C42", "D2"), useFoo())
39+
}
40+
41+
@Test
42+
fun contains() {
43+
println(containsEven(listOf(1, 2, 3, 126, 555)))
44+
Assert.assertTrue("The result should be true if the collection contains an even number", containsEven(listOf(1, 2, 3, 126, 555)))
45+
}
46+
47+
@Test
48+
fun notContains() {
49+
println(containsEven(listOf(43, 33)))
50+
Assert.assertFalse("The result should be false if the collection doesn't contain an even number", containsEven(listOf(43, 33)))
51+
}
52+
53+
private fun testMatch(date: String) = Assert.assertTrue("The pattern should match $date", date.matches(getPattern().toRegex()))
54+
private fun testMismatch(date: String) = Assert.assertFalse("The pattern shouldn't match $date", date.matches(getPattern().toRegex()))
55+
56+
@Test
57+
fun match() {
58+
testMatch("11 MAR 1952")
59+
}
60+
61+
@Test
62+
fun match1() {
63+
testMatch("24 AUG 1957")
64+
}
65+
66+
@Test
67+
fun doNotMatch() {
68+
testMismatch("24 RRR 1957")
69+
}
70+
71+
@Test
72+
fun testListOfPeople() {
73+
Assert.assertEquals("[Person(name=Alice, age=29), Person(name=Bob, age=31)]", getPeople().toString())
74+
}
75+
76+
fun testSendMessageToClient(client: Client?,
77+
message: String?,
78+
expectedEmail: String? = null,
79+
shouldBeInvoked: Boolean = false) {
80+
var invoked = false
81+
val expectedMessage = message
82+
sendMessageToClient(client, message, object : Mailer {
83+
override fun sendMessage(email: String, message: String) {
84+
invoked = true
85+
Assert.assertEquals("The message is not as expected:", expectedMessage, message)
86+
Assert.assertEquals("The email is not as expected:", expectedEmail, email)
87+
}
88+
})
89+
Assert.assertEquals("The function 'sendMessage' should${if (shouldBeInvoked) "" else "n't"} be invoked", shouldBeInvoked, invoked)
90+
}
91+
92+
@Test
93+
fun everythingIsOk() {
94+
testSendMessageToClient(Client(PersonalInfo("bob@gmail.com")),
95+
"Hi Bob! We have an awesome proposition for you...",
96+
"bob@gmail.com",
97+
true)
98+
}
99+
100+
@Test
101+
fun noMessage() {
102+
testSendMessageToClient(Client(PersonalInfo("bob@gmail.com")), null)
103+
}
104+
105+
@Test
106+
fun testNum() {
107+
Assert.assertEquals("'eval' on Num should work:", 2, eval(Num(2)))
108+
}
109+
110+
@Test
111+
fun testSum() {
112+
Assert.assertEquals("'eval' on Sum should work:", 3, eval(Sum(Num(2), Num(1))))
113+
}
114+
115+
@Test
116+
fun testRecursion() {
117+
Assert.assertEquals("'eval' should work:", 6, eval(Sum(Sum(Num(1), Num(2)), Num(3))))
118+
}
119+
120+
@Test
121+
fun testIntExtension() {
122+
Assert.assertEquals("Rational number creation error: ", RationalNumber(4, 1), 4.r())
123+
}
124+
125+
@Test
126+
fun testPairExtension() {
127+
Assert.assertEquals("Rational number creation error: ", RationalNumber(2, 3), Pair(2, 3).r())
128+
}
129+
130+
@Test
131+
fun testSort() {
132+
Assert.assertEquals("getList", listOf(5, 2, 1), getList())
133+
Assert.assertEquals("getList", listOf(5, 2, 1), getList2())
134+
Assert.assertEquals("getList", listOf(5, 2, 1), getList3())
135+
136+
println( arrayListOf(5, 1, 2).sortedDescending())
137+
println( arrayListOf(5, 1, 2).sorted())
138+
}
139+
}
140+
141+
/**
142+
* Hello, world!
143+
*/
144+
fun start(): String = "OK"
145+
146+
/**
147+
* Java to Kotlin conversion
148+
*/
149+
fun toJSON(collection: Collection<Int>): String {
150+
val sb = StringBuilder()
151+
sb.append("[")
152+
val iterator = collection.iterator()
153+
while (iterator.hasNext()) {
154+
val element = iterator.next()
155+
sb.append(element)
156+
if (iterator.hasNext()) {
157+
sb.append(", ")
158+
}
159+
}
160+
sb.append("]")
161+
return sb.toString()
162+
}
163+
164+
/**
165+
* Named arguments
166+
*/
167+
fun joinOptions(options: Collection<String>) = options.joinToString(", ", "[", "]")
168+
169+
/**
170+
* Default arguments
171+
*/
172+
173+
fun foo(name: String, number: Int = 42, toUpperCase: Boolean = false) = (if (toUpperCase) name.toUpperCase() else name) + number
174+
175+
fun useFoo() = listOf(
176+
foo("a"),
177+
foo("b", number = 1),
178+
foo("c", toUpperCase = true),
179+
foo(name = "d", number = 2, toUpperCase = true)
180+
)
181+
182+
183+
/**
184+
* Lambdas
185+
*/
186+
fun containsEven(collection: Collection<Int>): Boolean = collection.any { it % 2 == 0 }
187+
188+
189+
val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"
190+
/**
191+
* Strings
192+
*/
193+
fun getPattern(): String = """\d{2} ${month} \d{4}"""
194+
195+
/**
196+
* Data classes
197+
*/
198+
class Person(val name: String, var age: Int) {
199+
200+
override fun toString(): String {
201+
return "Person(name=$name, age=$age)"
202+
}
203+
}
204+
205+
fun getPeople(): List<Person> {
206+
return listOf(
207+
Person("Alice", 29),
208+
Person("Bob", 31)
209+
)
210+
}
211+
212+
/**
213+
* Nullable types
214+
*/
215+
fun sendMessageToClient(client: Client?, message: String?, mailer: Mailer) {
216+
if (client == null || message == null)
217+
return
218+
219+
val personalInfo: PersonalInfo? = client.personalInfo ?: return
220+
val email: String = personalInfo?.email ?: return
221+
222+
mailer.sendMessage(email, message)
223+
}
224+
225+
class Client(val personalInfo: PersonalInfo?)
226+
class PersonalInfo(val email: String?)
227+
interface Mailer {
228+
fun sendMessage(email: String, message: String)
229+
}
230+
231+
/**
232+
* Smart casts
233+
*/
234+
fun eval(expr: Expr): Int =
235+
when (expr) {
236+
is Num -> expr.value
237+
is Sum -> eval(expr.left) + eval(expr.right)
238+
else -> throw IllegalArgumentException("Unknown expression")
239+
}
240+
241+
interface Expr
242+
class Num(val value: Int) : Expr
243+
class Sum(val left: Expr, val right: Expr) : Expr
244+
245+
/**
246+
* Extension functions
247+
*/
248+
fun Int.r(): RationalNumber = RationalNumber(this, 1)
249+
250+
fun Pair<Int, Int>.r(): RationalNumber = RationalNumber(first, second)
251+
252+
data class RationalNumber(val numerator: Int, val denominator: Int)
253+
254+
/**
255+
* Object expressions
256+
*/
257+
fun getList(): List<Int> {
258+
val arrayList = arrayListOf(1, 5, 2)
259+
260+
Collections.sort(arrayList, object : Comparator<Int> {
261+
override fun compare(x: Int, y: Int) = y - x
262+
})
263+
264+
return arrayList
265+
}
266+
267+
/**
268+
* SAM conversions
269+
*/
270+
fun getList2(): List<Int> {
271+
val arrayList = arrayListOf(1, 5, 2)
272+
Collections.sort(arrayList, { x, y -> -x + y })
273+
return arrayList
274+
}
275+
276+
/**
277+
* Extension functions on collections
278+
*/
279+
fun getList3(): List<Int> {
280+
return arrayListOf(1, 5, 2).sortedDescending()
281+
}
Binary file not shown.

0 commit comments

Comments
 (0)