trackler 2.0.6.11 → 2.0.6.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (276) hide show
  1. checksums.yaml +4 -4
  2. data/common/CONTRIBUTING.md +6 -1
  3. data/common/exercises/difference-of-squares/metadata.yml +1 -1
  4. data/common/exercises/luhn/canonical-data.json +2 -2
  5. data/common/exercises/rectangles/canonical-data.json +25 -0
  6. data/common/exercises/rectangles/description.md +11 -3
  7. data/lib/trackler/version.rb +1 -1
  8. data/tracks/ceylon/config.json +9 -0
  9. data/tracks/ceylon/exercises/anagram/source/anagram/AnagramTest.ceylon +38 -39
  10. data/tracks/ceylon/exercises/bracket-push/source/bracketpush/BracketsTest.ceylon +28 -29
  11. data/tracks/ceylon/exercises/largest-series-product/example/Series.ceylon +13 -0
  12. data/tracks/ceylon/exercises/largest-series-product/source/largestseriesproduct/Series.ceylon +5 -0
  13. data/tracks/ceylon/exercises/largest-series-product/source/largestseriesproduct/SeriesTest.ceylon +30 -0
  14. data/tracks/ceylon/exercises/largest-series-product/source/largestseriesproduct/module.ceylon +3 -0
  15. data/tracks/csharp/config.json +41 -0
  16. data/tracks/csharp/exercises/alphametics/AlphameticsTest.cs +122 -0
  17. data/tracks/csharp/exercises/alphametics/Example.cs +139 -0
  18. data/tracks/csharp/exercises/dot-dsl/DotDslTest.cs +91 -0
  19. data/tracks/csharp/exercises/dot-dsl/Example.cs +90 -0
  20. data/tracks/csharp/exercises/dot-dsl/HINTS.md +2 -0
  21. data/tracks/csharp/exercises/error-handling/ErrorHandlingTest.cs +65 -0
  22. data/tracks/csharp/exercises/error-handling/Example.cs +34 -0
  23. data/tracks/csharp/exercises/exercises.csproj +1 -1
  24. data/tracks/csharp/exercises/hangman/Example.cs +85 -0
  25. data/tracks/csharp/exercises/hangman/HangmanTest.cs +140 -0
  26. data/tracks/csharp/exercises/ledger/Example.cs +106 -0
  27. data/tracks/csharp/exercises/ledger/Ledger.cs +166 -0
  28. data/tracks/csharp/exercises/ledger/LedgerTest.cs +168 -0
  29. data/tracks/elixir/exercises/allergies/allergies_test.exs +2 -2
  30. data/tracks/elixir/exercises/markdown/example.exs +3 -3
  31. data/tracks/elixir/exercises/phone-number/example.exs +0 -2
  32. data/tracks/elixir/exercises/queen-attack/example.exs +1 -1
  33. data/tracks/elixir/exercises/wordy/example.exs +6 -6
  34. data/tracks/elixir/exercises/zipper/zipper_test.exs +12 -12
  35. data/tracks/elixir/mix.exs +1 -1
  36. data/tracks/fsharp/config.json +8 -8
  37. data/tracks/fsharp/docs/ABOUT.md +4 -0
  38. data/tracks/fsharp/exercises/alphametics/AlphameticsTest.fs +33 -13
  39. data/tracks/fsharp/exercises/alphametics/Example.fs +29 -64
  40. data/tracks/fsharp/exercises/binary-search-tree/BinarySearchTreeTest.fs +14 -14
  41. data/tracks/fsharp/exercises/binary-search-tree/Example.fs +17 -14
  42. data/tracks/fsharp/exercises/triangle/TriangleTest.fs +0 -5
  43. data/tracks/go/README.md +3 -3
  44. data/tracks/go/config.json +10 -3
  45. data/tracks/go/exercises/acronym/acronym.go +5 -0
  46. data/tracks/go/exercises/bob/example_gen.go +1 -1
  47. data/tracks/go/exercises/clock/example_gen.go +1 -1
  48. data/tracks/go/exercises/connect/example_gen.go +1 -1
  49. data/tracks/go/exercises/custom-set/example_gen.go +1 -1
  50. data/tracks/go/exercises/gigasecond/example_gen.go +1 -1
  51. data/tracks/go/exercises/hamming/example_gen.go +1 -1
  52. data/tracks/go/exercises/largest-series-product/example_gen.go +1 -1
  53. data/tracks/go/exercises/leap/cases_test.go +5 -7
  54. data/tracks/go/exercises/leap/example.go +1 -1
  55. data/tracks/go/exercises/leap/example_gen.go +1 -1
  56. data/tracks/go/exercises/leap/leap.go +1 -1
  57. data/tracks/go/exercises/leap/leap_test.go +1 -1
  58. data/tracks/go/exercises/meetup/example_gen.go +1 -1
  59. data/tracks/go/exercises/nucleotide-count/nucleotide_count_test.go +0 -5
  60. data/tracks/go/exercises/pangram/pangram.go +5 -0
  61. data/tracks/go/exercises/raindrops/example_gen.go +1 -1
  62. data/tracks/go/exercises/rna-transcription/example_gen.go +1 -1
  63. data/tracks/go/exercises/roman-numerals/example_gen.go +1 -1
  64. data/tracks/go/exercises/word-count/example_gen.go +1 -1
  65. data/tracks/go/gen/gen.go +3 -2
  66. data/tracks/haskell/exercises/accumulate/src/Accumulate.hs +1 -1
  67. data/tracks/haskell/exercises/all-your-base/src/Base.hs +1 -1
  68. data/tracks/haskell/exercises/allergies/src/Allergies.hs +2 -2
  69. data/tracks/haskell/exercises/alphametics/src/Alphametics.hs +1 -1
  70. data/tracks/haskell/exercises/anagram/src/Anagram.hs +1 -1
  71. data/tracks/haskell/exercises/atbash-cipher/src/Atbash.hs +2 -2
  72. data/tracks/haskell/exercises/bank-account/src/BankAccount.hs +4 -4
  73. data/tracks/haskell/exercises/binary/src/Binary.hs +1 -1
  74. data/tracks/haskell/exercises/binary-search-tree/src/BST.hs +8 -8
  75. data/tracks/haskell/exercises/bob/src/Bob.hs +1 -1
  76. data/tracks/haskell/exercises/bowling/src/Bowling.hs +1 -1
  77. data/tracks/haskell/exercises/change/src/Change.hs +1 -1
  78. data/tracks/haskell/exercises/clock/src/Clock.hs +4 -4
  79. data/tracks/haskell/exercises/connect/src/Connect.hs +1 -1
  80. data/tracks/haskell/exercises/crypto-square/src/CryptoSquare.hs +1 -1
  81. data/tracks/haskell/exercises/custom-set/src/CustomSet.hs +13 -13
  82. data/tracks/haskell/exercises/difference-of-squares/src/Squares.hs +3 -3
  83. data/tracks/haskell/exercises/dominoes/src/Dominoes.hs +1 -1
  84. data/tracks/haskell/exercises/etl/src/ETL.hs +1 -1
  85. data/tracks/haskell/exercises/forth/src/Forth.hs +3 -3
  86. data/tracks/haskell/exercises/gigasecond/src/Gigasecond.hs +1 -1
  87. data/tracks/haskell/exercises/go-counting/src/Counting.hs +2 -2
  88. data/tracks/haskell/exercises/grade-school/src/School.hs +4 -4
  89. data/tracks/haskell/exercises/grains/src/Grains.hs +2 -2
  90. data/tracks/haskell/exercises/hamming/src/Hamming.hs +1 -1
  91. data/tracks/haskell/exercises/hexadecimal/src/Hexadecimal.hs +1 -1
  92. data/tracks/haskell/exercises/kindergarten-garden/src/Garden.hs +3 -3
  93. data/tracks/haskell/exercises/largest-series-product/src/Series.hs +1 -1
  94. data/tracks/haskell/exercises/leap/src/LeapYear.hs +1 -1
  95. data/tracks/haskell/exercises/lens-person/src/Person.hs +4 -4
  96. data/tracks/haskell/exercises/linked-list/src/Deque.hs +5 -5
  97. data/tracks/haskell/exercises/list-ops/src/ListOps.hs +8 -8
  98. data/tracks/haskell/exercises/luhn/src/Luhn.hs +5 -5
  99. data/tracks/haskell/exercises/matrix/src/Matrix.hs +10 -10
  100. data/tracks/haskell/exercises/meetup/src/Meetup.hs +1 -1
  101. data/tracks/haskell/exercises/minesweeper/src/Minesweeper.hs +1 -1
  102. data/tracks/haskell/exercises/nth-prime/src/Prime.hs +1 -1
  103. data/tracks/haskell/exercises/nucleotide-count/src/DNA.hs +2 -2
  104. data/tracks/haskell/exercises/ocr-numbers/src/OCR.hs +1 -1
  105. data/tracks/haskell/exercises/octal/src/Octal.hs +2 -2
  106. data/tracks/haskell/exercises/palindrome-products/src/Palindromes.hs +2 -2
  107. data/tracks/haskell/exercises/parallel-letter-frequency/src/Frequency.hs +1 -1
  108. data/tracks/haskell/exercises/pascals-triangle/src/Triangle.hs +1 -1
  109. data/tracks/haskell/exercises/phone-number/src/Phone.hs +3 -3
  110. data/tracks/haskell/exercises/pig-latin/src/PigLatin.hs +1 -1
  111. data/tracks/haskell/exercises/pov/src/POV.hs +2 -2
  112. data/tracks/haskell/exercises/prime-factors/src/PrimeFactors.hs +1 -1
  113. data/tracks/haskell/exercises/pythagorean-triplet/src/Triplet.hs +3 -3
  114. data/tracks/haskell/exercises/queen-attack/src/Queens.hs +2 -2
  115. data/tracks/haskell/exercises/raindrops/src/Raindrops.hs +1 -1
  116. data/tracks/haskell/exercises/rna-transcription/src/DNA.hs +1 -1
  117. data/tracks/haskell/exercises/robot-name/src/Robot.hs +3 -3
  118. data/tracks/haskell/exercises/robot-simulator/src/Robot.hs +6 -6
  119. data/tracks/haskell/exercises/roman-numerals/src/Roman.hs +1 -1
  120. data/tracks/haskell/exercises/run-length-encoding/src/RunLength.hs +2 -2
  121. data/tracks/haskell/exercises/saddle-points/src/Matrix.hs +1 -1
  122. data/tracks/haskell/exercises/say/src/Say.hs +1 -1
  123. data/tracks/haskell/exercises/scrabble-score/src/Scrabble.hs +2 -2
  124. data/tracks/haskell/exercises/secret-handshake/src/SecretHandshake.hs +1 -1
  125. data/tracks/haskell/exercises/series/src/Series.hs +1 -1
  126. data/tracks/haskell/exercises/sgf-parsing/src/Sgf.hs +1 -1
  127. data/tracks/haskell/exercises/sieve/src/Sieve.hs +1 -1
  128. data/tracks/haskell/exercises/simple-cipher/src/Cipher.hs +3 -3
  129. data/tracks/haskell/exercises/simple-linked-list/src/LinkedList.hs +8 -8
  130. data/tracks/haskell/exercises/space-age/src/SpaceAge.hs +1 -1
  131. data/tracks/haskell/exercises/strain/src/Strain.hs +2 -2
  132. data/tracks/haskell/exercises/sublist/src/Sublist.hs +1 -1
  133. data/tracks/haskell/exercises/sum-of-multiples/src/SumOfMultiples.hs +1 -1
  134. data/tracks/haskell/exercises/triangle/src/Triangle.hs +1 -1
  135. data/tracks/haskell/exercises/trinary/src/Trinary.hs +2 -2
  136. data/tracks/haskell/exercises/word-count/src/WordCount.hs +1 -1
  137. data/tracks/haskell/exercises/wordy/src/WordProblem.hs +1 -1
  138. data/tracks/haskell/exercises/zebra-puzzle/src/ZebraPuzzle.hs +1 -1
  139. data/tracks/haskell/exercises/zipper/src/Zipper.hs +9 -9
  140. data/tracks/java/docs/MAINTAINING.md +48 -0
  141. data/tracks/java/exercises/queen-attack/src/test/java/QueenAttackCalculatorTest.java +51 -51
  142. data/tracks/kotlin/exercises/etl/src/example/kotlin/ETL.kt +1 -1
  143. data/tracks/kotlin/exercises/etl/src/test/kotlin/ETLTest.kt +19 -19
  144. data/tracks/kotlin/exercises/pangram/src/test/kotlin/PangramTest.kt +5 -0
  145. data/tracks/lisp/docs/ABOUT.md +9 -0
  146. data/tracks/lua/exercises/transpose/example.lua +1 -1
  147. data/tracks/lua/exercises/transpose/transpose_spec.lua +16 -0
  148. data/tracks/pascal/config.json +36 -36
  149. data/tracks/pascal/exercises/bob/uBobTests.pas +0 -1
  150. data/tracks/pascal/exercises/hamming/uHammingTests.pas +0 -1
  151. data/tracks/pascal/exercises/leap/uLeapTests.pas +0 -1
  152. data/tracks/pascal/exercises/saddle-points/uSaddlePointsExample.pas +11 -0
  153. data/tracks/pascal/exercises/saddle-points/uSaddlePointsTests.pas +9 -1
  154. data/tracks/perl6/exercises/atbash-cipher/cipher.t +1 -1
  155. data/tracks/php/config.json +7 -0
  156. data/tracks/php/exercises/robot-simulator/example.php +148 -0
  157. data/tracks/php/exercises/robot-simulator/robot-simulator_test.php +168 -0
  158. data/tracks/pony/config.json +16 -7
  159. data/tracks/pony/exercises/roman-numerals/example.pony +35 -0
  160. data/tracks/pony/exercises/roman-numerals/test.pony +45 -0
  161. data/tracks/python/requirements-travis.txt +1 -1
  162. data/tracks/ruby/.rubocop.yml +1 -1
  163. data/tracks/ruby/bin/enable-executable +1 -1
  164. data/tracks/ruby/bin/executable-tests-check +1 -1
  165. data/tracks/ruby/exercises/acronym/example.tt +2 -3
  166. data/tracks/ruby/exercises/all-your-base/example.tt +2 -2
  167. data/tracks/ruby/exercises/alphametics/example.tt +2 -2
  168. data/tracks/ruby/exercises/anagram/example.tt +2 -3
  169. data/tracks/ruby/exercises/binary/example.tt +2 -3
  170. data/tracks/ruby/exercises/bowling/example.tt +2 -3
  171. data/tracks/ruby/exercises/bracket-push/example.tt +2 -3
  172. data/tracks/ruby/exercises/clock/example.tt +2 -3
  173. data/tracks/ruby/exercises/connect/example.rb +1 -1
  174. data/tracks/ruby/exercises/connect/example.tt +1 -1
  175. data/tracks/ruby/exercises/custom-set/example.tt +2 -3
  176. data/tracks/ruby/exercises/diamond/example.rb +1 -1
  177. data/tracks/ruby/exercises/difference-of-squares/example.tt +2 -3
  178. data/tracks/ruby/exercises/dominoes/example.tt +2 -2
  179. data/tracks/ruby/exercises/gigasecond/example.tt +2 -3
  180. data/tracks/ruby/exercises/grains/example.tt +2 -2
  181. data/tracks/ruby/exercises/hamming/example.tt +2 -3
  182. data/tracks/ruby/exercises/hello-world/example.tt +1 -2
  183. data/tracks/ruby/exercises/isogram/example.tt +2 -2
  184. data/tracks/ruby/exercises/largest-series-product/example.tt +2 -4
  185. data/tracks/ruby/exercises/leap/example.tt +2 -3
  186. data/tracks/ruby/exercises/nth-prime/example.tt +2 -4
  187. data/tracks/ruby/exercises/pangram/example.tt +2 -2
  188. data/tracks/ruby/exercises/queen-attack/example.tt +2 -3
  189. data/tracks/ruby/exercises/raindrops/example.tt +2 -3
  190. data/tracks/ruby/exercises/rna-transcription/example.tt +2 -3
  191. data/tracks/ruby/exercises/roman-numerals/example.tt +2 -3
  192. data/tracks/ruby/exercises/run-length-encoding/example.tt +2 -3
  193. data/tracks/ruby/exercises/sieve/example.tt +2 -4
  194. data/tracks/ruby/exercises/simple-linked-list/simple_linked_list_test.rb +6 -6
  195. data/tracks/ruby/exercises/tournament/example.tt +2 -3
  196. data/tracks/ruby/exercises/transpose/example.tt +2 -3
  197. data/tracks/ruby/exercises/triangle/example.tt +2 -3
  198. data/tracks/ruby/exercises/two-bucket/example.tt +2 -3
  199. data/tracks/ruby/exercises/word-count/example.tt +2 -3
  200. data/tracks/ruby/exercises/wordy/example.tt +2 -2
  201. data/tracks/ruby/lib/acronym_cases.rb +2 -0
  202. data/tracks/ruby/lib/all_your_base_cases.rb +3 -1
  203. data/tracks/ruby/lib/alphametics_cases.rb +6 -4
  204. data/tracks/ruby/lib/anagram_cases.rb +2 -0
  205. data/tracks/ruby/lib/binary_cases.rb +2 -0
  206. data/tracks/ruby/lib/bowling_cases.rb +2 -0
  207. data/tracks/ruby/lib/bracket_push_cases.rb +2 -0
  208. data/tracks/ruby/lib/clock_cases.rb +2 -0
  209. data/tracks/ruby/lib/connect_cases.rb +2 -0
  210. data/tracks/ruby/lib/custom_set_cases.rb +2 -0
  211. data/tracks/ruby/lib/difference_of_squares_cases.rb +2 -0
  212. data/tracks/ruby/lib/dominoes_cases.rb +2 -0
  213. data/tracks/ruby/lib/exercise_cases.rb +2 -0
  214. data/tracks/ruby/lib/generator/files/track_files.rb +3 -3
  215. data/tracks/ruby/lib/generator/files.rb +1 -1
  216. data/tracks/ruby/lib/generator/template_values.rb +5 -14
  217. data/tracks/ruby/lib/gigasecond_cases.rb +2 -0
  218. data/tracks/ruby/lib/grains_cases.rb +3 -1
  219. data/tracks/ruby/lib/hamming_cases.rb +2 -0
  220. data/tracks/ruby/lib/hello_world_cases.rb +2 -0
  221. data/tracks/ruby/lib/isogram_cases.rb +3 -1
  222. data/tracks/ruby/lib/largest_series_product_cases.rb +2 -0
  223. data/tracks/ruby/lib/leap_cases.rb +2 -0
  224. data/tracks/ruby/lib/nth_prime_cases.rb +2 -0
  225. data/tracks/ruby/lib/pangram_cases.rb +3 -1
  226. data/tracks/ruby/lib/queen_attack_cases.rb +2 -0
  227. data/tracks/ruby/lib/raindrops_cases.rb +2 -0
  228. data/tracks/ruby/lib/rna_transcription_cases.rb +2 -0
  229. data/tracks/ruby/lib/roman_numerals_cases.rb +2 -0
  230. data/tracks/ruby/lib/run_length_encoding_cases.rb +2 -0
  231. data/tracks/ruby/lib/sieve_cases.rb +2 -0
  232. data/tracks/ruby/lib/tournament_cases.rb +2 -0
  233. data/tracks/ruby/lib/transpose_cases.rb +2 -0
  234. data/tracks/ruby/lib/triangle_cases.rb +2 -0
  235. data/tracks/ruby/lib/two_bucket_cases.rb +2 -0
  236. data/tracks/ruby/lib/word_count_cases.rb +2 -0
  237. data/tracks/ruby/lib/wordy_cases.rb +2 -0
  238. data/tracks/ruby/test/fixtures/xruby/exercises/alpha/example.tt +2 -2
  239. data/tracks/ruby/test/fixtures/xruby/lib/alpha_cases.rb +1 -1
  240. data/tracks/ruby/test/generator/command_line_test.rb +1 -1
  241. data/tracks/ruby/test/generator/template_values_test.rb +7 -7
  242. data/tracks/rust/.travis.yml +4 -0
  243. data/tracks/rust/_test/check-exercises.sh +11 -2
  244. data/tracks/rust/config.json +9 -0
  245. data/tracks/rust/exercises/luhn/.gitignore +7 -0
  246. data/tracks/rust/exercises/luhn/Cargo.toml +3 -0
  247. data/tracks/rust/exercises/luhn/example.rs +13 -0
  248. data/tracks/rust/exercises/luhn/tests/luhn.rs +38 -0
  249. data/tracks/rust/exercises/parallel-letter-frequency/HINTS.md +32 -0
  250. data/tracks/rust/exercises/parallel-letter-frequency/benches/benchmark.rs +99 -0
  251. data/tracks/scala/config.json +57 -1
  252. data/tracks/scala/exercises/allergies/build.sbt +2 -2
  253. data/tracks/scala/exercises/atbash-cipher/build.sbt +2 -2
  254. data/tracks/scala/exercises/bank-account/build.sbt +3 -2
  255. data/tracks/scala/exercises/binary-search-tree/build.sbt +2 -2
  256. data/tracks/scala/exercises/clock/build.sbt +2 -2
  257. data/tracks/scala/exercises/crypto-square/build.sbt +2 -2
  258. data/tracks/scala/exercises/custom-set/build.sbt +3 -2
  259. data/tracks/scala/exercises/food-chain/build.sbt +3 -2
  260. data/tracks/scala/exercises/house/build.sbt +2 -2
  261. data/tracks/scala/exercises/kindergarten-garden/build.sbt +3 -2
  262. data/tracks/scala/exercises/largest-series-product/build.sbt +2 -2
  263. data/tracks/scala/exercises/linked-list/build.sbt +3 -2
  264. data/tracks/scala/exercises/matrix/build.sbt +2 -2
  265. data/tracks/scala/exercises/minesweeper/build.sbt +2 -2
  266. data/tracks/scala/exercises/nth-prime/build.sbt +2 -2
  267. data/tracks/scala/exercises/ocr-numbers/build.sbt +2 -2
  268. data/tracks/scala/exercises/palindrome-products/build.sbt +2 -2
  269. data/tracks/scala/exercises/prime-factors/build.sbt +3 -2
  270. data/tracks/scala/exercises/queen-attack/build.sbt +2 -2
  271. data/tracks/scala/exercises/raindrops/build.sbt +2 -2
  272. data/tracks/scala/exercises/robot-simulator/build.sbt +2 -2
  273. data/tracks/scala/exercises/triangle/build.sbt +2 -2
  274. data/tracks/scala/exercises/trinary/build.sbt +2 -2
  275. data/tracks/scala/exercises/wordy/build.sbt +3 -3
  276. metadata +33 -2
