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.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/nth-prime/canonical-data.json +2 -7
- data/problem-specifications/exercises/zebra-puzzle/canonical-data.json +16 -0
- data/tracks/c/config.json +11 -1
- data/tracks/c/docs/C_STYLE_GUIDE.md +142 -0
- data/tracks/c/exercises/collatz-conjecture/README.md +65 -0
- data/tracks/c/exercises/collatz-conjecture/makefile +15 -0
- data/tracks/c/exercises/collatz-conjecture/src/collatz_conjecture.h +8 -0
- data/tracks/c/exercises/collatz-conjecture/src/example.c +23 -0
- data/tracks/c/exercises/collatz-conjecture/test/test_collatz_conjecture.c +48 -0
- data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.c +1300 -0
- data/tracks/c/exercises/collatz-conjecture/test/vendor/unity.h +274 -0
- data/tracks/c/exercises/collatz-conjecture/test/vendor/unity_internals.h +701 -0
- data/tracks/cfml/tasks/GenerateReadme.cfc +5 -5
- data/tracks/erlang/testgen/src/testgen.erl +99 -17
- data/tracks/erlang/testgen/src/tg_file_tools.erl +3 -3
- data/tracks/erlang/testgen/src/tgen.erl +15 -7
- data/tracks/haskell/config.json +15 -3
- data/tracks/java/scripts/canonical_data_check.sh +1 -1
- data/tracks/javascript/config.json +12 -0
- data/tracks/javascript/exercises/difference-of-squares/README.md +1 -1
- data/tracks/javascript/exercises/sum-of-multiples/README.md +1 -1
- data/tracks/javascript/exercises/zipper/README.md +55 -0
- data/tracks/javascript/exercises/zipper/example.js +100 -0
- data/tracks/javascript/exercises/zipper/zipper.spec.js +77 -0
- data/tracks/julia/config.json +12 -0
- data/tracks/julia/exercises/triangle/README.md +30 -0
- data/tracks/julia/exercises/triangle/example.jl +25 -0
- data/tracks/julia/exercises/triangle/runtests.jl +64 -0
- data/tracks/julia/exercises/triangle/triangle.jl +8 -0
- data/tracks/kotlin/exercises/leap/.meta/version +1 -1
- data/tracks/kotlin/exercises/leap/src/test/kotlin/LeapTest.kt +1 -1
- data/tracks/kotlin/scripts/canonical_data_check.sh +1 -1
- data/tracks/perl6/bin/README.md +1 -4
- data/tracks/perl6/bin/exercise-gen.pl6 +3 -4
- data/tracks/perl6/exercises/accumulate/example.yaml +2 -2
- data/tracks/perl6/exercises/all-your-base/example.yaml +9 -9
- data/tracks/perl6/exercises/allergies/example.yaml +7 -7
- data/tracks/perl6/exercises/anagram/example.yaml +3 -3
- data/tracks/perl6/exercises/atbash-cipher/example.yaml +3 -3
- data/tracks/perl6/exercises/bob/example.yaml +4 -4
- data/tracks/perl6/exercises/clock/example.yaml +6 -6
- data/tracks/perl6/exercises/flatten-array/example.yaml +4 -4
- data/tracks/perl6/exercises/grade-school/example.yaml +6 -6
- data/tracks/perl6/exercises/grains/example.yaml +3 -3
- data/tracks/perl6/exercises/hello-world/example.yaml +5 -5
- data/tracks/perl6/exercises/leap/example.yaml +4 -4
- data/tracks/perl6/exercises/linked-list/example.yaml +14 -14
- data/tracks/perl6/exercises/luhn/example.yaml +3 -3
- data/tracks/perl6/exercises/phone-number/example.yaml +3 -3
- data/tracks/perl6/exercises/raindrops/example.yaml +3 -3
- data/tracks/perl6/exercises/rna-transcription/example.yaml +3 -3
- data/tracks/perl6/exercises/robot-name/example.yaml +8 -8
- data/tracks/perl6/exercises/scrabble-score/example.yaml +3 -3
- data/tracks/perl6/exercises/space-age/example.yaml +8 -8
- data/tracks/perl6/exercises/word-count/example.yaml +3 -3
- data/tracks/perl6/exercises/wordy/example.yaml +3 -3
- data/tracks/python/config.json +14 -0
- data/tracks/python/config/maintainers.json +30 -0
- data/tracks/python/docs/EXERCISE_README_INSERT.md +1 -2
- data/tracks/python/exercises/accumulate/README.md +1 -5
- data/tracks/python/exercises/acronym/README.md +1 -3
- data/tracks/python/exercises/all-your-base/README.md +2 -3
- data/tracks/python/exercises/all-your-base/all_your_base_test.py +13 -13
- data/tracks/python/exercises/allergies/README.md +1 -3
- data/tracks/python/exercises/alphametics/README.md +3 -4
- data/tracks/python/exercises/anagram/README.md +1 -2
- data/tracks/python/exercises/atbash-cipher/README.md +3 -3
- data/tracks/python/exercises/beer-song/README.md +2 -3
- data/tracks/python/exercises/binary-search/README.md +1 -2
- data/tracks/python/exercises/binary/README.md +3 -2
- data/tracks/python/exercises/bob/README.md +1 -2
- data/tracks/python/exercises/book-store/README.md +6 -7
- data/tracks/python/exercises/bracket-push/README.md +1 -2
- data/tracks/python/exercises/change/README.md +2 -3
- data/tracks/python/exercises/circular-buffer/README.md +14 -8
- data/tracks/python/exercises/clock/README.md +1 -2
- data/tracks/python/exercises/clock/clock_test.py +2 -0
- data/tracks/python/exercises/collatz-conjecture/.meta/hints.md +3 -0
- data/tracks/python/exercises/collatz-conjecture/README.md +6 -19
- data/tracks/python/exercises/complex-numbers/README.md +28 -2
- data/tracks/python/exercises/crypto-square/README.md +11 -10
- data/tracks/python/exercises/diamond/README.md +7 -8
- data/tracks/python/exercises/difference-of-squares/README.md +1 -2
- data/tracks/python/exercises/diffie-hellman/.meta/hints.md +1 -1
- data/tracks/python/exercises/diffie-hellman/README.md +3 -2
- data/tracks/python/exercises/error-handling/.meta/hints.md +8 -0
- data/tracks/python/exercises/error-handling/README.md +10 -2
- data/tracks/python/exercises/error-handling/error_handling_test.py +15 -3
- data/tracks/python/exercises/etl/README.md +3 -2
- data/tracks/python/exercises/flatten-array/README.md +2 -4
- data/tracks/python/exercises/food-chain/README.md +3 -4
- data/tracks/python/exercises/forth/README.md +2 -6
- data/tracks/python/exercises/gigasecond/README.md +1 -2
- data/tracks/python/exercises/grade-school/README.md +1 -3
- data/tracks/python/exercises/grains/README.md +1 -3
- data/tracks/python/exercises/grep/README.md +13 -14
- data/tracks/python/exercises/hamming/README.md +1 -2
- data/tracks/python/exercises/hamming/hamming_test.py +6 -6
- data/tracks/python/exercises/hello-world/README.md +1 -2
- data/tracks/python/exercises/hexadecimal/README.md +1 -2
- data/tracks/python/exercises/hexadecimal/example.py +6 -6
- data/tracks/python/exercises/house/README.md +2 -4
- data/tracks/python/exercises/isogram/README.md +3 -3
- data/tracks/python/exercises/kindergarten-garden/README.md +14 -15
- data/tracks/python/exercises/largest-series-product/README.md +1 -2
- data/tracks/python/exercises/leap/README.md +2 -3
- data/tracks/python/exercises/linked-list/README.md +11 -12
- data/tracks/python/exercises/list-ops/README.md +1 -2
- data/tracks/python/exercises/luhn/README.md +8 -9
- data/tracks/python/exercises/markdown/README.md +1 -6
- data/tracks/python/exercises/matrix/README.md +7 -6
- data/tracks/python/exercises/meetup/README.md +2 -4
- data/tracks/python/exercises/minesweeper/README.md +1 -2
- data/tracks/python/exercises/nth-prime/README.md +1 -2
- data/tracks/python/exercises/nucleotide-count/README.md +9 -24
- data/tracks/python/exercises/ocr-numbers/README.md +6 -7
- data/tracks/python/exercises/octal/README.md +7 -4
- data/tracks/python/exercises/palindrome-products/README.md +16 -18
- data/tracks/python/exercises/pangram/README.md +2 -3
- data/tracks/python/exercises/pascals-triangle/README.md +2 -3
- data/tracks/python/exercises/perfect-numbers/README.md +3 -4
- data/tracks/python/exercises/phone-number/README.md +4 -4
- data/tracks/python/exercises/pig-latin/README.md +1 -2
- data/tracks/python/exercises/point-mutations/README.md +1 -2
- data/tracks/python/exercises/poker/README.md +1 -2
- data/tracks/python/exercises/prime-factors/README.md +1 -2
- data/tracks/python/exercises/protein-translation/README.md +5 -7
- data/tracks/python/exercises/proverb/README.md +12 -11
- data/tracks/python/exercises/pythagorean-triplet/README.md +4 -5
- data/tracks/python/exercises/queen-attack/README.md +2 -3
- data/tracks/python/exercises/rail-fence-cipher/README.md +13 -9
- data/tracks/python/exercises/raindrops/README.md +1 -2
- data/tracks/python/exercises/rectangles/README.md +8 -9
- data/tracks/python/exercises/rectangles/example.py +3 -3
- data/tracks/python/exercises/rna-transcription/README.md +1 -2
- data/tracks/python/exercises/rna-transcription/rna_transcription_test.py +4 -3
- data/tracks/python/exercises/robot-name/README.md +1 -2
- data/tracks/python/exercises/robot-simulator/README.md +1 -2
- data/tracks/python/exercises/roman-numerals/README.md +2 -3
- data/tracks/python/exercises/rotational-cipher/README.md +3 -3
- data/tracks/python/exercises/run-length-encoding/README.md +5 -6
- data/tracks/python/exercises/run-length-encoding/example.py +2 -2
- data/tracks/python/exercises/saddle-points/README.md +2 -3
- data/tracks/python/exercises/say/README.md +1 -2
- data/tracks/python/exercises/scale-generator/README.md +1 -3
- data/tracks/python/exercises/scrabble-score/README.md +4 -3
- data/tracks/python/exercises/secret-handshake/README.md +2 -3
- data/tracks/python/exercises/series/README.md +1 -2
- data/tracks/python/exercises/sieve/README.md +1 -2
- data/tracks/python/exercises/simple-cipher/README.md +3 -4
- data/tracks/python/exercises/space-age/README.md +2 -3
- data/tracks/python/exercises/space-age/space_age_test.py +18 -29
- data/tracks/python/exercises/strain/README.md +1 -2
- data/tracks/python/exercises/sublist/README.md +1 -2
- data/tracks/python/exercises/sum-of-multiples/README.md +1 -5
- data/tracks/python/exercises/tournament/README.md +6 -7
- data/tracks/python/exercises/transpose/README.md +8 -9
- data/tracks/python/exercises/tree-building/README.md +25 -0
- data/tracks/python/exercises/tree-building/example.py +46 -0
- data/tracks/python/exercises/tree-building/tree_building.py +50 -0
- data/tracks/python/exercises/tree-building/tree_building_test.py +183 -0
- data/tracks/python/exercises/triangle/README.md +10 -8
- data/tracks/python/exercises/trinary/README.md +2 -3
- data/tracks/python/exercises/twelve-days/README.md +2 -3
- data/tracks/python/exercises/two-bucket/README.md +4 -5
- data/tracks/python/exercises/two-bucket/two_bucket_test.py +2 -0
- data/tracks/python/exercises/two-fer/README.md +4 -5
- data/tracks/python/exercises/two-fer/two_fer_test.py +5 -2
- data/tracks/python/exercises/variable-length-quantity/README.md +7 -9
- data/tracks/python/exercises/word-count/README.md +2 -4
- data/tracks/python/exercises/word-search/README.md +2 -3
- data/tracks/python/exercises/wordy/README.md +1 -7
- data/tracks/python/exercises/wordy/example.py +8 -8
- data/tracks/python/exercises/wordy/wordy_test.py +36 -32
- data/tracks/python/exercises/zebra-puzzle/README.md +1 -2
- data/tracks/python/requirements-travis.txt +1 -1
- data/tracks/ruby/config.json +11 -0
- data/tracks/ruby/docs/TESTS.md +6 -0
- data/tracks/ruby/exercises/pangram/.meta/.version +1 -1
- data/tracks/ruby/exercises/pangram/.meta/solutions/pangram.rb +1 -1
- data/tracks/ruby/exercises/pangram/pangram_test.rb +11 -4
- data/tracks/ruby/exercises/two-fer/.meta/.version +1 -0
- data/tracks/ruby/exercises/two-fer/.meta/generator/two_fer_case.rb +12 -0
- data/tracks/ruby/exercises/two-fer/.meta/solutions/two_fer.rb +9 -0
- data/tracks/ruby/exercises/two-fer/README.md +69 -0
- data/tracks/ruby/exercises/two-fer/two_fer_test.rb +42 -0
- data/tracks/rust/config.json +12 -0
- data/tracks/rust/exercises/binary-search/.meta/hints.md +38 -0
- data/tracks/rust/exercises/binary-search/Cargo.lock +4 -0
- data/tracks/rust/exercises/binary-search/Cargo.toml +6 -0
- data/tracks/rust/exercises/binary-search/README.md +113 -0
- data/tracks/rust/exercises/binary-search/example.rs +29 -0
- data/tracks/rust/exercises/binary-search/src/lib.rs +0 -0
- data/tracks/rust/exercises/binary-search/tests/binary-search.rs +96 -0
- data/tracks/typescript/common/package.json +6 -6
- data/tracks/typescript/common/yarn.lock +929 -610
- data/tracks/typescript/exercises/acronym/package.json +6 -6
- data/tracks/typescript/exercises/acronym/yarn.lock +929 -610
- data/tracks/typescript/exercises/anagram/package.json +6 -6
- data/tracks/typescript/exercises/anagram/yarn.lock +929 -610
- data/tracks/typescript/exercises/beer-song/package.json +6 -6
- data/tracks/typescript/exercises/beer-song/yarn.lock +929 -610
- data/tracks/typescript/exercises/binary-search-tree/package.json +6 -6
- data/tracks/typescript/exercises/binary-search-tree/yarn.lock +929 -610
- data/tracks/typescript/exercises/binary-search/package.json +6 -6
- data/tracks/typescript/exercises/binary-search/yarn.lock +929 -610
- data/tracks/typescript/exercises/bob/package.json +6 -6
- data/tracks/typescript/exercises/bob/yarn.lock +929 -610
- data/tracks/typescript/exercises/circular-buffer/package.json +6 -6
- data/tracks/typescript/exercises/circular-buffer/yarn.lock +929 -610
- data/tracks/typescript/exercises/clock/package.json +6 -6
- data/tracks/typescript/exercises/clock/yarn.lock +929 -610
- data/tracks/typescript/exercises/difference-of-squares/package.json +6 -6
- data/tracks/typescript/exercises/difference-of-squares/yarn.lock +929 -610
- data/tracks/typescript/exercises/etl/package.json +6 -6
- data/tracks/typescript/exercises/etl/yarn.lock +929 -610
- data/tracks/typescript/exercises/food-chain/package.json +6 -6
- data/tracks/typescript/exercises/food-chain/yarn.lock +929 -610
- data/tracks/typescript/exercises/gigasecond/package.json +6 -6
- data/tracks/typescript/exercises/gigasecond/yarn.lock +929 -610
- data/tracks/typescript/exercises/grade-school/package.json +6 -6
- data/tracks/typescript/exercises/grade-school/yarn.lock +929 -610
- data/tracks/typescript/exercises/hamming/package.json +6 -6
- data/tracks/typescript/exercises/hamming/yarn.lock +929 -610
- data/tracks/typescript/exercises/hello-world/README.md +354 -0
- data/tracks/typescript/exercises/hello-world/package.json +6 -6
- data/tracks/typescript/exercises/hello-world/yarn.lock +929 -610
- data/tracks/typescript/exercises/largest-series-product/package.json +6 -6
- data/tracks/typescript/exercises/largest-series-product/yarn.lock +929 -610
- data/tracks/typescript/exercises/leap/package.json +6 -6
- data/tracks/typescript/exercises/leap/yarn.lock +929 -610
- data/tracks/typescript/exercises/linked-list/package.json +6 -6
- data/tracks/typescript/exercises/linked-list/yarn.lock +929 -610
- data/tracks/typescript/exercises/nth-prime/package.json +6 -6
- data/tracks/typescript/exercises/nth-prime/yarn.lock +929 -610
- data/tracks/typescript/exercises/pangram/package.json +6 -6
- data/tracks/typescript/exercises/pangram/yarn.lock +929 -610
- data/tracks/typescript/exercises/pascals-triangle/package.json +6 -6
- data/tracks/typescript/exercises/pascals-triangle/yarn.lock +929 -610
- data/tracks/typescript/exercises/phone-number/package.json +6 -6
- data/tracks/typescript/exercises/phone-number/yarn.lock +929 -610
- data/tracks/typescript/exercises/prime-factors/package.json +6 -6
- data/tracks/typescript/exercises/prime-factors/yarn.lock +929 -610
- data/tracks/typescript/exercises/raindrops/package.json +6 -6
- data/tracks/typescript/exercises/raindrops/yarn.lock +929 -610
- data/tracks/typescript/exercises/rna-transcription/package.json +6 -6
- data/tracks/typescript/exercises/rna-transcription/yarn.lock +929 -610
- data/tracks/typescript/exercises/robot-name/package.json +6 -6
- data/tracks/typescript/exercises/robot-name/yarn.lock +929 -610
- data/tracks/typescript/exercises/robot-simulator/package.json +6 -6
- data/tracks/typescript/exercises/robot-simulator/yarn.lock +929 -610
- data/tracks/typescript/exercises/rotational-cipher/package.json +6 -6
- data/tracks/typescript/exercises/rotational-cipher/yarn.lock +929 -610
- data/tracks/typescript/exercises/say/package.json +6 -6
- data/tracks/typescript/exercises/say/yarn.lock +929 -610
- data/tracks/typescript/exercises/scrabble-score/package.json +6 -6
- data/tracks/typescript/exercises/scrabble-score/yarn.lock +929 -610
- data/tracks/typescript/exercises/series/package.json +6 -6
- data/tracks/typescript/exercises/series/yarn.lock +929 -610
- data/tracks/typescript/exercises/space-age/package.json +6 -6
- data/tracks/typescript/exercises/space-age/yarn.lock +929 -610
- data/tracks/typescript/exercises/strain/package.json +6 -6
- data/tracks/typescript/exercises/strain/yarn.lock +929 -610
- data/tracks/typescript/exercises/sum-of-multiples/package.json +6 -6
- data/tracks/typescript/exercises/sum-of-multiples/yarn.lock +929 -610
- data/tracks/typescript/exercises/triangle/package.json +6 -6
- data/tracks/typescript/exercises/triangle/yarn.lock +929 -610
- data/tracks/typescript/exercises/word-count/package.json +6 -6
- data/tracks/typescript/exercises/word-count/yarn.lock +929 -610
- data/tracks/typescript/exercises/wordy/package.json +6 -6
- data/tracks/typescript/exercises/wordy/yarn.lock +929 -610
- 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
|
-
|
15
|
-
|
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
|
-
|
32
|
-
|
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
|
-
_ ->
|
41
|
-
|
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(
|
9
|
-
lists:takewhile(fun(C) -> not lists:member(C, [$/, $\\]) end,
|
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
|
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
|
-
|
54
|
-
io:format(
|
55
|
-
|
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].
|
data/tracks/haskell/config.json
CHANGED
@@ -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
|
{
|
@@ -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": [],
|
@@ -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;
|