trackler 2.0.6.34 → 2.0.6.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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!