trackler 2.2.1.75 → 2.2.1.76

Sign up to get free protection for your applications and to get access to all the features.
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