trackler 2.2.1.75 → 2.2.1.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/alphametics/canonical-data.json +18 -1
  4. data/problem-specifications/exercises/anagram/canonical-data.json +72 -39
  5. data/problem-specifications/exercises/binary/canonical-data.json +47 -17
  6. data/tracks/clojure/exercises/beer-song/src/beer_song.clj +11 -0
  7. data/tracks/erlang/config.json +10 -0
  8. data/tracks/erlang/exercises/raindrops/README.md +67 -0
  9. data/tracks/erlang/exercises/raindrops/rebar.config +30 -0
  10. data/tracks/erlang/exercises/raindrops/src/example.erl +30 -0
  11. data/tracks/erlang/exercises/raindrops/src/raindrops.app.src +9 -0
  12. data/tracks/erlang/exercises/raindrops/src/raindrops.erl +8 -0
  13. data/tracks/erlang/exercises/raindrops/test/raindrops_tests.erl +50 -0
  14. data/tracks/fsharp/exercises/bob/BobTest.fs +2 -2
  15. data/tracks/fsharp/exercises/bob/Example.fs +10 -4
  16. data/tracks/fsharp/exercises/book-store/BookStoreTest.fs +5 -1
  17. data/tracks/fsharp/exercises/rna-transcription/RnaTranscriptionTest.fs +1 -13
  18. data/tracks/fsharp/generators/CanonicalData.fs +14 -7
  19. data/tracks/fsharp/generators/Exercise.fs +84 -18
  20. data/tracks/fsharp/generators/Generators.fs +65 -62
  21. data/tracks/fsharp/generators/Generators.fsproj +0 -4
  22. data/tracks/fsharp/generators/Options.fs +51 -17
  23. data/tracks/fsharp/generators/Program.fs +34 -7
  24. data/tracks/fsharp/generators/Rendering.fs +2 -1
  25. data/tracks/go/config.json +11 -0
  26. data/tracks/go/exercises/reverse-string/.meta/gen.go +52 -0
  27. data/tracks/go/exercises/reverse-string/README.md +31 -0
  28. data/tracks/go/exercises/reverse-string/cases_test.go +37 -0
  29. data/tracks/go/exercises/reverse-string/example.go +10 -0
  30. data/tracks/go/exercises/reverse-string/reverse_string_test.go +25 -0
  31. data/tracks/haskell/exercises/bob/README.md +2 -0
  32. data/tracks/haskell/exercises/bob/examples/success-standard/src/Bob.hs +7 -3
  33. data/tracks/haskell/exercises/bob/package.yaml +1 -1
  34. data/tracks/haskell/exercises/bob/test/Tests.hs +1 -1
  35. data/tracks/haskell/exercises/isbn-verifier/README.md +25 -20
  36. data/tracks/haskell/exercises/pov/README.md +0 -2
  37. data/tracks/haskell/exercises/secret-handshake/README.md +1 -1
  38. data/tracks/haskell/exercises/simple-cipher/README.md +4 -6
  39. data/tracks/java/config.json +12 -0
  40. data/tracks/java/exercises/beer-song/README.md +1 -1
  41. data/tracks/java/exercises/house/README.md +1 -1
  42. data/tracks/java/exercises/isbn-verifier/README.md +27 -21
  43. data/tracks/java/exercises/kindergarten-garden/README.md +3 -3
  44. data/tracks/java/exercises/meetup/README.md +16 -12
  45. data/tracks/java/exercises/nucleotide-count/README.md +2 -2
  46. data/tracks/java/exercises/palindrome-products/README.md +1 -1
  47. data/tracks/java/exercises/parallel-letter-frequency/.meta/HINTS.md +3 -0
  48. data/tracks/java/exercises/parallel-letter-frequency/.meta/src/reference/java/ParallelLetterFrequency.java +45 -0
  49. data/tracks/java/exercises/parallel-letter-frequency/README.md +30 -0
  50. data/tracks/java/exercises/parallel-letter-frequency/build.gradle +18 -0
  51. data/tracks/java/exercises/parallel-letter-frequency/src/main/java/.keep +0 -0
  52. data/tracks/java/exercises/parallel-letter-frequency/src/test/java/ParallelLetterFrequencyTest.java +235 -0
  53. data/tracks/java/exercises/pig-latin/README.md +1 -0
  54. data/tracks/java/exercises/protein-translation/README.md +4 -2
  55. data/tracks/java/exercises/rectangles/README.md +9 -9
  56. data/tracks/java/exercises/settings.gradle +1 -0
  57. data/tracks/java/exercises/simple-cipher/README.md +4 -6
  58. data/tracks/java/exercises/sum-of-multiples/README.md +3 -3
  59. data/tracks/objective-c/config.json +11 -0
  60. data/tracks/objective-c/exercises/two-fer/TwoFerExample.h +15 -0
  61. data/tracks/objective-c/exercises/two-fer/TwoFerExample.m +21 -0
  62. data/tracks/objective-c/exercises/two-fer/TwoFerTest.m +31 -0
  63. data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
  64. data/tracks/rust/exercises/bob/Cargo.toml +1 -1
  65. data/tracks/rust/exercises/bob/README.md +2 -0
  66. data/tracks/rust/exercises/bob/example.rs +1 -0
  67. data/tracks/rust/exercises/bob/tests/bob.rs +1 -1
  68. data/tracks/rust/exercises/isbn-verifier/README.md +25 -20
  69. data/tracks/typescript/config.json +13 -0
  70. data/tracks/typescript/exercises/atbash-cipher/README.md +60 -0
  71. data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.example.ts +32 -0
  72. data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.test.ts +73 -0
  73. data/tracks/typescript/exercises/atbash-cipher/atbash-cipher.ts +0 -0
  74. data/tracks/typescript/exercises/atbash-cipher/package.json +36 -0
  75. data/tracks/typescript/exercises/atbash-cipher/tsconfig.json +22 -0
  76. data/tracks/typescript/exercises/atbash-cipher/tslint.json +127 -0
  77. data/tracks/typescript/exercises/atbash-cipher/yarn.lock +2624 -0
  78. metadata +31 -2
