trackler 2.2.1.53 → 2.2.1.54

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/nth-prime/canonical-data.json +2 -7
  4. data/problem-specifications/exercises/zebra-puzzle/canonical-data.json +16 -0
  5. data/tracks/c/config.json +11 -1
  6. data/tracks/c/docs/C_STYLE_GUIDE.md +142 -0
  7. data/tracks/c/exercises/collatz-conjecture/README.md +65 -0
  8. data/tracks/c/exercises/collatz-conjecture/makefile +15 -0
  9. data/tracks/c/exercises/collatz-conjecture/src/collatz_conjecture.h +8 -0
  10. data/tracks/c/exercises/collatz-conjecture/src/example.c +23 -0
  11. data/tracks/c/exercises/collatz-conjecture/test/test_collatz_conjecture.c +48 -0
  12. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.c +1300 -0
  13. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.h +274 -0
  14. data/tracks/c/exercises/collatz-conjecture/test/vendor/unity_internals.h +701 -0
  15. data/tracks/cfml/tasks/GenerateReadme.cfc +5 -5
  16. data/tracks/erlang/testgen/src/testgen.erl +99 -17
  17. data/tracks/erlang/testgen/src/tg_file_tools.erl +3 -3
  18. data/tracks/erlang/testgen/src/tgen.erl +15 -7
  19. data/tracks/haskell/config.json +15 -3
  20. data/tracks/java/scripts/canonical_data_check.sh +1 -1
  21. data/tracks/javascript/config.json +12 -0
  22. data/tracks/javascript/exercises/difference-of-squares/README.md +1 -1
  23. data/tracks/javascript/exercises/sum-of-multiples/README.md +1 -1
  24. data/tracks/javascript/exercises/zipper/README.md +55 -0
  25. data/tracks/javascript/exercises/zipper/example.js +100 -0
  26. data/tracks/javascript/exercises/zipper/zipper.spec.js +77 -0
  27. data/tracks/julia/config.json +12 -0
  28. data/tracks/julia/exercises/triangle/README.md +30 -0
  29. data/tracks/julia/exercises/triangle/example.jl +25 -0
  30. data/tracks/julia/exercises/triangle/runtests.jl +64 -0
  31. data/tracks/julia/exercises/triangle/triangle.jl +8 -0
  32. data/tracks/kotlin/exercises/leap/.meta/version +1 -1
  33. data/tracks/kotlin/exercises/leap/src/test/kotlin/LeapTest.kt +1 -1
  34. data/tracks/kotlin/scripts/canonical_data_check.sh +1 -1
  35. data/tracks/perl6/bin/README.md +1 -4
  36. data/tracks/perl6/bin/exercise-gen.pl6 +3 -4
  37. data/tracks/perl6/exercises/accumulate/example.yaml +2 -2
  38. data/tracks/perl6/exercises/all-your-base/example.yaml +9 -9
  39. data/tracks/perl6/exercises/allergies/example.yaml +7 -7
  40. data/tracks/perl6/exercises/anagram/example.yaml +3 -3
  41. data/tracks/perl6/exercises/atbash-cipher/example.yaml +3 -3
  42. data/tracks/perl6/exercises/bob/example.yaml +4 -4
  43. data/tracks/perl6/exercises/clock/example.yaml +6 -6
  44. data/tracks/perl6/exercises/flatten-array/example.yaml +4 -4
  45. data/tracks/perl6/exercises/grade-school/example.yaml +6 -6
  46. data/tracks/perl6/exercises/grains/example.yaml +3 -3
  47. data/tracks/perl6/exercises/hello-world/example.yaml +5 -5
  48. data/tracks/perl6/exercises/leap/example.yaml +4 -4
  49. data/tracks/perl6/exercises/linked-list/example.yaml +14 -14
  50. data/tracks/perl6/exercises/luhn/example.yaml +3 -3
  51. data/tracks/perl6/exercises/phone-number/example.yaml +3 -3
  52. data/tracks/perl6/exercises/raindrops/example.yaml +3 -3
  53. data/tracks/perl6/exercises/rna-transcription/example.yaml +3 -3
  54. data/tracks/perl6/exercises/robot-name/example.yaml +8 -8
  55. data/tracks/perl6/exercises/scrabble-score/example.yaml +3 -3
  56. data/tracks/perl6/exercises/space-age/example.yaml +8 -8
  57. data/tracks/perl6/exercises/word-count/example.yaml +3 -3
  58. data/tracks/perl6/exercises/wordy/example.yaml +3 -3
  59. data/tracks/python/config.json +14 -0
  60. data/tracks/python/config/maintainers.json +30 -0
  61. data/tracks/python/docs/EXERCISE_README_INSERT.md +1 -2
  62. data/tracks/python/exercises/accumulate/README.md +1 -5
  63. data/tracks/python/exercises/acronym/README.md +1 -3
  64. data/tracks/python/exercises/all-your-base/README.md +2 -3
  65. data/tracks/python/exercises/all-your-base/all_your_base_test.py +13 -13
  66. data/tracks/python/exercises/allergies/README.md +1 -3
  67. data/tracks/python/exercises/alphametics/README.md +3 -4
  68. data/tracks/python/exercises/anagram/README.md +1 -2
  69. data/tracks/python/exercises/atbash-cipher/README.md +3 -3
  70. data/tracks/python/exercises/beer-song/README.md +2 -3
  71. data/tracks/python/exercises/binary-search/README.md +1 -2
  72. data/tracks/python/exercises/binary/README.md +3 -2
  73. data/tracks/python/exercises/bob/README.md +1 -2
  74. data/tracks/python/exercises/book-store/README.md +6 -7
  75. data/tracks/python/exercises/bracket-push/README.md +1 -2
  76. data/tracks/python/exercises/change/README.md +2 -3
  77. data/tracks/python/exercises/circular-buffer/README.md +14 -8
  78. data/tracks/python/exercises/clock/README.md +1 -2
  79. data/tracks/python/exercises/clock/clock_test.py +2 -0
  80. data/tracks/python/exercises/collatz-conjecture/.meta/hints.md +3 -0
  81. data/tracks/python/exercises/collatz-conjecture/README.md +6 -19
  82. data/tracks/python/exercises/complex-numbers/README.md +28 -2
  83. data/tracks/python/exercises/crypto-square/README.md +11 -10
  84. data/tracks/python/exercises/diamond/README.md +7 -8
  85. data/tracks/python/exercises/difference-of-squares/README.md +1 -2
  86. data/tracks/python/exercises/diffie-hellman/.meta/hints.md +1 -1
  87. data/tracks/python/exercises/diffie-hellman/README.md +3 -2
  88. data/tracks/python/exercises/error-handling/.meta/hints.md +8 -0
  89. data/tracks/python/exercises/error-handling/README.md +10 -2
  90. data/tracks/python/exercises/error-handling/error_handling_test.py +15 -3
  91. data/tracks/python/exercises/etl/README.md +3 -2
  92. data/tracks/python/exercises/flatten-array/README.md +2 -4
  93. data/tracks/python/exercises/food-chain/README.md +3 -4
  94. data/tracks/python/exercises/forth/README.md +2 -6
  95. data/tracks/python/exercises/gigasecond/README.md +1 -2
  96. data/tracks/python/exercises/grade-school/README.md +1 -3
  97. data/tracks/python/exercises/grains/README.md +1 -3
  98. data/tracks/python/exercises/grep/README.md +13 -14
  99. data/tracks/python/exercises/hamming/README.md +1 -2
  100. data/tracks/python/exercises/hamming/hamming_test.py +6 -6
  101. data/tracks/python/exercises/hello-world/README.md +1 -2
  102. data/tracks/python/exercises/hexadecimal/README.md +1 -2
  103. data/tracks/python/exercises/hexadecimal/example.py +6 -6
  104. data/tracks/python/exercises/house/README.md +2 -4
  105. data/tracks/python/exercises/isogram/README.md +3 -3
  106. data/tracks/python/exercises/kindergarten-garden/README.md +14 -15
  107. data/tracks/python/exercises/largest-series-product/README.md +1 -2
  108. data/tracks/python/exercises/leap/README.md +2 -3
  109. data/tracks/python/exercises/linked-list/README.md +11 -12
  110. data/tracks/python/exercises/list-ops/README.md +1 -2
  111. data/tracks/python/exercises/luhn/README.md +8 -9
  112. data/tracks/python/exercises/markdown/README.md +1 -6
  113. data/tracks/python/exercises/matrix/README.md +7 -6
  114. data/tracks/python/exercises/meetup/README.md +2 -4
  115. data/tracks/python/exercises/minesweeper/README.md +1 -2
  116. data/tracks/python/exercises/nth-prime/README.md +1 -2
  117. data/tracks/python/exercises/nucleotide-count/README.md +9 -24
  118. data/tracks/python/exercises/ocr-numbers/README.md +6 -7
  119. data/tracks/python/exercises/octal/README.md +7 -4
  120. data/tracks/python/exercises/palindrome-products/README.md +16 -18
  121. data/tracks/python/exercises/pangram/README.md +2 -3
  122. data/tracks/python/exercises/pascals-triangle/README.md +2 -3
  123. data/tracks/python/exercises/perfect-numbers/README.md +3 -4
  124. data/tracks/python/exercises/phone-number/README.md +4 -4
  125. data/tracks/python/exercises/pig-latin/README.md +1 -2
  126. data/tracks/python/exercises/point-mutations/README.md +1 -2
  127. data/tracks/python/exercises/poker/README.md +1 -2
  128. data/tracks/python/exercises/prime-factors/README.md +1 -2
  129. data/tracks/python/exercises/protein-translation/README.md +5 -7
  130. data/tracks/python/exercises/proverb/README.md +12 -11
  131. data/tracks/python/exercises/pythagorean-triplet/README.md +4 -5
  132. data/tracks/python/exercises/queen-attack/README.md +2 -3
  133. data/tracks/python/exercises/rail-fence-cipher/README.md +13 -9
  134. data/tracks/python/exercises/raindrops/README.md +1 -2
  135. data/tracks/python/exercises/rectangles/README.md +8 -9
  136. data/tracks/python/exercises/rectangles/example.py +3 -3
  137. data/tracks/python/exercises/rna-transcription/README.md +1 -2
  138. data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +4 -3
  139. data/tracks/python/exercises/robot-name/README.md +1 -2
  140. data/tracks/python/exercises/robot-simulator/README.md +1 -2
  141. data/tracks/python/exercises/roman-numerals/README.md +2 -3
  142. data/tracks/python/exercises/rotational-cipher/README.md +3 -3
  143. data/tracks/python/exercises/run-length-encoding/README.md +5 -6
  144. data/tracks/python/exercises/run-length-encoding/example.py +2 -2
  145. data/tracks/python/exercises/saddle-points/README.md +2 -3
  146. data/tracks/python/exercises/say/README.md +1 -2
  147. data/tracks/python/exercises/scale-generator/README.md +1 -3
  148. data/tracks/python/exercises/scrabble-score/README.md +4 -3
  149. data/tracks/python/exercises/secret-handshake/README.md +2 -3
  150. data/tracks/python/exercises/series/README.md +1 -2
  151. data/tracks/python/exercises/sieve/README.md +1 -2
  152. data/tracks/python/exercises/simple-cipher/README.md +3 -4
  153. data/tracks/python/exercises/space-age/README.md +2 -3
  154. data/tracks/python/exercises/space-age/space_age_test.py +18 -29
  155. data/tracks/python/exercises/strain/README.md +1 -2
  156. data/tracks/python/exercises/sublist/README.md +1 -2
  157. data/tracks/python/exercises/sum-of-multiples/README.md +1 -5
  158. data/tracks/python/exercises/tournament/README.md +6 -7
  159. data/tracks/python/exercises/transpose/README.md +8 -9
  160. data/tracks/python/exercises/tree-building/README.md +25 -0
  161. data/tracks/python/exercises/tree-building/example.py +46 -0
  162. data/tracks/python/exercises/tree-building/tree_building.py +50 -0
  163. data/tracks/python/exercises/tree-building/tree_building_test.py +183 -0
  164. data/tracks/python/exercises/triangle/README.md +10 -8
  165. data/tracks/python/exercises/trinary/README.md +2 -3
  166. data/tracks/python/exercises/twelve-days/README.md +2 -3
  167. data/tracks/python/exercises/two-bucket/README.md +4 -5
  168. data/tracks/python/exercises/two-bucket/two_bucket_test.py +2 -0
  169. data/tracks/python/exercises/two-fer/README.md +4 -5
  170. data/tracks/python/exercises/two-fer/two_fer_test.py +5 -2
  171. data/tracks/python/exercises/variable-length-quantity/README.md +7 -9
  172. data/tracks/python/exercises/word-count/README.md +2 -4
  173. data/tracks/python/exercises/word-search/README.md +2 -3
  174. data/tracks/python/exercises/wordy/README.md +1 -7
  175. data/tracks/python/exercises/wordy/example.py +8 -8
  176. data/tracks/python/exercises/wordy/wordy_test.py +36 -32
  177. data/tracks/python/exercises/zebra-puzzle/README.md +1 -2
  178. data/tracks/python/requirements-travis.txt +1 -1
  179. data/tracks/ruby/config.json +11 -0
  180. data/tracks/ruby/docs/TESTS.md +6 -0
  181. data/tracks/ruby/exercises/pangram/.meta/.version +1 -1
  182. data/tracks/ruby/exercises/pangram/.meta/solutions/pangram.rb +1 -1
  183. data/tracks/ruby/exercises/pangram/pangram_test.rb +11 -4
  184. data/tracks/ruby/exercises/two-fer/.meta/.version +1 -0
  185. data/tracks/ruby/exercises/two-fer/.meta/generator/two_fer_case.rb +12 -0
  186. data/tracks/ruby/exercises/two-fer/.meta/solutions/two_fer.rb +9 -0
  187. data/tracks/ruby/exercises/two-fer/README.md +69 -0
  188. data/tracks/ruby/exercises/two-fer/two_fer_test.rb +42 -0
  189. data/tracks/rust/config.json +12 -0
  190. data/tracks/rust/exercises/binary-search/.meta/hints.md +38 -0
  191. data/tracks/rust/exercises/binary-search/Cargo.lock +4 -0
  192. data/tracks/rust/exercises/binary-search/Cargo.toml +6 -0
  193. data/tracks/rust/exercises/binary-search/README.md +113 -0
  194. data/tracks/rust/exercises/binary-search/example.rs +29 -0
  195. data/tracks/rust/exercises/binary-search/src/lib.rs +0 -0
  196. data/tracks/rust/exercises/binary-search/tests/binary-search.rs +96 -0
  197. data/tracks/typescript/common/package.json +6 -6
  198. data/tracks/typescript/common/yarn.lock +929 -610
  199. data/tracks/typescript/exercises/acronym/package.json +6 -6
  200. data/tracks/typescript/exercises/acronym/yarn.lock +929 -610
  201. data/tracks/typescript/exercises/anagram/package.json +6 -6
  202. data/tracks/typescript/exercises/anagram/yarn.lock +929 -610
  203. data/tracks/typescript/exercises/beer-song/package.json +6 -6
  204. data/tracks/typescript/exercises/beer-song/yarn.lock +929 -610
  205. data/tracks/typescript/exercises/binary-search-tree/package.json +6 -6
  206. data/tracks/typescript/exercises/binary-search-tree/yarn.lock +929 -610
  207. data/tracks/typescript/exercises/binary-search/package.json +6 -6
  208. data/tracks/typescript/exercises/binary-search/yarn.lock +929 -610
  209. data/tracks/typescript/exercises/bob/package.json +6 -6
  210. data/tracks/typescript/exercises/bob/yarn.lock +929 -610
  211. data/tracks/typescript/exercises/circular-buffer/package.json +6 -6
  212. data/tracks/typescript/exercises/circular-buffer/yarn.lock +929 -610
  213. data/tracks/typescript/exercises/clock/package.json +6 -6
  214. data/tracks/typescript/exercises/clock/yarn.lock +929 -610
  215. data/tracks/typescript/exercises/difference-of-squares/package.json +6 -6
  216. data/tracks/typescript/exercises/difference-of-squares/yarn.lock +929 -610
  217. data/tracks/typescript/exercises/etl/package.json +6 -6
  218. data/tracks/typescript/exercises/etl/yarn.lock +929 -610
  219. data/tracks/typescript/exercises/food-chain/package.json +6 -6
  220. data/tracks/typescript/exercises/food-chain/yarn.lock +929 -610
  221. data/tracks/typescript/exercises/gigasecond/package.json +6 -6
  222. data/tracks/typescript/exercises/gigasecond/yarn.lock +929 -610
  223. data/tracks/typescript/exercises/grade-school/package.json +6 -6
  224. data/tracks/typescript/exercises/grade-school/yarn.lock +929 -610
  225. data/tracks/typescript/exercises/hamming/package.json +6 -6
  226. data/tracks/typescript/exercises/hamming/yarn.lock +929 -610
  227. data/tracks/typescript/exercises/hello-world/README.md +354 -0
  228. data/tracks/typescript/exercises/hello-world/package.json +6 -6
  229. data/tracks/typescript/exercises/hello-world/yarn.lock +929 -610
  230. data/tracks/typescript/exercises/largest-series-product/package.json +6 -6
  231. data/tracks/typescript/exercises/largest-series-product/yarn.lock +929 -610
  232. data/tracks/typescript/exercises/leap/package.json +6 -6
  233. data/tracks/typescript/exercises/leap/yarn.lock +929 -610
  234. data/tracks/typescript/exercises/linked-list/package.json +6 -6
  235. data/tracks/typescript/exercises/linked-list/yarn.lock +929 -610
  236. data/tracks/typescript/exercises/nth-prime/package.json +6 -6
  237. data/tracks/typescript/exercises/nth-prime/yarn.lock +929 -610
  238. data/tracks/typescript/exercises/pangram/package.json +6 -6
  239. data/tracks/typescript/exercises/pangram/yarn.lock +929 -610
  240. data/tracks/typescript/exercises/pascals-triangle/package.json +6 -6
  241. data/tracks/typescript/exercises/pascals-triangle/yarn.lock +929 -610
  242. data/tracks/typescript/exercises/phone-number/package.json +6 -6
  243. data/tracks/typescript/exercises/phone-number/yarn.lock +929 -610
  244. data/tracks/typescript/exercises/prime-factors/package.json +6 -6
  245. data/tracks/typescript/exercises/prime-factors/yarn.lock +929 -610
  246. data/tracks/typescript/exercises/raindrops/package.json +6 -6
  247. data/tracks/typescript/exercises/raindrops/yarn.lock +929 -610
  248. data/tracks/typescript/exercises/rna-transcription/package.json +6 -6
  249. data/tracks/typescript/exercises/rna-transcription/yarn.lock +929 -610
  250. data/tracks/typescript/exercises/robot-name/package.json +6 -6
  251. data/tracks/typescript/exercises/robot-name/yarn.lock +929 -610
  252. data/tracks/typescript/exercises/robot-simulator/package.json +6 -6
  253. data/tracks/typescript/exercises/robot-simulator/yarn.lock +929 -610
  254. data/tracks/typescript/exercises/rotational-cipher/package.json +6 -6
  255. data/tracks/typescript/exercises/rotational-cipher/yarn.lock +929 -610
  256. data/tracks/typescript/exercises/say/package.json +6 -6
  257. data/tracks/typescript/exercises/say/yarn.lock +929 -610
  258. data/tracks/typescript/exercises/scrabble-score/package.json +6 -6
  259. data/tracks/typescript/exercises/scrabble-score/yarn.lock +929 -610
  260. data/tracks/typescript/exercises/series/package.json +6 -6
  261. data/tracks/typescript/exercises/series/yarn.lock +929 -610
  262. data/tracks/typescript/exercises/space-age/package.json +6 -6
  263. data/tracks/typescript/exercises/space-age/yarn.lock +929 -610
  264. data/tracks/typescript/exercises/strain/package.json +6 -6
  265. data/tracks/typescript/exercises/strain/yarn.lock +929 -610
  266. data/tracks/typescript/exercises/sum-of-multiples/package.json +6 -6
  267. data/tracks/typescript/exercises/sum-of-multiples/yarn.lock +929 -610
  268. data/tracks/typescript/exercises/triangle/package.json +6 -6
  269. data/tracks/typescript/exercises/triangle/yarn.lock +929 -610
  270. data/tracks/typescript/exercises/word-count/package.json +6 -6
  271. data/tracks/typescript/exercises/word-count/yarn.lock +929 -610
  272. data/tracks/typescript/exercises/wordy/package.json +6 -6
  273. data/tracks/typescript/exercises/wordy/yarn.lock +929 -610
  274. metadata +37 -2