@@ -0,0 +1,106 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Globalization;
4
+ using System.Linq;
5
+
6
+ public class LedgerEntry
7
+ {
8
+ public LedgerEntry(DateTime date, string description, float change)
9
+ {
10
+ Date = date;
11
+ Description = description;
12
+ Change = change;
13
+ }
14
+
15
+ public DateTime Date { get; }
16
+ public string Description { get; }
17
+ public float Change { get; }
18
+ }
19
+
20
+ public static class Ledger
21
+ {
22
+ private const int TruncateLength = 25;
23
+ private const string TruncateSuffix = "...";
24
+
25
+ public static LedgerEntry CreateEntry(string date, string description, int change) =>
26
+ new LedgerEntry(ParseDate(date), description, ParseChange(change));
27
+
28
+ private static DateTime ParseDate(string date) => DateTime.Parse(date, System.Globalization.CultureInfo.InvariantCulture);
29
+
30
+ private static float ParseChange(int change) => change / 100.0f;
31
+
32
+ private static string CurrencySymbol(string currency)
33
+ {
34
+ switch (currency)
35
+ {
36
+ case "USD": return "$";
37
+ case "EUR": return "€";
38
+ default: throw new ArgumentException("Invalid currency");
39
+ }
40
+ }
41
+
42
+ private static CultureInfo CultureInfo(string locale)
43
+ {
44
+ switch (locale)
45
+ {
46
+ case "en-US": return new CultureInfo(locale);
47
+ case "nl-NL": return new CultureInfo(locale);
48
+ default: throw new ArgumentException("Invalid locale");
49
+ }
50
+ }
51
+
52
+ private static string ShortDateFormat(string locale)
53
+ {
54
+ switch (locale)
55
+ {
56
+ case "en-US": return "MM/dd/yyyy";
57
+ case "nl-NL": return "dd/MM/yyyy";
58
+ default: throw new ArgumentException("Invalid locale");
59
+ }
60
+ }
61
+
62
+ private static CultureInfo getCulture(string currency, string locale)
63
+ {
64
+ var culture = CultureInfo(locale);
65
+ culture.NumberFormat.CurrencySymbol = CurrencySymbol(currency);
66
+ culture.DateTimeFormat.ShortDatePattern = ShortDateFormat(locale);
67
+ return culture;
68
+ }
69
+
70
+ private static string FormatHeader(CultureInfo culture)
71
+ {
72
+ switch (culture.Name)
73
+ {
74
+ case "en-US": return "Date | Description | Change ";
75
+ case "nl-NL": return "Datum | Omschrijving | Verandering ";
76
+ default: throw new ArgumentException("Invalid locale");
77
+ }
78
+ }
79
+
80
+ private static string FormatDate(IFormatProvider culture, DateTime date) => date.ToString("d", culture);
81
+
82
+ private static string FoormatDescription(string description) =>
83
+ description.Length <= TruncateLength ? description : description.Substring(0, TruncateLength - TruncateSuffix.Length) + TruncateSuffix;
84
+
85
+ private static string FormatChange(IFormatProvider culture, float change) =>
86
+ change < 0.0 ? change.ToString("C", culture) : change.ToString("C", culture) + " ";
87
+
88
+ private static string FormatEntry(IFormatProvider culture, LedgerEntry entry) =>
89
+ string.Format("{0} | {1,-25} | {2,13}", FormatDate(culture, entry.Date), FoormatDescription(entry.Description), FormatChange(culture, entry.Change));
90
+
91
+ private static IEnumerable<LedgerEntry> OrderEntries(LedgerEntry[] entries) =>
92
+ entries
93
+ .OrderBy(x => x.Date)
94
+ .ThenBy(x => x.Description)
95
+ .ThenBy(x => x.Change);
96
+
97
+ public static string Format(string currency, string locale, LedgerEntry[] entries)
98
+ {
99
+ var culture = getCulture(currency, locale);
100
+ var header = FormatHeader(culture);
101
+ var printedEntries = OrderEntries(entries).Select(entry => FormatEntry(culture, entry));
102
+ var lines = new[] { header }.Concat(printedEntries);
103
+
104
+ return string.Join("\n", lines);
105
+ }
106
+ }
@@ -0,0 +1,166 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Globalization;
4
+ using System.Linq;
5
+
6
+ public class LedgerEntry
7
+ {
8
+ public LedgerEntry(DateTime date, string desc, float chg)
9
+ {
10
+ Date = date;
11
+ Desc = desc;
12
+ Chg = chg;
13
+ }
14
+
15
+ public DateTime Date { get; }
16
+ public string Desc { get; }
17
+ public float Chg { get; }
18
+ }
19
+
20
+ public static class Ledger
21
+ {
22
+ public static LedgerEntry CreateEntry(string date, string desc, int chng)
23
+ {
24
+ return new LedgerEntry(DateTime.Parse(date, CultureInfo.InvariantCulture), desc, chng / 100.0f);
25
+ }
26
+
27
+ private static CultureInfo CreateCulture(string cur, string loc)
28
+ {
29
+ string curSymb = null;
30
+ string datPat = null;
31
+
32
+ if (cur != "USD" && cur != "EUR")
33
+ {
34
+ throw new ArgumentException("Invalid currency");
35
+ }
36
+ else
37
+ {
38
+ if (loc != "nl-NL" && loc != "en-US")
39
+ {
40
+ throw new ArgumentException("Invalid currency");
41
+ }
42
+
43
+ if (cur == "USD")
44
+ {
45
+ if (loc == "en-US")
46
+ {
47
+ curSymb = "$";
48
+ datPat = "MM/dd/yyyy";
49
+ }
50
+ else if (loc == "nl-NL")
51
+ {
52
+ curSymb = "$";
53
+ datPat = "dd/MM/yyyy";
54
+ }
55
+ }
56
+
57
+
58
+ if (cur == "EUR")
59
+ {
60
+ if (loc == "en-US")
61
+ {
62
+ curSymb = "€";
63
+ datPat = "MM/dd/yyyy";
64
+ }
65
+ else if (loc == "nl-NL")
66
+ {
67
+ curSymb = "€";
68
+ datPat = "dd/MM/yyyy";
69
+ }
70
+ }
71
+ }
72
+
73
+ var culture = new CultureInfo(loc);
74
+ culture.NumberFormat.CurrencySymbol = curSymb;
75
+ culture.DateTimeFormat.ShortDatePattern = datPat;
76
+ return culture;
77
+ }
78
+
79
+ private static string PrintHead(string loc)
80
+ {
81
+ if (loc == "en-US")
82
+ {
83
+ return "Date | Description | Change ";
84
+ }
85
+
86
+ else
87
+ {
88
+ if (loc == "nl-NL")
89
+ {
90
+ return "Datum | Omschrijving | Verandering ";
91
+ }
92
+ else
93
+ {
94
+ throw new ArgumentException("Invalid locale");
95
+ }
96
+ }
97
+ }
98
+
99
+ private static string Date(IFormatProvider culture, DateTime date) => date.ToString("d", culture);
100
+
101
+ private static string Description(string desc)
102
+ {
103
+ if (desc.Length > 25)
104
+ {
105
+ var trunc = desc.Substring(0, 22);
106
+ trunc += "...";
107
+ return trunc;
108
+ }
109
+
110
+ return desc;
111
+ }
112
+
113
+ private static string Change(IFormatProvider culture, float cgh)
114
+ {
115
+ return cgh < 0.0 ? cgh.ToString("C", culture) : cgh.ToString("C", culture) + " ";
116
+ }
117
+
118
+ private static string PrintEntry(IFormatProvider culture, LedgerEntry entry)
119
+ {
120
+ var formatted = "";
121
+ var date = Date(culture, entry.Date);
122
+ var description = Description(entry.Desc);
123
+ var change = Change(culture, entry.Chg);
124
+
125
+ formatted += date;
126
+ formatted += " | ";
127
+ formatted += string.Format("{0,-25}", description);
128
+ formatted += " | ";
129
+ formatted += string.Format("{0,13}", change);
130
+
131
+ return formatted;
132
+ }
133
+
134
+
135
+ private static IEnumerable<LedgerEntry> sort(LedgerEntry[] entries)
136
+ {
137
+ var neg = entries.Where(e => e.Chg < 0).OrderBy(x => x.Date + "@" + x.Desc + "@" + x.Chg);
138
+ var post = entries.Where(e => e.Chg >= 0).OrderBy(x => x.Date + "@" + x.Desc + "@" + x.Chg);
139
+
140
+ var result = new List<LedgerEntry>();
141
+ result.AddRange(neg);
142
+ result.AddRange(post);
143
+
144
+ return result;
145
+ }
146
+
147
+ public static string Format(string currency, string locale, LedgerEntry[] entries)
148
+ {
149
+ var formatted = "";
150
+ formatted += PrintHead(locale);
151
+
152
+ var culture = CreateCulture(currency, locale);
153
+
154
+ if (entries.Length > 0)
155
+ {
156
+ var entriesForOutput = sort(entries);
157
+
158
+ for (var i = 0; i < entriesForOutput.Count(); i++)
159
+ {
160
+ formatted += "\n" + PrintEntry(culture, entriesForOutput.Skip(i).First());
161
+ }
162
+ }
163
+
164
+ return formatted;
165
+ }
166
+ }
@@ -0,0 +1,168 @@
1
+ using NUnit.Framework;
2
+
3
+ public class LedgerTest
4
+ {
5
+ [Test]
6
+ public void Empty_ledger()
7
+ {
8
+ var currency = "USD";
9
+ var locale = "en-US";
10
+ var entries = new LedgerEntry[0];
11
+ var expected =
12
+ "Date | Description | Change ";
13
+
14
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
15
+ }
16
+
17
+ [Test]
18
+ public void One_entry()
19
+ {
20
+ var currency = "USD";
21
+ var locale = "en-US";
22
+ var entries = new[]
23
+ {
24
+ Ledger.CreateEntry("2015-01-01", "Buy present", -1000)
25
+ };
26
+ var expected =
27
+ "Date | Description | Change \n" +
28
+ "01/01/2015 | Buy present | ($10.00)";
29
+
30
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
31
+ }
32
+
33
+ [Test]
34
+ public void Credit_and_debit()
35
+ {
36
+ var currency = "USD";
37
+ var locale = "en-US";
38
+ var entries = new[]
39
+ {
40
+ Ledger.CreateEntry("2015-01-02", "Get present", 1000),
41
+ Ledger.CreateEntry("2015-01-01", "Buy present", -1000)
42
+ };
43
+ var expected =
44
+ "Date | Description | Change \n" +
45
+ "01/01/2015 | Buy present | ($10.00)\n" +
46
+ "01/02/2015 | Get present | $10.00 ";
47
+
48
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
49
+ }
50
+
51
+ [Test]
52
+ public void Multiple_entries_on_same_date_ordered_by_description()
53
+ {
54
+ var currency = "USD";
55
+ var locale = "en-US";
56
+ var entries = new[]
57
+ {
58
+ Ledger.CreateEntry("2015-01-01", "Buy present", -1000),
59
+ Ledger.CreateEntry("2015-01-01", "Get present", 1000)
60
+ };
61
+ var expected =
62
+ "Date | Description | Change \n" +
63
+ "01/01/2015 | Buy present | ($10.00)\n" +
64
+ "01/01/2015 | Get present | $10.00 ";
65
+
66
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
67
+ }
68
+
69
+ [Test]
70
+ public void Final_order_tie_breaker_is_change()
71
+ {
72
+ var currency = "USD";
73
+ var locale = "en-US";
74
+ var entries = new[]
75
+ {
76
+ Ledger.CreateEntry("2015-01-01", "Something", 0),
77
+ Ledger.CreateEntry("2015-01-01", "Something", -1),
78
+ Ledger.CreateEntry("2015-01-01", "Something", 1)
79
+ };
80
+ var expected =
81
+ "Date | Description | Change \n" +
82
+ "01/01/2015 | Something | ($0.01)\n" +
83
+ "01/01/2015 | Something | $0.00 \n" +
84
+ "01/01/2015 | Something | $0.01 ";
85
+
86
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
87
+ }
88
+
89
+ [Test]
90
+ public void Overlong_descriptions()
91
+ {
92
+ var currency = "USD";
93
+ var locale = "en-US";
94
+ var entries = new[]
95
+ {
96
+ Ledger.CreateEntry("2015-01-01", "Freude schoner Gotterfunken", -123456)
97
+ };
98
+ var expected =
99
+ "Date | Description | Change \n" +
100
+ "01/01/2015 | Freude schoner Gotterf... | ($1,234.56)";
101
+
102
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
103
+ }
104
+
105
+ [Test]
106
+ public void Euros()
107
+ {
108
+ var currency = "EUR";
109
+ var locale = "en-US";
110
+ var entries = new[]
111
+ {
112
+ Ledger.CreateEntry("2015-01-01", "Buy present", -1000)
113
+ };
114
+ var expected =
115
+ "Date | Description | Change \n" +
116
+ "01/01/2015 | Buy present | (€10.00)";
117
+
118
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
119
+ }
120
+
121
+ [Test]
122
+ public void Dutch_locale()
123
+ {
124
+ var currency = "USD";
125
+ var locale = "nl-NL";
126
+ var entries = new[]
127
+ {
128
+ Ledger.CreateEntry("2015-03-12", "Buy present", 123456)
129
+ };
130
+ var expected =
131
+ "Datum | Omschrijving | Verandering \n" +
132
+ "12-03-2015 | Buy present | $ 1.234,56 ";
133
+
134
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
135
+ }
136
+
137
+ [Test]
138
+ public void Dutch_negative_number_with_3_digits_before_decimal_point()
139
+ {
140
+ var currency = "USD";
141
+ var locale = "nl-NL";
142
+ var entries = new[]
143
+ {
144
+ Ledger.CreateEntry("2015-03-12", "Buy present", -12345)
145
+ };
146
+ var expected =
147
+ "Datum | Omschrijving | Verandering \n" +
148
+ "12-03-2015 | Buy present | $ -123,45";
149
+
150
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
151
+ }
152
+
153
+ [Test]
154
+ public void American_negative_number_with_3_digits_before_decimal_point()
155
+ {
156
+ var currency = "USD";
157
+ var locale = "en-US";
158
+ var entries = new[]
159
+ {
160
+ Ledger.CreateEntry("2015-03-12", "Buy present", -12345)
161
+ };
162
+ var expected =
163
+ "Date | Description | Change \n" +
164
+ "03/12/2015 | Buy present | ($123.45)";
165
+
166
+ Assert.That(Ledger.Format(currency, locale, entries), Is.EqualTo(expected));
167
+ }
168
+ }
@@ -75,9 +75,9 @@ defmodule AllergiesTest do
75
75
  set = Enum.into(list, MapSet.new)