@@ -0,0 +1,30 @@
1
+ %% Erlang compiler options
2
+ {erl_opts, [debug_info]}.
3
+
4
+ {deps, [{erl_exercism, "0.1.1"}]}.
5
+
6
+ {dialyzer, [
7
+ {warnings, [underspecs, no_return]},
8
+ {get_warnings, true},
9
+ {plt_apps, top_level_deps}, % top_level_deps | all_deps
10
+ {plt_extra_apps, []},
11
+ {plt_location, local}, % local | "/my/file/name"
12
+ {plt_prefix, "rebar3"},
13
+ {base_plt_apps, [stdlib, kernel, crypto]},
14
+ {base_plt_location, global}, % global | "/my/file/name"
15
+ {base_plt_prefix, "rebar3"}
16
+ ]}.
17
+
18
+ %% eunit:test(Tests)
19
+ {eunit_tests, []}.
20
+ %% Options for eunit:test(Tests, Opts)
21
+ {eunit_opts, [verbose]}.
22
+
23
+ %% == xref ==
24
+
25
+ {xref_warnings, true}.
26
+
27
+ %% xref checks to run
28
+ {xref_checks, [undefined_function_calls, undefined_functions,
29
+ locals_not_used, exports_not_used,
30
+ deprecated_function_calls, deprecated_functions]}.
@@ -0,0 +1,30 @@
1
+ -module(example).
2
+
3
+ -export([convert/1, test_version/0]).
4
+
5
+ convert(Number) when Number rem 3 == 0 ->
6
+ pling(Number);
7
+ convert(Number) when Number rem 5 == 0 ->
8
+ plang(Number);
9
+ convert(Number) when Number rem 7 == 0 ->
10
+ plong(Number);
11
+ convert(Number) ->
12
+ integer_to_list(Number).
13
+
14
+ pling(Number) when Number rem 5 == 0 ->
15
+ "Pling" ++ plang(Number);
16
+ pling(Number) when Number rem 7 == 0 ->
17
+ "Pling" ++ plong(Number);
18
+ pling(_) ->
19
+ "Pling".
20
+
21
+ plang(Number) when Number rem 7 == 0 ->
22
+ "Plang" ++ plong(Number);
23
+ plang(_) ->
24
+ "Plang".
25
+
26
+ plong(_) ->
27
+ "Plong".
28
+
29
+ test_version() ->
30
+ 1.
@@ -0,0 +1,9 @@
1
+ {application, raindrops,
2
+ [{description, "exercism.io - raindrops"},
3
+ {vsn, "0.0.1"},
4
+ {modules, []},
5
+ {registered, []},
6
+ {applications, [kernel,
7
+ stdlib]},
8
+ {env, []}
9
+ ]}.
@@ -0,0 +1,8 @@
1
+ -module(raindrops).
2
+
3
+ -export([convert/1, test_version/0]).
4
+
5
+ convert(Number) ->
6
+ undefined.
7
+
8
+ test_version() -> 1.
@@ -0,0 +1,50 @@
1
+ -module(raindrops_tests).
2
+
3
+ -include_lib("erl_exercism/include/exercism.hrl").
4
+ -include_lib("eunit/include/eunit.hrl").
5
+
6
+ % test cases adapted from `x-common//canonical-data.json` @ version: 1.0.0
7
+
8
+ sound_of_1_is_1_test() ->
9
+ ?assert( raindrops:convert(1) =:= "1").
10
+ sound_of_3_is_Pling_test() ->
11
+ ?assert( raindrops:convert(3) =:= "Pling").
12
+ sound_of_5_is_Plang_test() ->
13
+ ?assert( raindrops:convert(5) =:= "Plang").
14
+ sound_of_7_is_Plong_test() ->
15
+ ?assert( raindrops:convert(7) =:= "Plong").
16
+
17
+ sound_of_6_is_Pling_test() ->
18
+ ?assert( raindrops:convert(6) =:= "Pling").
19
+ sound_of_2_to_the_power_3_is_8_test() ->
20
+ ?assert( raindrops:convert(8) =:= "8").
21
+ sound_of_9_is_Pling_test() ->
22
+ ?assert( raindrops:convert(9) =:= "Pling").
23
+ sound_of_10_is_Plang_test() ->
24
+ ?assert( raindrops:convert(10) =:= "Plang").
25
+ sound_of_14_is_Plong_test() ->
26
+ ?assert( raindrops:convert(14) =:= "Plong").
27
+
28
+ sound_of_15_is_PlingPlang_test() ->
29
+ ?assert( raindrops:convert(15) =:= "PlingPlang").
30
+ sound_of_21_is_PlingPlong_test() ->
31
+ ?assert( raindrops:convert(21) =:= "PlingPlong").
32
+ sound_of_25_is_Plang_test() ->
33
+ ?assert( raindrops:convert(25) =:= "Plang").
34
+
35
+ sound_of_27_is_Pling_test() ->
36
+ ?assert( raindrops:convert(27) =:= "Pling").
37
+ sound_of_35_is_PlangPlong_test() ->
38
+ ?assert( raindrops:convert(35) =:= "PlangPlong").
39
+ sound_of_49_is_Plong_test() ->
40
+ ?assert( raindrops:convert(49) =:= "Plong").
41
+
42
+ sound_of_52_is_52_test() ->
43
+ ?assert( raindrops:convert(52) =:= "52").
44
+ sound_of_105_is_PlingPlangPlong_test() ->
45
+ ?assert( raindrops:convert(105) =:= "PlingPlangPlong").
46
+ sound_of_3125_is_Plang_test() ->
47
+ ?assert( raindrops:convert(3125) =:= "Plang").
48
+
49
+ version_test() ->
50
+ ?assertMatch(1, raindrops:test_version()).
@@ -1,4 +1,4 @@
1
- // This file was auto-generated based on version 1.0.0 of the canonical data.
1
+ // This file was auto-generated based on version 1.1.0 of the canonical data.
2
2
 