@@ -15,7 +15,7 @@ component {
15
15
  /* Init global variables */
16
16
  repoRootPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../' );
17
17
  problemSpecsPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../../problem-specifications' );
18
- trackReadmeInsert= fileRead( repoRootPath & "docs/EXERCISE_README_INSERT.md" );
18
+ trackReadmeInsert= fileRead( repoRootPath & "docs/EXERCISE_README_INSERT.md", "utf-8" );
19
19
  overwriteExistingFiles = arguments.force;
20
20
 
21
21
  if( !directoryExists( problemSpecsPath ) ){
@@ -65,7 +65,7 @@ component {
65
65
  readmeContent = readmeContent & "#### Submitting Incomplete Solutions#chr( 10 )#It's possible to submit an incomplete solution so you can see how others have completed the exercise.#chr( 10 )#";
66
66
 
67
67
  /* Write the file */
68
- fileWrite( readMeFile , readmeContent );
68
+ fileWrite( readMeFile , readmeContent, "utf-8" );
69
69
 
70
70
  print.greenLine( 'Readme generated!' )
71
71
  .indentedYellowLine( readMeFile )
@@ -87,7 +87,7 @@ component {
87
87
  private function getHints( required string slug ) {
88
88
 
89
89
  var hintsFilePath = repoRootPath & "/exercises/" & arguments.slug & "/.meta/hints.md";
90
- var hints = fileExists( hintsFilePath ) ? fileRead( hintsFilePath ) : "";
90
+ var hints = fileExists( hintsFilePath ) ? fileRead( hintsFilePath, "utf-8" ) : "";
91
91
 
92
92
  return hints;
93
93
  }
@@ -119,7 +119,7 @@ component {
119
119
 
120
120
  var descriptionFilePath = problemSpecsPath & "/exercises/" & arguments.slug & "/description.md";
121
121
 
122
- return fileExists( descriptionFilePath ) ? trim( fileRead( descriptionFilePath ) ) : "";
122
+ return fileExists( descriptionFilePath ) ? trim( fileRead( descriptionFilePath, "utf-8" ) ) : "";
123
123
  }
124
124
 
125
125
  /**
@@ -163,7 +163,7 @@ component {
163
163
  private struct function getExerciseMetadata( required string slug ) {
164
164
 
165
165
  var metadataFilePath = problemSpecsPath & "/exercises/" & arguments.slug & "/metadata.yml";
166
- var content = fileRead(metadataFilePath);
166
+ var content = fileRead( metadataFilePath , "utf-8");
167
167
  var metadata = {};
168
168
 
169
169
  /* Get the title if provided in metadata.yml */
@@ -10,26 +10,103 @@
10
10
  %%====================================================================
11
11
 
12
12
  %% escript Entry point
13
- main([]) ->
14
- io:format("Searching for git basedir~n"),
15
- {ok, PWD} = file:get_cwd(),
16
- case tg_git_tools:find_git(PWD) of
17
- {ok, GitDir} -> main([GitDir]);
18
- error -> io:format("No git basedir found, please specifiy manually~n")
19
- end;
20
- main([GitPath]) ->
21
- io:format("Using ~s as basepath~n", [GitPath]),
22
- SpecFiles0 = filelib:wildcard("canonical_data/exercises/*/canonical-data.json", GitPath),
23
- SpecFiles1 = lists:filtermap(fun filter_by_generator_and_create_record/1, SpecFiles0),
24
- SpecFiles2 = lists:map(fun(TGen) -> TGen#tgen{path = GitPath ++ "/" ++ TGen#tgen.path, dest = GitPath ++ "/exercises/" ++ TGen#tgen.name} end, SpecFiles1),
25
- lists:map(fun tgen:generate/1, SpecFiles2).
13
+ main(Args) ->
14
+ Config = process_args(Args, #{}),
15
+ execute(Config).
26
16
 
27
17
  %%====================================================================
28
18
  %% Internal functions
29
19
  %%====================================================================
30
20
 
31
- filter_by_generator_and_create_record(Path) ->
32
- Name = tg_file_tools:extract_name(Path),
21
+ process_args([], Config = #{path := _, spec_path := _, out_path := _}) ->
22
+ case maps:is_key(exercises, Config) of
23
+ false -> maps:put(exercises, all, Config);
24
+ true -> Config
25
+ end;
26
+ process_args([], Config = #{path := Path}) ->
27
+ Config1 = case maps:is_key(spec_path, Config) of
28
+ false -> maps:put(spec_path, iolist_to_binary([Path, "/canonical_data/exercises"]), Config);
29
+ true -> Config
30
+ end,
31
+
32
+ Config2 = case maps:is_key(out_path, Config1) of
33
+ false -> maps:put(out_path, iolist_to_binary([Path, "/exercises"]), Config1);
34
+ true -> Config1
35
+ end,
36
+
37
+ process_args([], Config2);
38
+ process_args([], Config) ->
39
+ Config1 = case maps:is_key(path, Config) and not (maps:is_key(out_path, Config) or maps:is_key(spec_path, Config)) of
40
+ false -> maps:put(path, search_git_upwards(), Config);
41
+ true -> Config
42
+ end,
43
+
44
+ Config2 = case maps:is_key(command, Config1) of
45
+ false -> maps:put(command, "generate", Config1);
46
+ true -> Config1
47
+ end,
48
+
49
+ process_args([], Config2);
50
+ process_args(["--path", Path|Args], Config) ->
51
+ process_args(Args, maps:put(path, Path, Config));
52
+ process_args(["--spec-path", SpecPath|Args], Config) ->
53
+ process_args(Args, maps:put(spec_path, SpecPath, Config));
54
+ process_args(["--out-path", OutPath|Args], Config) ->
55
+ process_args(Args, maps:put(out_path, OutPath, Config));
56
+ process_args([Arg|Args], Config) ->
57
+ Config1 = case maps:is_key(command, Config) of
58
+ false ->
59
+ maps:put(command, Arg, Config);
60
+ true ->
61
+ maps:update_with(exercises, fun(Tail) -> [Arg|Tail] end, [Arg], Config)
62
+ end,
63
+ process_args(Args, Config1).
64
+
65
+ search_git_upwards() ->
66
+ {ok, PWD} = file:get_cwd(),
67
+ case tg_git_tools:find_git(PWD) of
68
+ {ok, GitDir} -> GitDir;
69
+ error -> error
70
+ end.
71
+
72
+ execute(Config = #{command := "generate", spec_path := SpecPath, exercises := all}) ->
73
+ SpecFiles = filelib:wildcard("*/canonical-data.json", binary_to_list(SpecPath)),
74
+ Exercises = lists:map(fun tg_file_tools:extract_name/1, SpecFiles),
75
+ put(log_unavailable, false), % TODO: Get rid of the use of the process dictionary!
76
+ execute(maps:put(exercises, Exercises, Config));
77
+ execute(#{command := "generate", spec_path := SpecPath, out_path := OutPath, exercises := [_|_] = Exercises}) ->
78
+ case get(log_unavailable) of % TODO: Get rid of the use of the process dictionary!
79
+ undefined -> put(log_unavailable, true);
80
+ _ -> ok
81
+ end,
82
+ SpecFiles = lists:map(fun (Exercise) -> {Exercise, iolist_to_binary([SpecPath, $/, Exercise, "/canonical-data.json"])} end, Exercises),
83
+ Generators0 = lists:filtermap(fun filter_by_generator_and_create_record/1, SpecFiles),
84
+ Generators1 = lists:map(fun (Generator) -> Generator#tgen{dest = iolist_to_binary([OutPath, $/, Generator#tgen.name])} end, Generators0),
85
+ Contents = lists:map(fun tgen:generate/1, Generators1),
86
+ lists:map(
87
+ fun
88
+ (#{name := Name, impl := Impl, path := Path}) ->
89
+ io:format("Writing ~s", [Name]),
90
+ case file:open(Path, [write]) of
91
+ {ok, IODevice} ->
92
+ io:format(IODevice, "~s", [Impl]),
93
+ file:close(IODevice),
94
+ io:format(", finished~n");
95
+ {error, Reason} ->
96
+ io:format("Can not open ~p for writing because of ~p.~n", [Path, Reason])
97
+ end;
98
+ ({error, Reason, Path}) ->
99
+ io:format("Can not open ~p for reading because of ~p.~n", [Path, Reason])
100
+ end, Contents);
101
+ execute(#{command := "check"}) ->
102
+ io:format("This command has not been implemented yet");
103
+ execute(#{command := "help"}) ->
104
+ io:format("This command has not been implemented yet");
105
+ execute(_) ->
106
+ io:format("Unknown command. Only generate is available right now.").
107
+
108
+
109
+ filter_by_generator_and_create_record({Name, Path}) ->
33
110
  case tgen:check(Name) of
34
111
  {true, Module} ->
35
112
  {true, #tgen{
@@ -37,5 +114,10 @@ filter_by_generator_and_create_record(Path) ->
37
114
  name = Name,
38
115
  path = Path
39
116
  }};
40
- _ -> false
41
- end.
117
+ _ ->
118
+ case get(log_unavailable) of
119
+ true -> io:format("No generator for '~s' available~n", [Name]);
120
+ _ -> ok
121
+ end,
122
+ false
123
+ end.
@@ -5,10 +5,10 @@
5
5
  parent_dir/1
6
6
  ]).
7
7
 
8
- extract_name("canonical_data/exercises/" ++ Rest) ->
9
- lists:takewhile(fun(C) -> not lists:member(C, [$/, $\\]) end, Rest).
8
+ extract_name(Name) ->
9
+ lists:takewhile(fun(C) -> not lists:member(C, [$/, $\\]) end, Name).
10
10
 
11
11
  parent_dir(Dir) ->
12
12
  DirRev0 = lists:reverse(Dir),
13
13
  DirRev1 = lists:dropwhile(fun(C) -> not lists:member(C, [$/, $\\]) end, DirRev0),
14
- lists:reverse(tl(DirRev1)).
14
+ lists:reverse(tl(DirRev1)).
@@ -44,15 +44,23 @@ check(Name) ->
44
44
  _:_ -> false
45
45
  end.
46
46
 
47
- -spec generate(tgen()) -> ok.
47
+ -spec generate(tgen()) -> ok.
48
48
  generate(Generator = #tgen{}) ->
49
- io:format("Generating ~s~n", [Generator#tgen.name]),
49
+ io:format("Generating ~s", [Generator#tgen.name]),
50
50
  case file:read_file(Generator#tgen.path) of
51
51
  {ok, Content} ->
52
52
  {ModName, TestModule} = process_json(Generator, Content),
53
- {ok, IODevice} = file:open([Generator#tgen.dest, "/test/", ModName, ".erl"], [write]),
54
- io:format(IODevice, "~s", [TestModule]),
55
- file:close(IODevice)
53
+ TestfilePath = iolist_to_binary([Generator#tgen.dest, "/test/", ModName, ".erl"]),
54
+ io:format(", finished~n"),
55
+ #{
56
+ name => Generator#tgen.name,
57
+ module => ModName,
58
+ impl => TestModule,
59
+ path => TestfilePath
60
+ };
61
+ {error, Reason} ->
62
+ io:format(", failed (~p)~n", [Reason]),
63
+ {error, Reason, Generator#tgen.path}
56
64
  end.
57
65
 
58
66
  process_json(G = #tgen{name = GName}, Content) when is_list(GName) ->
@@ -66,7 +74,7 @@ process_json(#tgen{name = GName, module = Module}, Content) ->
66
74
  {[Test|Tests], NewState}
67
75
  end, {[], undefined}, Cases),
68
76
  {ModuleName, ModuleContent} = generate_module(binary_to_list(GName), TestImpls, Module:version(undefined)), % TODO: Read version dynamically and pass as Integer!
69
-
77
+
70
78
  {ModuleName, io_lib:format("~s", [ModuleContent])};
71
79
  #{exercise := Name} ->
72
80
  io:format("Name in JSON (~p) and name for generator (~p) do not line up", [Name, GName])
@@ -123,4 +131,4 @@ generate_module(ModuleName, Tests, Version) ->
123
131
 
124
132
  inter(_, []) -> [];
125
133
  inter(_, [X]) -> [X];
126
- inter(Delim, [X|Xs]) -> [X, Delim|Xs].
134
+ inter(Delim, [X|Xs]) -> [X, Delim|Xs].
@@ -65,7 +65,8 @@
65
65
  "unlocked_by": null,
66
66
  "difficulty": 1,
67
67
  "topics": [
68
- "Maybe"
68
+ "Maybe",
69
+ "Number Theory"
69
70
  ]
70
71
  },
71
72
  {
@@ -103,6 +104,7 @@
103
104
  "unlocked_by": null,
104
105
  "difficulty": 1,
105
106
  "topics": [
107
+ "Number Theory"
106
108
  ]
107
109
  },
108
110
  {
@@ -112,6 +114,7 @@
112
114
  "unlocked_by": null,
113
115
  "difficulty": 1,
114
116
  "topics": [
117
+ "Number Theory"
115
118
  ]
116
119
  },
117
120
  {
@@ -130,6 +133,8 @@
130
133
  "unlocked_by": null,
131
134
  "difficulty": 2,
132
135
  "topics": [
136
+ "Define type",
137
+ "Number Theory"
133
138
  ]
134
139
  },
135
140
  {
@@ -139,7 +144,8 @@
139
144
  "unlocked_by": null,
140
145
  "difficulty": 2,
141
146
  "topics": [
142
- "Maybe"
147
+ "Maybe",
148
+ "Number Theory"
143
149
  ]
144
150
  },
145
151
  {
@@ -248,6 +254,7 @@
248
254
  "unlocked_by": null,
249
255
  "difficulty": 3,
250
256
  "topics": [
257
+ "Number Theory"
251
258
  ]
252
259
  },
253
260
  {
@@ -344,6 +351,7 @@
344
351
  "unlocked_by": null,
345
352
  "difficulty": 4,
346
353
  "topics": [
354
+ "Number Theory"
347
355
  ]
348
356
  },
349
357
  {
@@ -413,6 +421,7 @@
413
421
  "unlocked_by": null,
414
422
  "difficulty": 4,
415
423
  "topics": [
424
+ "Number Theory"
416
425
  ]
417
426
  },
418
427
  {
@@ -422,6 +431,7 @@
422
431
  "unlocked_by": null,
423
432
  "difficulty": 4,
424
433
  "topics": [
434
+ "Number Theory"
425
435
  ]
426
436
  },
427
437
  {
@@ -449,6 +459,7 @@
449
459
  "unlocked_by": null,
450
460
  "difficulty": 4,
451
461
  "topics": [
462
+ "Number Theory"
452
463
  ]
453
464
  },
454
465
  {
@@ -486,7 +497,8 @@
486
497
  "unlocked_by": null,
487
498
  "difficulty": 5,
488
499
  "topics": [
489
- "Maybe"
500
+ "Maybe",
501
+ "Number Theory"
490
502
  ]
491
503
  },
492
504
  {
@@ -106,7 +106,7 @@ do
106
106
 
107
107
  done
108
108
 
109
- if [ $update_needed_count -eq 1 ]
109
+ if [ $update_needed_count -eq 0 ]
110
110
  then
111
111
  echo "All exercises are up to date!"
112
112
  fi
@@ -1123,6 +1123,18 @@
1123
1123
  "strings",
1124
1124
  "algorithms"
1125
1125
  ]
1126
+ },
1127
+ {
1128
+ "uuid": "f4a3d66a-04a8-3e80-6c9a-8a573ccb26fd9ed1d5c",
1129
+ "slug": "zipper",
1130
+ "core": false,
1131
+ "unlocked_by": null,
1132
+ "difficulty": 8,
1133
+ "topics": [
1134
+ "recursion",
1135
+ "searching",
1136
+ "trees"
1137
+ ]
1126
1138
  }
1127
1139
  ],
1128
1140
  "foregone": [],
@@ -1,4 +1,4 @@
1
- # Difference Of Squares
1
+ # Difference of Squares
2
2
 
3
3
  Find the difference between the square of the sum and the sum of the squares of the first N natural numbers.
4
4
 
@@ -1,4 +1,4 @@
1
- # Sum Of Multiples
1
+ # Sum of Multiples
2
2
 
3
3
  Given a number, find the sum of all the multiples of particular numbers up to
4
4
  but not including that number.
@@ -0,0 +1,55 @@
1
+ # Zipper
2
+
3
+ Creating a zipper for a binary tree.
4
+
5
+ [Zippers](https://en.wikipedia.org/wiki/Zipper_%28data_structure%29) are
6
+ a way purely functional of navigating within a data structure and
7
+ manipulating it. They essentially contain a data structure and a
8
+ pointer into that data structure (called the focus).
9
+
10
+ For example given a rose tree (where each node contains a value and a
11
+ list of child nodes) a zipper might support these operations:
12
+
13
+ - `from_tree` (get a zipper out of a rose tree, the focus is on the root node)
14
+ - `to_tree` (get the rose tree out of the zipper)
15
+ - `value` (get the value of the focus node)
16
+ - `prev` (move the focus to the previous child of the same parent,
17
+ returns a new zipper)
18
+ - `next` (move the focus to the next child of the same parent, returns a
19
+ new zipper)
20
+ - `up` (move the focus to the parent, returns a new zipper)
21
+ - `set_value` (set the value of the focus node, returns a new zipper)
22
+ - `insert_before` (insert a new subtree before the focus node, it
23
+ becomes the `prev` of the focus node, returns a new zipper)
24
+ - `insert_after` (insert a new subtree after the focus node, it becomes
25
+ the `next` of the focus node, returns a new zipper)
26
+ - `delete` (removes the focus node and all subtrees, focus moves to the
27
+ `next` node if possible otherwise to the `prev` node if possible,
28
+ otherwise to the parent node, returns a new zipper)
29
+
30
+ ## Setup
31
+
32
+ Go through the setup instructions for JavaScript to
33
+ install the necessary dependencies:
34
+
35
+ http://exercism.io/languages/javascript
36
+
37
+ ## Making the Test Suite Pass
38
+
39
+ Execute the tests with:
40
+
41
+ jasmine <exercise-name>.spec.js
42
+
43
+ Replace `<exercise-name>` with the name of the current exercise. E.g., to
44
+ test the Hello World exercise:
45
+
46
+ jasmine hello-world.spec.js
47
+
48
+ All but the first test have been skipped.
49
+
50
+ Once you get a test passing, you can unskip the next one by
51
+ changing `xit` to `it`.
52
+
53
+
54
+ ## Submitting Incomplete Solutions
55
+ It's possible to submit an incomplete solution so you can see how others have completed the exercise.
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ function fromTrail(tree, last) {
4
+ if (last[0] === 'left') {
5
+ return {
6
+ value: last[1],
7
+ left: tree,
8
+ right: last[2]
9
+ };
10
+ }
11
+ return {
12
+ value: last[1],
13
+ left: last[2],
14
+ right: tree
15
+ };
16
+ }
17
+
18
+ function rebuildTree(tree, trail) {
19
+ if (trail.length === 0) return tree;
20
+
21
+ var last = trail[0];
22
+ return rebuildTree(fromTrail(tree, last), trail.slice(1));
23
+ }
24
+
25
+ var Zipper = function (tree, trail) {
26
+ this.tree = tree;
27
+ this.trail = trail;
28
+ };
29
+
30
+ Zipper.fromTree = function (tree) {
31
+ return new Zipper(tree, []);
32
+ };
33
+
34
+ Zipper.prototype.toTree = function () {
35
+ return rebuildTree(this.tree, this.trail);
36
+ };
37
+
38
+ Zipper.prototype.value = function () {
39
+ return this.tree.value;
40
+ };
41
+
42
+ Zipper.prototype.left = function () {
43
+ if (!this.tree.left) return null;
44
+
45
+ return new Zipper(
46
+ this.tree.left,
47
+ [['left', this.tree.value, this.tree.right]].concat(this.trail)
48
+ );
49
+ };
50
+
51
+ Zipper.prototype.right = function () {
52
+ if (!this.tree.right) return null;
53
+
54
+ return new Zipper(
55
+ this.tree.right,
56
+ [['right', this.tree.value, this.tree.left]].concat(this.trail)
57
+ );
58
+ };
59
+
60
+ Zipper.prototype.up = function () {
61
+ if (this.trail.length === 0) return null;
62
+
63
+ var last = this.trail[0];
64
+ return new Zipper(fromTrail(this.tree, last), this.trail.slice(1));
65
+ };
66
+
67
+ Zipper.prototype.setValue = function (value) {
68
+ return new Zipper(
69
+ {
70
+ value: value,
71
+ left: this.tree.left,
72
+ right: this.tree.right
73
+ },
74
+ this.trail
75
+ );
76
+ };
77
+
78
+ Zipper.prototype.setLeft = function (left) {
79
+ return new Zipper(
80
+ {
81
+ value: this.tree.value,
82
+ left: left,
83
+ right: this.tree.right
84
+ },
85
+ this.trail
86
+ );
87
+ };
88
+
89
+ Zipper.prototype.setRight = function (right) {
90
+ return new Zipper(
91
+ {
92
+ value: this.tree.value,
93
+ left: this.tree.left,
94
+ right: right
95
+ },
96
+ this.trail
97
+ );
98
+ };
99
+
100
+ module.exports = Zipper;