76
76
  same_contents = to_contain
77
77
  |> Enum.into(MapSet.new)
78
- |> Set.equal?(set)
78
+ |> MapSet.equal?(set)
79
79
  assert same_contents,
80
- "Expected a set with: #{inspect to_contain} got #{inspect set |> Set.to_list}"
80
+ "Expected a set with: #{inspect to_contain} got #{inspect set |> MapSet.to_list}"
81
81
  end
82
82
 
83
83
  end
@@ -27,9 +27,9 @@ defmodule Markdown do
27
27
 
28
28
  defp process_md(text_with_md) do
29
29
  cond do
30
- String.starts_with?(text_with_md, "#") -> parse_header_md_level(text_with_md) |> enclose_with_header_tag
31
- String.starts_with?(text_with_md, "*") -> parse_list_md_level(text_with_md)
32
- true -> String.split(text_with_md) |> enclose_with_paragraph_tag
30
+ String.starts_with?(text_with_md, @header_md) -> parse_header_md_level(text_with_md) |> enclose_with_header_tag
31
+ String.starts_with?(text_with_md, @list_md) -> parse_list_md_level(text_with_md)
32
+ true -> String.split(text_with_md) |> enclose_with_paragraph_tag
33
33
  end
34
34
  end
35
35
 
@@ -3,8 +3,6 @@ defmodule Phone do
3
3
  Utilities to work with phone numbers.
