trackler 2.0.6.34 → 2.0.6.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/change/canonical-data.json +6 -0
  3. data/common/exercises/luhn/canonical-data.json +35 -0
  4. data/common/exercises/rotational-cipher/cannonical-data.json +70 -0
  5. data/common/exercises/rotational-cipher/description.md +30 -0
  6. data/common/exercises/rotational-cipher/metadata.yml +4 -0
  7. data/common/exercises/run-length-encoding/description.md +7 -1
  8. data/lib/trackler/version.rb +1 -1
  9. data/tracks/elixir/exercises/run-length-encoding/example.exs +15 -4
  10. data/tracks/elixir/exercises/run-length-encoding/rle.exs +2 -2
  11. data/tracks/elixir/exercises/run-length-encoding/rle_test.exs +28 -11
  12. data/tracks/go/exercises/bob/bob_test.go +4 -1
  13. data/tracks/go/exercises/bracket-push/bracket_push_test.go +5 -2
  14. data/tracks/go/exercises/circular-buffer/circular_buffer_test.go +6 -6
  15. data/tracks/go/exercises/clock/clock_test.go +4 -1
  16. data/tracks/go/exercises/connect/connect_test.go +4 -1
  17. data/tracks/go/exercises/crypto-square/crypto_square_test.go +5 -2
  18. data/tracks/go/exercises/luhn/luhn_test.go +1 -1
  19. data/tracks/javascript/exercises/leap/leap.js +1 -1
  20. data/tracks/julia/.travis.yml +0 -2
  21. data/tracks/julia/config.json +41 -0
  22. data/tracks/julia/exercises/custom-set/HINTS.md +1 -0
  23. data/tracks/julia/exercises/custom-set/custom-set.jl +0 -0
  24. data/tracks/julia/exercises/custom-set/example.jl +51 -0
  25. data/tracks/julia/exercises/custom-set/runtests.jl +200 -0
  26. data/tracks/julia/exercises/isogram/example.jl +11 -0
  27. data/tracks/julia/exercises/isogram/isogram.jl +3 -0
  28. data/tracks/julia/exercises/isogram/runtests.jl +35 -0
  29. data/tracks/julia/exercises/luhn/example.jl +16 -0
  30. data/tracks/julia/exercises/luhn/luhn.jl +0 -0
  31. data/tracks/julia/exercises/luhn/runtests.jl +31 -0
  32. data/tracks/julia/exercises/nucleotide-count/example.jl +8 -0
  33. data/tracks/julia/exercises/nucleotide-count/nucleotide-count.jl +3 -0
  34. data/tracks/julia/exercises/nucleotide-count/runtests.jl +19 -0
  35. data/tracks/kotlin/.travis.yml +9 -1
  36. data/tracks/kotlin/README.md +117 -11
  37. data/tracks/kotlin/bin/journey-test.sh +279 -0
  38. data/tracks/kotlin/docs/INSTALLATION.md +193 -97
  39. data/tracks/kotlin/docs/TESTS.md +72 -137
  40. data/tracks/kotlin/exercises/hello-world/GETTING_STARTED.md +50 -0
  41. data/tracks/kotlin/exercises/hello-world/TUTORIAL.md +693 -0
  42. data/tracks/kotlin/exercises/hello-world/src/example/kotlin/HelloWorld.kt +2 -30
  43. data/tracks/kotlin/exercises/hello-world/src/main/kotlin/HelloWorld.kt +2 -30
  44. data/tracks/kotlin/exercises/hello-world/src/test/kotlin/HelloWorldTest.kt +11 -19
  45. data/tracks/objective-c/circle.yml +1 -1
  46. data/tracks/perl6/exercises/atbash-cipher/{cipher.t → atbash-cipher.t} +0 -0
  47. data/tracks/perl6/exercises/linked-list/linked-list.t +0 -0
  48. data/tracks/perl6/exercises/phone-number/{phone.t → phone-number.t} +0 -0
  49. data/tracks/perl6/exercises/rna-transcription/{rna_transcription.t → rna-transcription.t} +0 -0
  50. data/tracks/perl6/exercises/robot-name/{robot.t → robot-name.t} +0 -0
  51. data/tracks/perl6/exercises/scrabble-score/{scrabble_score.t → scrabble-score.t} +0 -0
  52. data/tracks/perl6/exercises/word-count/{word_count.t → word-count.t} +0 -0
  53. data/tracks/pony/config.json +9 -0
  54. data/tracks/pony/exercises/pascals-triangle/example.pony +18 -0
  55. data/tracks/pony/exercises/pascals-triangle/test.pony +31 -0
  56. data/tracks/r/config.json +20 -0
  57. data/tracks/r/exercises/grains/example.R +16 -0
  58. data/tracks/r/exercises/grains/grains.R +7 -0
  59. data/tracks/r/exercises/grains/test_grains.R +49 -0
  60. data/tracks/r/exercises/phone-number/example.R +30 -0
  61. data/tracks/r/exercises/phone-number/phone-number.R +3 -0
  62. data/tracks/r/exercises/phone-number/test_phone-number.R +44 -0
  63. data/tracks/r/exercises/secret-handshake/example.R +26 -0
  64. data/tracks/r/exercises/secret-handshake/secret-handshake.R +3 -0
  65. data/tracks/r/exercises/secret-handshake/test_secret-handshake.R +52 -0
  66. data/tracks/r/exercises/sieve/example.R +16 -0
  67. data/tracks/r/exercises/sieve/sieve.R +3 -0
  68. data/tracks/r/exercises/sieve/test_sieve.R +37 -0
  69. data/tracks/rust/config.json +11 -0
  70. data/tracks/rust/exercises/rotational-cipher/Cargo.lock +4 -0
  71. data/tracks/rust/exercises/rotational-cipher/Cargo.toml +4 -0
  72. data/tracks/rust/exercises/rotational-cipher/example.rs +16 -0
  73. data/tracks/rust/exercises/rotational-cipher/tests/rotational-cipher.rs +61 -0
  74. data/tracks/swift/circle.yml +6 -0
  75. metadata +46 -8