3
3
  module BobTest
4
4
 
@@ -41,7 +41,7 @@ let ``Using acronyms in regular speech`` () =
41
41
 
42
42
  [<Fact(Skip = "Remove to run test")>]
43
43
  let ``Forceful question`` () =
44
- response "WHAT THE HELL WERE YOU THINKING?" |> should equal "Whoa, chill out!"
44
+ response "WHAT THE HELL WERE YOU THINKING?" |> should equal "Calm down, I know what I'm doing!"
45
45
 
46
46
  [<Fact(Skip = "Remove to run test")>]
47
47
  let ``Shouting numbers`` () =
@@ -8,7 +8,13 @@ let response (input: string) =
8
8
  let isQuestion = input.Trim().EndsWith "?"
9
9
 
10
10
  match input with
11
- | _ when isEmpty -> "Fine. Be that way!"
12
- | _ when isYell -> "Whoa, chill out!"
13
- | _ when isQuestion -> "Sure."
14
- | _ -> "Whatever."
11
+ | _ when isEmpty ->
12
+ "Fine. Be that way!"
13
+ | _ when isYell && isQuestion ->
14
+ "Calm down, I know what I'm doing!"
15
+ | _ when isYell ->
16
+ "Whoa, chill out!"
17
+ | _ when isQuestion ->
18
+ "Sure."
19
+ | _ ->
20
+ "Whatever."
@@ -1,4 +1,4 @@
1
- // This file was auto-generated based on version 1.0.1 of the canonical data.
1
+ // This file was auto-generated based on version 1.1.0 of the canonical data.
2
2
 
3
3
  module BookStoreTest
4
4
 
@@ -59,3 +59,7 @@ let ``Three copies of first book and 2 each of remaining`` () =
59
59
  let ``Three each of first 2 books and 2 each of remaining books`` () =
60
60
  total [1; 1; 2; 2; 3; 3; 4; 4; 5; 5; 1; 2] |> should equal 75.20
61
61
 
62
+ [<Fact(Skip = "Remove to run test")>]
63
+ let ``Four groups of four are cheaper than two groups each of five and three`` () =
64
+ total [1; 1; 2; 2; 3; 3; 4; 5; 1; 1; 2; 2; 3; 3; 4; 5] |> should equal 102.40
65
+
@@ -1,4 +1,4 @@
1
- // This file was auto-generated based on version 1.0.1 of the canonical data.
1
+ // This file was auto-generated based on version 1.1.0 of the canonical data.
2
2
 
3
3
  module RnaTranscriptionTest
4
4
 
@@ -27,15 +27,3 @@ let ``RNA complement of adenine is uracil`` () =
27
27
  let ``RNA complement`` () =
28
28
  toRna "ACGTGGTCTTAA" |> should equal (Some "UGCACCAGAAUU")
29
29
 
30
- [<Fact(Skip = "Remove to run test")>]
31
- let ``Correctly handles invalid input (RNA instead of DNA)`` () =
32
- toRna "U" |> should equal None
33
-
34
- [<Fact(Skip = "Remove to run test")>]
35
- let ``Correctly handles completely invalid DNA input`` () =
36
- toRna "XXX" |> should equal None
37
-
38
- [<Fact(Skip = "Remove to run test")>]
39
- let ``Correctly handles partially invalid DNA input`` () =
40
- toRna "ACGTXXXCTTAA" |> should equal None
41
-
@@ -37,15 +37,11 @@ let private updateToLatestVersion options =
37
37
  Log.Information("Updated repository to latest version.");