4
4
  """
5
5
 
6
- @bad_result "0000000000"
7
-
8
6
  @doc """
9
7
  Clean up a phone number.
10
8
 
@@ -19,7 +19,7 @@ defmodule Queens do
19
19
  """
20
20
  @spec to_string(Queens.t()) :: String.t()
21
21
  def to_string(%Queens{ white: white, black: black }) do
22
- generate_board
22
+ generate_board()
23
23
  |> insert_queen(white, "W")
24
24
  |> insert_queen(black, "B")
25
25
  |> Enum.map(&Enum.join(&1, " "))
@@ -16,7 +16,7 @@ defmodule Wordy do
16
16
  end
17
17
 
18
18
  defp tokenize(sentence) do
19
- Regex.scan(~r/(#{all_matchers})/, sentence)
19
+ Regex.scan(~r/(#{all_matchers()})/, sentence)
20
20
  |> Enum.map(&(Enum.at(&1,0)))
21
21
  end
22
22
 
@@ -53,7 +53,7 @@ defmodule Wordy do
53
53
  end
54
54
 
55
55
  def match?(token) do
56
- String.match?(token,~r/#{matcher}/)
56
+ String.match?(token,~r/#{matcher()}/)
57
57
  end
58
58
 
59
59
  def parse(token) do
@@ -67,7 +67,7 @@ defmodule Wordy do
67
67
  end
68
68
 
69
69
  def match?(token) do
70
- String.match?(token,~r/#{matcher}/)
70
+ String.match?(token,~r/#{matcher()}/)
71
71
  end
72
72
 
73
73
  def parse(_) do
@@ -85,7 +85,7 @@ defmodule Wordy do
85
85
  end
86
86
 
87
87
  def match?(token) do
88
- String.match?(token,~r/#{matcher}/)
88
+ String.match?(token,~r/#{matcher()}/)
89
89
  end
90
90
 
91
91
  def parse(_) do
@@ -103,7 +103,7 @@ defmodule Wordy do
103
103
  end
104
104
 
105
105
  def match?(token) do
106
- String.match?(token,~r/#{matcher}/)
106
+ String.match?(token,~r/#{matcher()}/)
107
107
  end
108
108
 
109
109
  def parse(_) do
@@ -121,7 +121,7 @@ defmodule Wordy do
121
121
  end
122
122
 
123
123
  def match?(token) do
124
- String.match?(token,~r/#{matcher}/)
124
+ String.match?(token,~r/#{matcher()}/)
125
125
  end
126
126
 
127
127
  def parse(_) do
@@ -23,61 +23,61 @@ defmodule ZipperTest do
23
23
 
24
24
  # @tag :pending
25
25
  test "data is retained" do
26
- assert (t1 |> from_tree |> to_tree) == t1
26
+ assert (t1() |> from_tree |> to_tree) == t1()
27
27
  end
28
28
 
29
29
  @tag :pending
30
30
  test "left, right and value" do
31
- assert (t1 |> from_tree |> left |> right |> value) == 3
31
+ assert (t1() |> from_tree |> left |> right |> value) == 3
32
32
  end
33
33
 
34
34
  @tag :pending
35
35
  test "dead end" do
36
- assert (t1 |> from_tree |> left |> left) == nil
36
+ assert (t1() |> from_tree |> left |> left) == nil
37
37
  end
38
38
 
39
39
  @tag :pending
40
40
  test "tree from deep focus" do
41
- assert (t1 |> from_tree |> left |> right |> to_tree) == t1
41
+ assert (t1() |> from_tree |> left |> right |> to_tree) == t1()
42
42
  end
43
43
 
44
44
  @tag :pending
45
45
  test "traversing up from top" do
46
- assert (t1 |> from_tree |> up) == nil
46
+ assert (t1() |> from_tree |> up) == nil
47
47
  end
48
48
 
49
49
  @tag :pending
50
50
  test "left, right, and up" do
51
- assert (t1 |> from_tree |> left |> up |> right |> up |> left |> right |> value) == 3
51
+ assert (t1() |> from_tree |> left |> up |> right |> up |> left |> right |> value) == 3
52
52
  end
53
53
 
54
54
  @tag :pending
55
55
  test "set_value" do
56
- assert (t1 |> from_tree |> left |> set_value(5) |> to_tree) == t2
56
+ assert (t1() |> from_tree |> left |> set_value(5) |> to_tree) == t2()
57
57
  end
58
58
 
59
59
  @tag :pending
60
60
  test "set_value after traversing up" do
61
- assert (t1 |> from_tree |> left |> right |> up |> set_value(5) |> to_tree) == t2
61
+ assert (t1() |> from_tree |> left |> right |> up |> set_value(5) |> to_tree) == t2()
62
62
  end
63
63
 
64
64
  @tag :pending
65
65
  test "set_left with leaf" do
66
- assert (t1 |> from_tree |> left |> set_left(leaf(5)) |> to_tree) == t3
66
+ assert (t1() |> from_tree |> left |> set_left(leaf(5)) |> to_tree) == t3()
67
67
  end
68
68
 
69
69
  @tag :pending
70
70
  test "set_right with nil" do
71
- assert (t1 |> from_tree |> left |> set_right(nil) |> to_tree) == t4
71
+ assert (t1() |> from_tree |> left |> set_right(nil) |> to_tree) == t4()
72
72
  end
73
73
 
74
74
  @tag :pending
75
75
  test "set_right with subtree" do
76
- assert (t1 |> from_tree |> set_right(bt(6, leaf(7), leaf(8))) |> to_tree) == t5
76
+ assert (t1() |> from_tree |> set_right(bt(6, leaf(7), leaf(8))) |> to_tree) == t5()
77
77
  end
78
78
 
79
79
  @tag :pending
80
80
  test "set_value on deep focus" do
81
- assert (t1 |> from_tree |> left |> right |> set_value(5) |> to_tree) == t6
81
+ assert (t1() |> from_tree |> left |> right |> set_value(5) |> to_tree) == t6()
82
82
  end
83
83
  end
@@ -5,7 +5,7 @@ defmodule ExercismTestRunner.Mixfile do
5
5
  [app: :tests,
6
6
  version: "0.0.1",
7
7
  elixir: "~> 1.3",
8
- deps: deps,
8
+ deps: deps(),
9
9
  test_paths: ["exercises"],
10
10
  consolidate_protocols: false]
11
11
  end
@@ -803,6 +803,14 @@
803
803
  "Transforming"
804
804
  ]
805
805
  },
806
+ {
807
+ "slug": "alphametics",
808
+ "difficulty": 9,
809
+ "topics": [
810
+ "Parsing",
811
+ "Maps"
812
+ ]
813
+ },
806
814
  {
807
815
  "slug": "zipper",
808
816
  "difficulty": 10,
@@ -828,14 +836,6 @@
828
836
  "Recursion",
829
837
  "Searching"
830
838
  ]
831
- },
832
- {
833
- "slug": "alphametics",
834
- "difficulty": 10,
835
- "topics": [
836
- "Parsing",
837
- "Maps"
838
- ]
839
839
  }
840
840
  ],
841
841
  "deprecated": [
@@ -1 +1,5 @@
1
1
  [F#](http://www.tryfsharp.org/Explore) is a strongly-typed, functional language that is part of Microsoft's .NET language stack.
2
+
3
+ Although F# is great for data science problems, it can elegantly handle almost every problem you throw at it. As F# runs on the .NET runtime, you get access to the entire .NET ecosystem, including all packages on [nuget.org](https://www.nuget.org/). This integration is further simplified due to F# also allowing you to write object-oriented code.
4
+
5
+ The home page for F# is [fsharp.org](http://fsharp.org/). A great introduction to F# can be found at the [F# for fun and profit](http://fsharpforfunandprofit.com/) website.