@@ -0,0 +1,50 @@
1
+ ----
2
+ # Quick Start Guide
3
+
4
+ This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests)
5
+ left off. If you haven't reviewed those instructions, do so now.
6
+
7
+ Need more information? A **step-by-step tutorial** is available in this directory at TUTORIAL.md or you can read
8
+ the [HTML version](https://github.com/exercism/xkotlin/blob/master/exercises/hello-world/TUTORIAL.md).
9
+
10
+ The following instructions work equally well on Windows, Mac OS X and Linux.
11
+
12
+ ## Solve "Hello World"
13
+
14
+ Try writing a solution that passes one test at a time, running Gradle each time:
15
+
16
+
17
+ ```
18
+ $ gradle test
19
+ ```
20
+
21
+ ## Iterate through the tests
22
+
23
+ After your first test passes, remove the `@Ignore` from the next test, and iterate on your solution,
24
+ testing after each change.
25
+
26
+ ## All the tests pass? Submit your solution!
27
+
28
+ With a working solution that we've reviewed, we're ready to submit it to
29
+ exercism.io.
30
+
31
+ ```
32
+ $ exercism submit src/main/kotlin/HelloWorld.kt
33
+ ```
34
+
35
+ ## Next Steps
36
+
37
+ From here, there are a number of paths you can take.
38
+
39
+ 1. Move on to the next exercise
40
+ 2. Review (and comment on) others' submissions to this exercise
41
+ 3. Submit another iteration
42
+ 4. Contribute to Exercism
43
+
44
+
45
+ We sincerely hope you learn and enjoy being part of this community. If at any time you need assistance
46
+ do not hesitate to ask for help:
47
+
48
+ http://exercism.io/languages/kotlin/help
49
+
50
+ Cheers!
@@ -0,0 +1,693 @@
1
+ NOTE: You can also view the HTML version of this file here:
2
+ https://github.com/exercism/xkotlin/blob/master/exercises/hello-world/TUTORIAL.md
3
+
4
+ * [Solving "Hello, World!"](#solving-hello-world)
5
+ * [Reading Gradle output](#reading-gradle-output)
6
+ * [Fixing the first failing test](#fixing-the-first-failing-test)
7
+ * [Enabling and fixing the second test](#enabling-and-fixing-the-second-test)
8
+ * [Enabling and fixing the third test](#enabling-and-fixing-the-third-test)
9
+ * [Enabling the last test](#enabling-the-last-test)
10
+ * [Refactoring](#refactoring)
11
+ * [Submitting your first iteration](#submitting-your-first-iteration)
12
+ * [Next Steps](#next-steps)
13
+ * [Review (and comment on) others' submissions to this exercise](#review-and-comment-on-others-submissions-to-this-exercise)
14
+ * [Extend an exercise](#extend-an-exercise)
15
+ * [Contribute to Exercism](#contribute-to-exercism)
16
+
17
+ ----
18
+
19
+ # Solving "Hello, World!"
20
+
21
+ Welcome to the first exercise on the Kotlin track!
22
+
23
+ This is a step-by-step guide to solving this exercise.
24
+
25
+ Each exercise comes with a set of tests. The first pass through the
26
+ exercise is about getting all of the tests to pass, one at a time.
27
+
28
+ If you have not installed the Java Development Kit and Gradle, you must do
29
+ so now. For help with this, see: http://exercism.io/languages/kotlin/installing
30
+
31
+ ----
32
+
33
+ This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests)
34
+ left off. If you haven't reviewed those instructions, do so now.
35
+
36
+ The following instructions work equally well on Windows, Mac OS X and Linux.
37
+
38
+ ## Reading Gradle output
39
+
40
+ Use Gradle to run the tests:
41
+
42
+ ```
43
+ $ gradle test
44
+ ```
45
+
46
+ This command does a lot and displays a bunch of stuff. Let's break it down...
47
+
48
+ ```
49
+ :compileKotlin
50
+ w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used
51
+ :compileJava UP-TO-DATE
52
+ :copyMainKotlinClasses
53
+ :processResources UP-TO-DATE
54
+ :classes UP-TO-DATE
55
+ ```
56
+
57
+ Each line that begins with a colon (like `:compileKotlin`) is Gradle telling
58
+ us that it's starting that task. The first five tasks are about compiling
59
+ the source code of our *solution*. We've done you a favor and included just
60
+ enough code for the solution that it compiles.
61
+
62
+ When a task is successful, it generally does not output anything. This is
63
+ why `:copyMainKotlinClasses` does not produce any additional output.
64
+
65
+ A task may succeed but warn of a potential problem. This is what we see from
66
+ `:compileKotlin`. The Kotlin compiler tells us that on line 1, 11 characters in
67
+ of the `HelloWorld.kt` file, there is a parameter called `name` that was
68
+ declared but never used. Usually, warnings _are_ helpful and should be heeded.
69
+ We'll address this warning soon enough, but we're okay for now.
70
+
71
+ The next five tasks are about compiling source code of the *tests*.
72
+
73
+ ```
74
+ :compileTestKotlin
75
+ :compileTestJava UP-TO-DATE
76
+ :copyTestKotlinClasses
77
+ :processTestResources UP-TO-DATE
78
+ :testClasses UP-TO-DATE
79
+ ```
80
+
81
+ ... with both sets of source code successfully compiled, Gradle turns to
82
+ running the task you asked it to: executing the tests against the solution.
83
+
84
+ ```
85
+ :test
86
+
87
+ HelloWorldTest > helloSampleName SKIPPED
88
+
89
+ HelloWorldTest > helloBlankName SKIPPED
90
+
91
+ HelloWorldTest > helloNoName FAILED
92
+ org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
93
+ at org.junit.Assert.assertEquals(Assert.java:115)
94
+ at org.junit.Assert.assertEquals(Assert.java:144)
95
+ at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
96
+
97
+ HelloWorldTest > helloAnotherSampleName SKIPPED
98
+
99
+ 4 tests completed, 1 failed, 3 skipped
100
+ :test FAILED
101
+
102
+ FAILURE: Build failed with an exception.
103
+
104
+ * What went wrong:
105
+ Execution failed for task ':test'.
106
+ > There were failing tests. See the report at: file:///Users/jtigger/exercism/exercises/kotlin/hello-world/build/reports/tests/index.html
107
+
108
+ * Try:
109
+ Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
110
+
111
+ BUILD FAILED
112
+
113
+ Total time: 7.473 secs
114
+ ```
115
+
116
+ Seeing the word "fail" NINE TIMES might give you the impression you've done
117
+ something horribly wrong! You haven't. It's a whole lot of noise over
118
+ a single test not passing.
119
+
120
+ Let's focus in on the important bits:
121
+
122
+ ```
123
+ HelloWorldTest > helloNoName FAILED
124
+ org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
125
+ ```
126
+
127
+ ...is read: "Within the test class named `HelloWorldTest`, the test method
128
+ `helloNoName` did not pass because the solution did not satisfy an
129
+ assertion. Apparently, we expected to see the string 'Hello, World!' but
130
+ a blank string was returned instead.
131
+
132
+ The last line of the stack trace tells us exactly where this unsatisfied
133
+ assertion lives:
134
+
135
+ ```
136
+ at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
137
+ ```
138
+
139
+ Looks like the scene of the crime is on line 10 in the test file.
140
+
141
+ Knowing these two facts,
142
+
143
+ 1. the return value was not what was expected, and
144
+ 2. the failure was on line 10 of the test,
145
+
146
+ we can turn this failure into success.
147
+
148
+
149
+
150
+ ## Fixing the first failing test
151
+
152
+ In your favorite text editor, open `src/test/kotlin/HelloWorldTest.kt`
153
+ and go to line 10.
154
+
155
+ ```kotlin
156
+ assertEquals("Hello, World!", hello(""));
157
+ ```
158
+
159
+ The test is expecting that `hello()`, when given an empty string (`""`),
160
+ returns "Hello, World!". Instead, `hello()` is returning `""`.
161
+ Let's fix that.
162
+
163
+ Open `src/main/kotlin/HelloWorld.kt`.
164
+
165
+ ```kotlin
166
+ fun hello(name: String = ""): String {
167
+ return ""
168
+ }
169
+ ```
170
+
171
+ Let's change that to return the expected string:
172
+
173
+ ```kotlin
174
+ fun hello(name: String = ""): String {
175
+ return "Hello, World!"
176
+ }
177
+ ```
178
+
179
+ Save the file and run the tests again:
180
+
181
+ ```
182
+ $ gradle test
183
+ :compileKotlin
184
+ w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used
185
+ :compileJava UP-TO-DATE
186
+ :copyMainKotlinClasses
187
+ :processResources UP-TO-DATE
188
+ :classes UP-TO-DATE
189
+ :compileTestKotlin
190
+ :compileTestJava UP-TO-DATE
191
+ :copyTestKotlinClasses UP-TO-DATE
192
+ :processTestResources UP-TO-DATE
193
+ :testClasses UP-TO-DATE
194
+ :test
195
+
196
+ HelloWorldTest > helloSampleName SKIPPED
197
+
198
+ HelloWorldTest > helloBlankName SKIPPED
199
+
200
+ HelloWorldTest > helloNoName PASSED
201
+
202
+ HelloWorldTest > helloAnotherSampleName SKIPPED
203
+
204
+ BUILD SUCCESSFUL
205
+
206
+ Total time: 7.318 secs
207
+ ```
208
+
209
+ "BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloNoName()` test is
210
+ now passing.
211
+
212
+ We still see the warning about `name` not being used; we'll get to that
213
+ next.
214
+
215
+ With one win under our belt, we can turn our focus to some other messages
216
+ that we've been ignoring: the lines ending in "`SKIPPED`".
217
+
218
+ Each test suite contains a series of tests, all of which have been marked
219
+ to be skipped/ignored except the first one. We did this to help you focus
220
+ on getting one test running at a time.
221
+
222
+ Let's tackle the next test...
223
+
224
+
225
+
226
+ ## Enabling and fixing the second test
227
+
228
+ Right now, that second test is being skipped/ignored. Let's enable it.
229
+
230
+ (Re)open `src/test/kotlin/HelloWorldTest.kt` and find the second test:
231
+
232
+ ```kotlin
233
+ @Test
234
+ @Ignore
235
+ fun helloSampleName() {
236
+ assertEquals("Hello, Alice!", hello("Alice"))
237
+ }
238
+ ```
239
+
240
+ When the JUnit test runner sees that `@Ignore` annotation on the test
241
+ method, it knows to skip over that test. Remove that line:
242
+
243
+ ```kotlin
244
+ @Test
245
+ fun helloSampleName() {
246
+ assertEquals("Hello, Alice!", hello("Alice"))
247
+ }
248
+ ```
249
+
250
+ Now, when you run the tests, both tests run:
251
+
252
+ ```
253
+ $ gradle test
254
+ :test
255
+
256
+ HelloWorldTest > helloSampleName FAILED
257
+ org.junit.ComparisonFailure: expected:<Hello, [Alice]!> but was:<Hello, [World]!>
258
+ at org.junit.Assert.assertEquals(Assert.java:115)
259
+ at org.junit.Assert.assertEquals(Assert.java:144)
260
+ at HelloWorldTest.helloSampleName(HelloWorldTest.kt:15)
261
+
262
+ HelloWorldTest > helloBlankName SKIPPED
263
+
264
+ HelloWorldTest > helloNoName PASSED
265
+
266
+ HelloWorldTest > helloAnotherSampleName SKIPPED
267
+
268
+ 4 tests completed, 1 failed, 2 skipped
269
+ ```
270
+
271
+ The first test, `helloNoName()` continues to pass. We see that
272
+ `helloSampleName` -- the test we just un-`@Ignore`'d -- is now running and
273
+ failing. Yay, failing test! In fact, the "failure" message is just
274
+ describing the difference between what the program does now and what it
275
+ should do for us to call it "done."
276
+
277
+ Right now, we've hardcoded the greeting. Enabling this second test has
278
+ unleashed a new expectation: that our program incorporate a name given
279
+ into that greeting. When given the name "`Alice`", that's who should be
280
+ greeted instead of "`World`".
281
+
282
+ (Re)open `src/main/kotlin/HelloWorld.kt`.
283
+
284
+ ```kotlin
285
+ fun hello(name: String = ""): String {
286
+ return "Hello, World!"
287
+ }
288
+ ```
289
+
290
+ While `hello()` does accept a reference to a string named `name`, it is not
291
+ using it in the output. Let's change that:
292
+
293
+
294
+ ```kotlin
295
+ fun hello(name: String = ""): String {
296
+ return "Hello, $name!"
297
+ }
298
+ ```
299
+
300
+ _(Kotlin allows you to embed expressions within strings, a feature known as
301
+ string interpolation. For more about this feature, see
302
+ https://kotlinlang.org/docs/reference/basic-types.html#string-templates )_
303
+
304
+ ... and rerun the tests ...
305
+
306
+ ```
307
+ $ gradle test
308
+ :test
309
+
310
+ HelloWorldTest > helloSampleName PASSED
311
+
312
+ HelloWorldTest > helloBlankName SKIPPED
313
+
314
+ HelloWorldTest > helloNoName FAILED
315
+ org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, []!>
316
+ at org.junit.Assert.assertEquals(Assert.java:115)
317
+ at org.junit.Assert.assertEquals(Assert.java:144)
318
+ at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
319
+
320
+ HelloWorldTest > helloAnotherSampleName SKIPPED
321
+
322
+ 4 tests completed, 1 failed, 2 skipped
323
+ ```
324
+
325
+ Wait... didn't we just fix the test? Why is it failing? Take a closer look...
326
+
327
+ In fact, `helloSampleName()` *is* passing. It's just that at the same time,
328
+ we just inadvertently broke that first test: `helloNoName()`.
329
+
330
+ This is one tiny example of the benefit of maintaining a test suite: if we
331
+ use them to drive out our code, the second we break the program the tests
332
+ say so. Since we saw them passing just *before* our latest change,
333
+ whatever we *just* did most likely cause that regression.
334
+
335
+ Our latest change was making the greeting dependent on the name given. If
336
+ no name is given, our function defaults to an empty string. The intent is
337
+ that when `hello()` is called on no one in particular, our function greets
338
+ the whole world. Sound like a job for a default value!
339
+
340
+ `src/main/kotlin/HelloWorld.kt`:
341
+ ```kotlin
342
+ fun hello(name: String = "World"): String {
343
+ return "Hello, $name!"
344
+ }
345
+ ```
346
+
347
+ ... and re-run the tests ...
348
+
349
+ ```
350
+ $ gradle test
351
+ :compileKotlin
352
+ :compileJava UP-TO-DATE
353
+ :copyMainKotlinClasses
354
+ :processResources UP-TO-DATE
355
+ :classes UP-TO-DATE
356
+ :compileTestKotlin
357
+ :compileTestJava UP-TO-DATE
358
+ :copyTestKotlinClasses
359
+ :processTestResources UP-TO-DATE
360
+ :testClasses UP-TO-DATE
361
+ :test
362
+
363
+ HelloWorldTest > helloSampleName PASSED
364
+
365
+ HelloWorldTest > helloBlankName SKIPPED
366
+
367
+ HelloWorldTest > helloNoName PASSED
368
+
369
+ HelloWorldTest > helloAnotherSampleName SKIPPED
370
+
371
+ BUILD SUCCESSFUL
372
+ ```
373
+
374
+ Excellent! Not only are both our tests passing, but that pesky warning
375
+ about not using `name` has faded into the distant past. We're now
376
+ (at least) three-fourth the way done. Just two more tests to go...
377
+
378
+
379
+
380
+ ## Enabling and fixing the third test
381
+
382
+ (Re)open `src/test/kotlin/HelloWorldTest.kt` and find the penultimate test:
383
+
384
+ ```kotlin
385
+ @Test
386
+ @Ignore
387
+ fun helloBlankName() {
388
+ assertEquals("Hello, World!", hello(" "))
389
+ }
390
+ ```
391
+
392
+ In this test, we're trying to be tricky. It's one thing to omit a
393
+ parameter completely; it's a whole other situation when we provide a blank
394
+ string for a name. This test is telling us that we'd like to treat these
395
+ cases the same way.
396
+
397
+ ... and remove it's `@Ignore` to enable it ...
398
+
399
+ ```kotlin
400
+ @Test
401
+ fun helloBlankName() {
402
+ assertEquals("Hello, World!", hello(" "))
403
+ }
404
+ ```
405
+
406
+ ... and re-run the tests ...
407
+
408
+ ```
409
+ $ gradle test
410
+ :test
411
+
412
+ HelloWorldTest > helloSampleName PASSED
413
+
414
+ HelloWorldTest > helloBlankName FAILED
415
+ org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, [ ]!>
416
+ at org.junit.Assert.assertEquals(Assert.java:115)
417
+ at org.junit.Assert.assertEquals(Assert.java:144)
418
+ at HelloWorldTest.helloBlankName(HelloWorldTest.kt:20)
419
+
420
+ HelloWorldTest > helloNoName PASSED
421
+
422
+ HelloWorldTest > helloAnotherSampleName SKIPPED
423
+
424
+ 4 tests completed, 1 failed, 1 skipped
425
+ ```
426
+
427
+ Since `" "` is an actual value, Kotlin does _not_ substitute in the
428
+ default value.
429
+
430
+ (Re)open `src/main/kotlin/HelloWorld.kt`.
431
+
432
+ ```kotlin
433
+ fun hello(name: String = "World"): String {
434
+ return "Hello, $name!"
435
+ }
436
+ ```
437
+
438
+ One way to handle this case is to check to see if `name` is blank. Let's
439
+ do that:
440
+
441
+
442
+ ```kotlin
443
+ fun hello(name: String = "World"): String {
444
+ return "Hello, ${if (name.isBlank()) "World" else name}!"
445
+ }
446
+ ```
447
+
448
+ As you can see, string templates can contain not just references to
449
+ variables, but entire expressions! This is appropriate in a case like this
450
+ where we want to apply a simple condition to a value.
451
+
452
+ ... and rerun the tests ...
453
+
454
+ ```
455
+ $ gradle test
456
+ :test
457
+
458
+ HelloWorldTest > helloSampleName PASSED
459
+
460
+ HelloWorldTest > helloBlankName PASSED
461
+
462
+ HelloWorldTest > helloNoName PASSED
463
+
464
+ HelloWorldTest > helloAnotherSampleName SKIPPED
465
+
466
+ BUILD SUCCESSFUL
467
+ ```
468
+
469
+ We're almost there (perhaps closer than you think)! Just _one_ more test
470
+ to pass before we have a solution we can have real confidence in.
471
+
472
+
473
+
474
+ ## Enabling the last test
475
+
476
+ (Re)open `src/test/kotlin/HelloWorldTest.kt` and find the last test:
477
+
478
+ ```kotlin
479
+ @Test
480
+ @Ignore
481
+ fun helloAnotherSampleName() {
482
+ assertEquals("Hello, Bob!", hello("Bob"))
483
+ }
484
+ ```
485
+
486
+ ... and pop-off that `@Ignore` ...
487
+
488
+ ```kotlin
489
+ @Test
490
+ fun helloAnotherSampleName() {
491
+ assertEquals("Hello, Bob!", hello("Bob"))
492
+ }
493
+ ```
494
+
495
+ ... then rerun the tests ...
496
+
497
+ ```
498
+ :test
499
+
500
+ HelloWorldTest > helloSampleName PASSED
501
+
502
+ HelloWorldTest > helloBlankName PASSED
503
+
504
+ HelloWorldTest > helloNoName PASSED
505
+
506
+ HelloWorldTest > helloAnotherSampleName PASSED
507
+
508
+ BUILD SUCCESSFUL
509
+ ```
510
+
511
+ Oh, hello! Turns out, the solution we put into place didn't just apply for
512
+ "`Alice`" but for "`Bob`" equally well. In this case, the test succeeded
513
+ with no additional code on our part.
514
+
515
+ Congratulations!
516
+
517
+
518
+
519
+ ## Refactoring
520
+
521
+ Now that you've got all the tests passing, you might consider whether
522
+ the code is in the most readable/maintainable/efficient shape. What makes
523
+ for "good" design of software is a big topic. The pursuit of it underlies
524
+ much of what makes up the more valuable conversations on Exercism.
525
+
526
+ Kotlin is such a concise language and this exercise is so small, there is
527
+ not much room for us to make adjustments. Most would leave this code, as
528
+ is.
529
+
530
+ That said, we've taken such pains to illustrate two core parts of the
531
+ Test-Driven Development approach (i.e. "red", "green"), we'd be remiss if
532
+ we skipped the all important final part: "refactor".
533
+
534
+ More on TDD at http://www.jamesshore.com/Blog/Red-Green-Refactor.html.
535
+
536
+ The core responsibility of `hello()` is to produce a personalized greeting.
537
+ _How_ we determine whether or not a name is given (i.e. `name` is
538
+ effectively an empty string) is a lower-level detail.
539
+
540
+ ```kotlin
541
+ fun hello(name: String = "World"): String {
542
+ return "Hello, ${if (name.isBlank()) "World" else name}!"
543
+ }
544
+ ```
545
+
546
+ How would things read if we extracted that detail into a separate method?
547
+
548
+ ```kotlin
549
+ fun hello(name: String = ""): String {
550
+ return "Hello, ${whom(name)}!"
551
+ }
552
+
553
+ private fun whom(name: String):String {
554
+ return if(name.isBlank()) "World" else name;
555
+ }
556
+ ```
557
+
558
+ By extracting that logic into the `whom()` method, we've added a little
559
+ abstraction to our program — it's not as literal as it was before. Yet,
560
+ it allows us to defer _needing_ to understand _how_ the recipient of the
561
+ greeting is determined.
562
+
563
+ If we can assume that `whom()` just works, we don't have to
564
+ downshift in our head to those details. Instead, we can remain at the same
565
+ level of thinking: what's the greeting?
566
+
567
+ _(Yes, this is considerable more lines of code; again, not a move we'd likely
568
+ make typically. The takeaway is this: when you are "done" with an exercise
569
+ ask yourself, "can I adjust the shape of this code to better tell the
570
+ story of what's going on through its shape?")_
571
+
572
+ We made a bunch of changes, let's make sure we didn't break the program!
573
+
574
+ ```
575
+ $ gradle test
576
+ :compileKotlin
577
+ :compileJava UP-TO-DATE
578
+ :copyMainKotlinClasses
579
+ :processResources UP-TO-DATE
580
+ :classes UP-TO-DATE
581
+ :compileTestKotlin
582
+ :compileTestJava UP-TO-DATE
583
+ :copyTestKotlinClasses UP-TO-DATE
584
+ :processTestResources UP-TO-DATE
585
+ :testClasses UP-TO-DATE
586
+ :test
587
+
588
+ HelloWorldTest > helloSampleName PASSED
589
+
590
+ HelloWorldTest > helloBlankName PASSED
591
+
592
+ HelloWorldTest > helloNoName PASSED
593
+
594
+ HelloWorldTest > helloAnotherSampleName PASSED
595
+
596
+ BUILD SUCCESSFUL
597
+ ```
598
+
599
+ This illustrates another benefit of writing tests: you can make significant
600
+ changes to the structure of the program and very quickly restore your
601
+ confidence that the program still works. These tests are a far cry from a
602
+ "proof" of correctness, but well-written tests do a much better job of
603
+ (very quickly) giving us evidence that it is. Without them, we manually
604
+ run the program with different inputs and/or inspecting the code
605
+ line-by-line — time-consuming and error prone.
606
+
607
+
608
+
609
+ # Submitting your first iteration
610
+
611
+ With a working solution that we've reviewed, we're ready to submit it to
612
+ exercism.io.
613
+
614
+ ```
615
+ $ exercism submit src/main/kotlin/HelloWorld.kt
616
+ ```
617
+
618
+
619
+
620
+ # Next Steps
621
+
622
+ From here, there are a number of paths you can take.
623
+
624
+
625
+ ## Move on to the next exercise
626
+
627
+ There are many more exercises you can practice with. Grab the next one!
628
+
629
+ ```
630
+ $ exercism fetch kotlin
631
+ ```
632
+
633
+
634
+ ## Review (and comment on) others' submissions to this exercise
635
+
636
+ The heart of Exercism is the conversations about coding
637
+ practices. It's definitely fun to practice, but engaging with others
638
+ both in their attempts and your own is how you get feedback. That feedback
639
+ can help point out what you're doing well and where you might need to
640
+ improve.
641
+
642
+ Some submissions will be nearly identical to yours; others will be
643
+ completely different. Seeing both kinds can be instructive and interesting.
644
+
645
+ Note that you can only view submissions of others for exercises you have
646
+ completed yourself. This enriches the experience of reading others' code
647
+ because you'll have your own experience of trying to solve the problem.
648
+
649
+ Here's an up-to-date list of submissions on the Kotlin track:
650
+
651
+ http://exercism.io/tracks/kotlin/exercises
652
+
653
+
654
+
655
+ ## Submit another iteration
656
+
657
+ You are also encouraged to consider additional "requirements" on a given
658
+ exercise.
659
+
660
+ For example, you could add a test or two that requires that the greeting
661
+ use the capitalized form on the person's name, regardless of the case they
662
+ used.
663
+
664
+ In that situation, you'd:
665
+
666
+ 1. add a new test setting up that new expectation,
667
+ 2. implement that in the code (the same process we just went through
668
+ together, above).
669
+ 3. review your code for readability and refactor as you see fit.
670
+
671
+ Exercism practitioners who "play" with each exercise — over trying to go as
672
+ fast as they can through the stream of exercises — report deep rewards.
673
+
674
+
675
+ ## Contribute to Exercism
676
+
677
+ The entire of Exercism is Open Source and is the labor of love for more
678
+ than 100 maintainers and many more contributors.
679
+
680
+ A starting point to jumping in can be found here:
681
+
682
+ https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md
683
+
684
+
685
+ ----
686
+
687
+ Regardless of what you decide to do next, we sincerely hope you learn
688
+ and enjoy being part of this community. If at any time you need assistance
689
+ do not hesitate to ask for help:
690
+
691
+ http://exercism.io/languages/kotlin/help
692
+
693
+ Cheers!