38
38
 
39
39
  let private downloadData options =
40
- if options.SkipUpdateCanonicalData then
40
+ if options.CacheCanonicalData then
41
41
  ()
42
42
  else
43
43
  cloneRepository options
44
- updateToLatestVersion options
45
-
46
- let private readCanonicalData options exercise =
47
- let exerciseCanonicalDataPath = Path.Combine(options.CanonicalDataDirectory, "exercises", exercise, "canonical-data.json")
48
- File.ReadAllText(exerciseCanonicalDataPath)
44
+ updateToLatestVersion options
49
45
 
50
46
  type CanonicalDataConverter() =
51
47
  inherit JsonConverter()
@@ -87,7 +83,18 @@ type CanonicalDataConverter() =
87
83
  override __.CanConvert(objectType: Type) = objectType = typeof<CanonicalData>
88
84
 
89
85
  let private convertCanonicalData canonicalDataContents =
90
- JsonConvert.DeserializeObject<CanonicalData>(canonicalDataContents, CanonicalDataConverter())
86
+ JsonConvert.DeserializeObject<CanonicalData>(canonicalDataContents, CanonicalDataConverter())
87
+
88
+ let private canonicalDataFile options exercise =
89
+ Path.Combine(options.CanonicalDataDirectory, "exercises", exercise, "canonical-data.json")
90
+
91
+ let private readCanonicalData options exercise =
92
+ canonicalDataFile options exercise
93
+ |> File.ReadAllText
94
+
95
+ let hasCanonicalData options exercise =
96
+ canonicalDataFile options exercise
97
+ |> File.Exists
91
98
 
92
99
  let parseCanonicalData options =
93
100
  downloadData options
@@ -3,14 +3,19 @@ module Generators.Exercise
3
3
  open System
4
4
  open System.IO
5
5
  open System.Reflection
6
+ open Newtonsoft.Json
6
7
  open Newtonsoft.Json.Linq
7
8
  open Humanizer
8
9
  open Serilog
9
10
  open Formatting
10
11
  open Rendering
12
+ open CanonicalData
13
+
14
+ let private exerciseNameFromType (exerciseType: Type) = exerciseType.Name.Kebaberize()
11
15
 
12
16
  [<AbstractClass>]
13
- type Exercise() =
17
+ type GeneratorExercise() =
18
+
14
19
  // Allow changes in canonical data
15
20
  abstract member MapCanonicalData : CanonicalData -> CanonicalData
16
21
  abstract member MapCanonicalDataCase : CanonicalDataCase -> CanonicalDataCase
@@ -56,7 +61,7 @@ type Exercise() =
56
61
  abstract member UseFullMethodName : CanonicalDataCase -> bool
57
62
  abstract member AdditionalNamespaces : string list
58
63
 
59
- member this.Name = this.GetType().Name.Kebaberize()
64
+ member this.Name = this.GetType() |> exerciseNameFromType
60
65
  member this.TestModuleName = this.GetType().Name.Pascalize() |> sprintf "%sTest"
61
66
  member this.TestedModuleName = this.GetType().Name.Pascalize()
62
67
 
@@ -66,8 +71,6 @@ type Exercise() =
66
71
  Directory.CreateDirectory(Path.GetDirectoryName(testClassPath)) |> ignore
67
72
  File.WriteAllText(testClassPath, contents)
68
73
 
69
- Log.Information("Generated tests for {Exercise} exercise in {TestClassPath}", this.Name, testClassPath);
70
-
71
74
  member this.Regenerate(canonicalData) =
72
75
  canonicalData
73
76
  |> this.MapCanonicalData
@@ -233,23 +236,86 @@ type Exercise() =
233
236
  default __.UseFullMethodName _ = false
234
237
 
235
238
  default __.AdditionalNamespaces = []
239
+
240
+ type CustomExercise() =
241
+
242
+ member this.Name = this.GetType().Name.Kebaberize()
243
+
244
+ type MissingDataExercise = { Name: string }
245
+
246
+ type UnimplementedExercise = { Name: string }
247
+
248
+ type Exercise =
249
+ | Generator of GeneratorExercise
250
+ | Custom of CustomExercise
251
+ | MissingData of MissingDataExercise
252
+ | Unimplemented of UnimplementedExercise
253
+
254
+ let exerciseName exercise =
255
+ match exercise with
256
+ | Generator generator -> generator.Name
257
+ | Custom custom -> custom.Name
258
+ | Unimplemented unimplemented -> unimplemented.Name
259
+ | MissingData missingData -> missingData.Name
260
+
261
+ type ConfigExercise = { Slug: string }
262
+
263
+ type Config = { Exercises: ConfigExercise[] }
264
+
265
+ let private exerciseNames =
266
+ let configFilePath = "../config.json"
267
+ let configFileContents = File.ReadAllText configFilePath
268
+ let config = JsonConvert.DeserializeObject<Config>(configFileContents)
269
+
270
+ config.Exercises
271
+ |> Seq.map (fun exercise -> exercise.Slug)
272
+ |> Seq.sort
273
+ |> Seq.toList
236
274
 
237
- let createExercises filteredExercise =
275
+ let private isConcreteType (ty: Type) = not ty.IsAbstract
238
276
 
239
- let isConcreteExercise (exerciseType: Type) =
240
- not exerciseType.IsAbstract && typeof<Exercise>.IsAssignableFrom(exerciseType)
277
+ let private isGeneratorExercise (ty: Type) = typeof<GeneratorExercise>.IsAssignableFrom(ty)
241
278
 
242
- let isFilteredExercise exercise (exerciseType: Type) =
243
- String.equals exercise exerciseType.Name ||
244
- String.equals exercise (exerciseType.Name.Kebaberize())
279
+ let private isCustomExercise (ty: Type) = typeof<CustomExercise>.IsAssignableFrom(ty)
245
280
 
246
- let includeExercise (exerciseType: Type) =
247
- match filteredExercise with
248
- | None -> isConcreteExercise exerciseType
249
- | Some exercise -> isConcreteExercise exerciseType && isFilteredExercise exercise exerciseType
281
+ let private concreteAssemblyTypes =
282
+ Assembly.GetEntryAssembly().GetTypes()
283
+ |> Array.filter isConcreteType
250
284
 
251
- let assemblyTypes = Assembly.GetEntryAssembly().GetTypes()
285
+ let private exerciseTypeByName<'T> exerciseType =
286
+ (exerciseNameFromType exerciseType, Activator.CreateInstance(exerciseType) :?> 'T)
252
287
 
253
- seq { for exerciseType in assemblyTypes do
254
- if includeExercise exerciseType then
255
- yield Activator.CreateInstance(exerciseType) :?> Exercise }
288
+ let private exerciseTypesByName<'T> predicate =
289
+ concreteAssemblyTypes
290
+ |> Array.filter predicate
291
+ |> Array.map exerciseTypeByName<'T>
292
+ |> Map.ofArray
293
+
294
+ let private generatorExercises = exerciseTypesByName<GeneratorExercise> isGeneratorExercise
295
+
296
+ let private customExercises = exerciseTypesByName<CustomExercise> isCustomExercise
297
+
298
+ let private tryFindGeneratorExercise exerciseName =
299
+ generatorExercises
300
+ |> Map.tryFind exerciseName
301
+ |> Option.map Generator
302
+
303
+ let private tryFindCustomExercise exerciseName =
304
+ customExercises
305
+ |> Map.tryFind exerciseName
306
+ |> Option.map Custom
307
+
308
+ let private tryFindUnimplementedExercise options exerciseName =
309
+ match hasCanonicalData options exerciseName with
310
+ | true -> Unimplemented { Name = exerciseName } |> Some
311
+ | false -> None
312
+
313
+ let private createExercise options exerciseName =
314
+ tryFindGeneratorExercise exerciseName
315
+ |> Option.orElse (tryFindCustomExercise exerciseName)
316
+ |> Option.orElse (tryFindUnimplementedExercise options exerciseName)
317
+ |> Option.orElse (MissingData { Name = exerciseName } |> Some)
318
+
319
+ let createExercises options =
320
+ exerciseNames
321
+ |> List.choose (createExercise options)
@@ -7,13 +7,13 @@ open Formatting
7
7
  open Exercise
8
8
 
9
9
  type Acronym() =
10
- inherit Exercise()
10
+ inherit GeneratorExercise()
11
11
 
12
12
  type AtbashCipher() =
13
- inherit Exercise()
13
+ inherit GeneratorExercise()
14
14
 
15
15
  type AllYourBase() =
16
- inherit Exercise()
16
+ inherit GeneratorExercise()
17
17
 
18
18
  override __.RenderExpected (_, _, value) =
19
19
  value
@@ -23,7 +23,7 @@ type AllYourBase() =
23
23
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
24
24
 
25
25
  type Allergies() =
26
- inherit Exercise()
26
+ inherit GeneratorExercise()
27
27
 
28
28
  let toAllergen (jToken: JToken) = sprintf "Allergen.%s" (jToken.ToString() |> String.humanize)
29
29
 
@@ -59,7 +59,7 @@ type Allergies() =
59
59
  | _ -> base.RenderInput (canonicalDataCase, key, value)
60
60
 
61
61
  type Alphametics() =
62
- inherit Exercise()
62
+ inherit GeneratorExercise()
63
63
 
64
64
  member __.formatMap<'TKey, 'TValue> (value: obj) =
65
65
  if isNull value then
@@ -82,19 +82,19 @@ type Alphametics() =
82
82
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
83
83
 
84
84
  type Anagram() =
85
- inherit Exercise()
85
+ inherit GeneratorExercise()
86
86
 
87
87
  override __.PropertiesWithIdentifier _ = ["candidates"]
88
88
 
89
89
  type ArmstrongNumbers() =
90
- inherit Exercise()
90
+ inherit GeneratorExercise()
91
91
 
92
92
  override __.RenderInput (_, _, value) =
93
93
  (value :?> JToken).Value("number")
94
94
  |> formatValue
95
95
 
96
96
  type BeerSong() =
97
- inherit Exercise()
97
+ inherit GeneratorExercise()
98
98
 
99
99
  override __.PropertiesUsedAsSutParameter _ = ["startBottles"; "takeDown"]
100
100
 
@@ -107,7 +107,7 @@ type BeerSong() =
107
107
  |> formatMultiLineList
108
108
 
109
109
  type BinarySearch() =
110
- inherit Exercise()
110
+ inherit GeneratorExercise()
111
111
 
112
112
  override __.PropertiesWithIdentifier _ = ["array"; "value"; "expected"]
113
113
 
@@ -123,10 +123,10 @@ type BinarySearch() =
123
123
  base.RenderValueWithoutIdentifier (canonicalDataCase, key, value)
124
124
 
125
125
  type Bob() =
126
- inherit Exercise()
126
+ inherit GeneratorExercise()
127
127
 
128
128
  type BookStore() =
129
- inherit Exercise()
129
+ inherit GeneratorExercise()
130
130
 
131
131
  let formatFloat (value:obj) = value :?> float |> sprintf "%.2f"
132
132
 
@@ -136,10 +136,10 @@ type BookStore() =
136
136
  base.PropertiesUsedAsSutParameter canonicalDataCase |> List.except ["targetgrouping"]
137
137
 
138
138
  type BracketPush() =
139
- inherit Exercise()
139
+ inherit GeneratorExercise()
140
140
 
141
141
  type Change() =
142
- inherit Exercise()
142
+ inherit GeneratorExercise()
143
143
 
144
144
  override __.RenderExpected (_, _, value) =
145
145
  let convertToOption = if value :? JArray then Option.ofObj else Option.ofNonNegativeInt
@@ -156,7 +156,7 @@ type Change() =
156
156
  | _ -> None
157
157
 
158
158
  type Clock() =
159
- inherit Exercise()
159
+ inherit GeneratorExercise()
160
160
 
161
161
  let createClock (value:obj) clockId =
162
162
  let clock = value :?> JObject
@@ -196,7 +196,7 @@ type Clock() =
196
196
  base.RenderSut canonicalDataCase
197
197
 
198
198
  type Connect() =
199
- inherit Exercise()
199
+ inherit GeneratorExercise()
200
200
 
201
201
  override __.RenderExpected (_, _, value) =
202
202
  match string value with
@@ -215,7 +215,7 @@ type Connect() =
215
215
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
216
216
 
217
217
  type CollatzConjecture() =
218
- inherit Exercise()
218
+ inherit GeneratorExercise()
219
219
 
220
220
  override __.RenderExpected (_, _, value) =
221
221
  value
@@ -224,13 +224,16 @@ type CollatzConjecture() =
224
224
  |> parenthesizeOption
225
225
 
226
226
  type CryptoSquare() =
227
- inherit Exercise()
227
+ inherit GeneratorExercise()
228
+
229
+ type Diamond() =
230
+ inherit CustomExercise()
228
231
 
229
232
  type DifferenceOfSquares() =
230
- inherit Exercise()
233
+ inherit GeneratorExercise()
231
234
 
232
235
  type Dominoes() =
233
- inherit Exercise()
236
+ inherit GeneratorExercise()
234
237
 
235
238
  let formatAsTuple (value:obj) =
236
239
  let twoElementList = value :?> JArray |> normalizeJArray
@@ -245,7 +248,7 @@ type Dominoes() =
245
248
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
246
249
 
247
250
  type Etl() =
248
- inherit Exercise()
251
+ inherit GeneratorExercise()
249
252
 
250
253
  member __.formatMap<'TKey, 'TValue> (value: obj) =
251
254
  let input = value :?> JObject
@@ -267,7 +270,7 @@ type Etl() =
267
270
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
268
271
 
269
272
  type FoodChain() =
270
- inherit Exercise()
273
+ inherit GeneratorExercise()
271
274
 
272
275
  override __.PropertiesUsedAsSutParameter _ = ["startVerse"; "endVerse"]
273
276
 
@@ -280,7 +283,7 @@ type FoodChain() =
280
283
  |> formatMultiLineList
281
284
 
282
285
  type Forth() =
283
- inherit Exercise()
286
+ inherit GeneratorExercise()
284
287
 
285
288
  override __.PropertiesWithIdentifier _ = ["expected"]
286
289
 
@@ -297,7 +300,7 @@ type Forth() =
297
300
  override __.UseFullMethodName _ = true
298
301
 
299
302
  type Gigasecond() =
300
- inherit Exercise()
303
+ inherit GeneratorExercise()
301
304
 
302
305
  override __.RenderExpected (_, _, value) = value :?> DateTime |> formatDateTime |> parenthesize
303
306
 
@@ -309,7 +312,7 @@ type Gigasecond() =
309
312
  override __.AdditionalNamespaces = [typeof<DateTime>.Namespace]
310
313
 
311
314
  type Grains() =
312
- inherit Exercise()
315
+ inherit GeneratorExercise()
313
316
 
314
317
  override __.PropertiesWithIdentifier _ = ["expected"]
315
318
 
@@ -321,7 +324,7 @@ type Grains() =
321
324
  | x -> sprintf "Ok %sUL" x
322
325
 
323
326
  type Hamming() =
324
- inherit Exercise()
327
+ inherit GeneratorExercise()
325
328
 
326
329
  override __.RenderExpected (_, _, value) =
327
330
  value
@@ -330,10 +333,10 @@ type Hamming() =
330
333
  |> parenthesizeOption
331
334
 
332
335
  type HelloWorld() =
333
- inherit Exercise()
336
+ inherit GeneratorExercise()
334
337
 
335
338
  type House() =
336
- inherit Exercise()
339
+ inherit GeneratorExercise()
337
340
 
338
341
  override __.PropertiesUsedAsSutParameter _ = ["startVerse"; "endVerse"]
339
342
 
@@ -346,13 +349,13 @@ type House() =
346
349
  |> formatMultiLineList
347
350
 
348
351
  type IsbnVerifier() =
349
- inherit Exercise()
352
+ inherit GeneratorExercise()
350
353
 
351
354
  type Isogram() =
352
- inherit Exercise()
355
+ inherit GeneratorExercise()
353
356
 
354
357
  type KindergartenGarden() =
355
- inherit Exercise()
358
+ inherit GeneratorExercise()
356
359
 
357
360
  let toPlant (jToken: JToken) = sprintf "Plant.%s" (jToken.ToString() |> String.humanize)
358
361
 
@@ -366,7 +369,7 @@ type KindergartenGarden() =
366
369
  override __.UseFullMethodName _ = true
367
370
 
368
371
  type LargestSeriesProduct() =
369
- inherit Exercise()
372
+ inherit GeneratorExercise()
370
373
 
371
374
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
372
375
 
@@ -377,13 +380,13 @@ type LargestSeriesProduct() =
377
380
  |> parenthesizeOption
378
381
 
379
382
  type Leap() =
380
- inherit Exercise()
383
+ inherit GeneratorExercise()
381
384
 
382
385
  type Luhn() =
383
- inherit Exercise()
386
+ inherit GeneratorExercise()
384
387
 
385
388
  type Markdown() =
386
- inherit Exercise()
389
+ inherit GeneratorExercise()
387
390
 
388
391
  override __.ToTestMethod (index, canonicalDataCase) =
389
392
  { base.ToTestMethod (index, canonicalDataCase) with Skip = false }
@@ -391,7 +394,7 @@ type Markdown() =
391
394
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
392
395
 
393
396
  type Meetup() =
394
- inherit Exercise()
397
+ inherit GeneratorExercise()
395
398
 
396
399
  override __.RenderExpected (canonicalDataCase, _, _) =
397
400
  let year = canonicalDataCase.Properties.["year"] :?> int64 |> int
@@ -417,7 +420,7 @@ type Meetup() =
417
420
  override this.AdditionalNamespaces = [typeof<DateTime>.Namespace]
418
421
 
419
422
  type Minesweeper() =
420
- inherit Exercise()
423
+ inherit GeneratorExercise()
421
424
 
422
425
  override __.RenderValueWithoutIdentifier (_, _, value) =
423
426
  value :?> JArray
@@ -433,7 +436,7 @@ type Minesweeper() =
433
436
  | false -> None
434
437
 
435
438
  type NthPrime() =
436
- inherit Exercise()
439
+ inherit GeneratorExercise()
437
440
 
438
441
  override __.RenderExpected (_, _, value) =
439
442
  value
@@ -442,7 +445,7 @@ type NthPrime() =
442
445
  |> parenthesizeOption
443
446
 
444
447
  type NucleotideCount() =
445
- inherit Exercise()
448
+ inherit GeneratorExercise()
446
449
 
447
450
  member __.formatMap<'TKey, 'TValue> (value: obj) =
448
451
  match Option.ofNonError value with
@@ -466,7 +469,7 @@ type NucleotideCount() =
466
469
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
467
470
 
468
471
  type OcrNumbers() =
469
- inherit Exercise()
472
+ inherit GeneratorExercise()
470
473
 
471
474
  override this.PropertiesWithIdentifier canonicalDataCase = this.PropertiesUsedAsSutParameter canonicalDataCase
472
475
 
@@ -483,10 +486,10 @@ type OcrNumbers() =
483
486
  |> formatMultiLineList
484
487
 
485
488
  type Pangram() =
486
- inherit Exercise()
489
+ inherit GeneratorExercise()
487
490
 
488
491
  type PalindromeProducts() =
489
- inherit Exercise()
492
+ inherit GeneratorExercise()
490
493
 
491
494
  let toFactors (value: obj) =
492
495
  let jArray = value :?> JArray
@@ -514,7 +517,7 @@ type PalindromeProducts() =
514
517
  override __.PropertiesUsedAsSutParameter _ = ["input_min"; "input_max"]
515
518
 
516
519
  type PascalsTriangle() =
517
- inherit Exercise()
520
+ inherit GeneratorExercise()
518
521
 
519
522
  override __.PropertiesWithIdentifier _ = ["expected"]
520
523
 
@@ -544,7 +547,7 @@ type PascalsTriangle() =
544
547
  override __.ToTestMethodBodyAssertTemplate _ = "AssertEqual"
545
548
 
546
549
  type PerfectNumbers() =
547
- inherit Exercise()
550
+ inherit GeneratorExercise()
548
551
 
549
552
  let toClassification value = string value |> String.humanize
550
553
 
@@ -556,7 +559,7 @@ type PerfectNumbers() =
556
559
  |> parenthesizeOption
557
560
 
558
561
  type PhoneNumber() =
559
- inherit Exercise()
562
+ inherit GeneratorExercise()
560
563
 
561
564
  override __.RenderExpected (_, _, value) =
562
565
  value
@@ -565,21 +568,21 @@ type PhoneNumber() =
565
568
  |> parenthesizeOption
566
569
 
567
570
  type PigLatin() =
568
- inherit Exercise()
571
+ inherit GeneratorExercise()
569
572
 
570
573
  type Poker() =
571
- inherit Exercise()
574
+ inherit GeneratorExercise()
572
575
 
573
576
  override __.PropertiesWithIdentifier _ = ["input"; "expected"]
574
577
 
575
578
  type PrimeFactors() =
576
- inherit Exercise()
579
+ inherit GeneratorExercise()
577
580
 
578
581
  override __.RenderInput (canonicalDataCase, key, value) =
579
582
  base.RenderInput (canonicalDataCase, key, value) |> sprintf "%sL"
580
583
 
581
584
  type Proverb() =
582
- inherit Exercise()
585
+ inherit GeneratorExercise()
583
586
 
584
587
  override __.PropertiesWithIdentifier _ = ["input"; "expected"]
585
588
 
@@ -595,7 +598,7 @@ type Proverb() =
595
598
  | false -> None
596
599
 
597
600
  type QueenAttack() =
598
- inherit Exercise()
601
+ inherit GeneratorExercise()
599
602
 
600
603
  override __.MapCanonicalDataCaseProperty (canonicalDataCase, key, value) =
601
604
  match canonicalDataCase.Property, key, value with
@@ -614,17 +617,17 @@ type QueenAttack() =
614
617
  override __.PropertiesWithIdentifier _ = ["white_queen"; "black_queen"]
615
618
 
616
619
  type RailFenceCipher() =
617
- inherit Exercise()
620
+ inherit GeneratorExercise()
618
621
 
619
622
  override __.PropertiesUsedAsSutParameter _ = ["rails"; "msg"]
620
623
 
621
624
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
622
625
 
623
626
  type Raindrops() =
624
- inherit Exercise()
627
+ inherit GeneratorExercise()
625
628
 
626
629
  type Rectangles() =
627
- inherit Exercise()
630
+ inherit GeneratorExercise()
628
631
 
629
632
  member private __.GetPadding n =
630
633
  String.replicate n " "
@@ -653,10 +656,10 @@ type Rectangles() =
653
656
  base.RenderValueWithoutIdentifier (canonicalDataCase, key, value)
654
657
 
655
658
  type ReverseString() =
656
- inherit Exercise()
659
+ inherit GeneratorExercise()
657
660
 
658
661
  type RobotSimulator() =
659
- inherit Exercise()
662
+ inherit GeneratorExercise()
660
663
 
661
664
  let resultIdentifierName = "actual"
662
665
 
@@ -748,16 +751,16 @@ type RobotSimulator() =
748
751
  sprintf "%s - %s" canonicalDataCase.Property (canonicalDataCase.Description |> String.upperCaseFirst)
749
752
 
750
753
  type RotationalCipher() =
751
- inherit Exercise()
754
+ inherit GeneratorExercise()
752
755
 
753
756
  type RnaTranscription() =
754
- inherit Exercise()
757
+ inherit GeneratorExercise()
755
758
 
756
759
  override __.RenderExpected (_, _, value) =
757
760
  value |> Option.ofObj |> formatValue |> parenthesizeOption
758
761
 
759
762
  type RunLengthEncoding() =
760
- inherit Exercise()
763
+ inherit GeneratorExercise()
761
764
 
762
765
  override this.RenderSut canonicalDataCase =
763
766
  match canonicalDataCase.Property with
@@ -775,13 +778,13 @@ type RunLengthEncoding() =
775
778
  sprintf "%s %s" canonicalDataCase.Property canonicalDataCase.Description |> String.upperCaseFirst
776
779
 
777
780
  type RomanNumerals() =
778
- inherit Exercise()
781
+ inherit GeneratorExercise()
779
782
 
780
783
  type ScrabbleScore() =
781
- inherit Exercise()
784
+ inherit GeneratorExercise()
782
785
 
783
786
  type SpiralMatrix() =
784
- inherit Exercise()
787
+ inherit GeneratorExercise()
785
788
 
786
789
  override __.RenderExpected (_, _, value) =
787
790
  (value :?> JArray)
@@ -790,7 +793,7 @@ type SpiralMatrix() =
790
793
  |> formatMultiLineList
791
794
 
792
795
  type TwelveDays() =
793
- inherit Exercise()
796
+ inherit GeneratorExercise()
794
797
 
795
798
  override __.PropertiesUsedAsSutParameter _ = ["startVerse"; "endVerse"]
796
799
 
@@ -803,7 +806,7 @@ type TwelveDays() =
803
806
  |> formatMultiLineList
804
807
 
805
808
  type TwoFer() =
806
- inherit Exercise()
809
+ inherit GeneratorExercise()
807
810
 
808
811
  override __.RenderInput (_, _, value) =
809
812
  value |> Option.ofObj |> formatValue |> parenthesizeOption