trackler 2.2.1.77 → 2.2.1.78

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/transpose/canonical-data.json +94 -116
  4. data/tracks/bash/config/maintainers.json +11 -1
  5. data/tracks/clojure/config.json +10 -2
  6. data/tracks/clojure/exercises/reverse-string/README.md +14 -0
  7. data/tracks/clojure/exercises/reverse-string/project.clj +4 -0
  8. data/tracks/clojure/exercises/reverse-string/src/example.clj +5 -0
  9. data/tracks/clojure/exercises/reverse-string/src/reverse_string.clj +5 -0
  10. data/tracks/clojure/exercises/reverse-string/test/reverse_string_test.clj +18 -0
  11. data/tracks/clojure/exercises/say/README.md +70 -0
  12. data/tracks/clojure/exercises/{two-fer → say}/project.clj +3 -3
  13. data/tracks/clojure/exercises/say/src/example.clj +9 -0
  14. data/tracks/clojure/exercises/say/src/say.clj +5 -0
  15. data/tracks/clojure/exercises/say/test/say_test.clj +48 -0
  16. data/tracks/coffeescript/docs/ABOUT.md +4 -9
  17. data/tracks/coffeescript/docs/INSTALLATION.md +2 -2
  18. data/tracks/erlang/exercises/pangram/rebar.config +1 -1
  19. data/tracks/erlang/exercises/pangram/src/example.erl +2 -3
  20. data/tracks/erlang/exercises/pangram/test/pangram_tests.erl +12 -13
  21. data/tracks/fsharp/exercises/grep/Example.fs +16 -20
  22. data/tracks/fsharp/exercises/grep/GrepTest.fs +154 -233
  23. data/tracks/fsharp/generators/Common.fs +7 -2
  24. data/tracks/fsharp/generators/Exercise.fs +51 -16
  25. data/tracks/fsharp/generators/Formatting.fs +13 -6
  26. data/tracks/fsharp/generators/Generators.fs +44 -14
  27. data/tracks/fsharp/generators/Rendering.fs +8 -1
  28. data/tracks/fsharp/generators/Templates/Generators/_GrepSetup.liquid +37 -0
  29. data/tracks/fsharp/generators/Templates/_TestClass.liquid +9 -3
  30. data/tracks/fsharp/generators/Templates/{_TestMethod.liquid → _TestFunction.liquid} +0 -0
  31. data/tracks/fsharp/generators/Templates/{_TestMethodBody.liquid → _TestFunctionBody.liquid} +0 -0
  32. data/tracks/fsharp/generators/Templates/_TestMember.liquid +3 -0
  33. data/tracks/fsharp/generators/Templates/_TestMemberBody.liquid +4 -0
  34. data/tracks/fsharp/generators/Templates/_TestModule.liquid +17 -0
  35. data/tracks/go/config.json +24 -0
  36. data/tracks/go/exercises/acronym/.meta/gen.go +5 -3
  37. data/tracks/go/exercises/acronym/acronym.go +0 -2
  38. data/tracks/go/exercises/acronym/cases_test.go +2 -2
  39. data/tracks/go/exercises/acronym/example.go +2 -3
  40. data/tracks/go/exercises/all-your-base/.meta/gen.go +9 -7
  41. data/tracks/go/exercises/all-your-base/cases_test.go +2 -2
  42. data/tracks/go/exercises/allergies/.meta/gen.go +10 -6
  43. data/tracks/go/exercises/allergies/cases_test.go +2 -2
  44. data/tracks/go/exercises/anagram/.meta/gen.go +7 -5
  45. data/tracks/go/exercises/anagram/cases_test.go +2 -2
  46. data/tracks/go/exercises/armstrong-numbers/.meta/gen.go +54 -0
  47. data/tracks/go/exercises/armstrong-numbers/armstrong_test.go +12 -0
  48. data/tracks/go/exercises/armstrong-numbers/cases_test.go +52 -0
  49. data/tracks/go/exercises/armstrong-numbers/example.go +24 -0
  50. data/tracks/go/exercises/binary-search/.meta/gen.go +7 -5
  51. data/tracks/go/exercises/binary-search/cases_test.go +2 -2
  52. data/tracks/go/exercises/book-store/.meta/gen.go +5 -3
  53. data/tracks/go/exercises/book-store/cases_test.go +2 -2
  54. data/tracks/go/exercises/connect/example.go +4 -5
  55. data/tracks/go/exercises/dominoes/.meta/gen.go +61 -0
  56. data/tracks/go/exercises/dominoes/.meta/hints.md +29 -0
  57. data/tracks/go/exercises/dominoes/README.md +67 -0
  58. data/tracks/go/exercises/dominoes/cases_test.go +72 -0
  59. data/tracks/go/exercises/dominoes/dominoes_test.go +106 -0
  60. data/tracks/go/exercises/dominoes/example.go +146 -0
  61. data/tracks/go/exercises/ledger/example.go +1 -1
  62. data/tracks/groovy/.gitignore +3 -0
  63. data/tracks/groovy/.travis.yml +10 -1
  64. data/tracks/groovy/bin/prepeare_exercise_builds.groovy +77 -0
  65. data/tracks/groovy/build.gradle +25 -0
  66. data/tracks/groovy/exercises/difference-of-squares/Example.groovy +3 -3
  67. data/tracks/groovy/exercises/gigasecond/GigasecondSpec.groovy +3 -3
  68. data/tracks/groovy/exercises/linked-list/{DoubleLinkedList.groovy → LinkedList.groovy} +0 -0
  69. data/tracks/groovy/exercises/linked-list/{DoubleLinkedListSpec.groovy → LinkedListSpec.groovy} +0 -0
  70. data/tracks/groovy/exercises/linked-list/README.md +1 -1
  71. data/tracks/groovy/gradle/wrapper/gradle-wrapper.jar +0 -0
  72. data/tracks/groovy/gradle/wrapper/gradle-wrapper.properties +6 -0
  73. data/tracks/groovy/gradlew +172 -0
  74. data/tracks/groovy/gradlew.bat +84 -0
  75. data/tracks/groovy/settings.gradle +9 -0
  76. data/tracks/ocaml/exercises/acronym/.merlin +1 -1
  77. data/tracks/ocaml/exercises/all-your-base/.merlin +1 -1
  78. data/tracks/ocaml/exercises/anagram/.merlin +1 -1
  79. data/tracks/ocaml/exercises/atbash-cipher/.merlin +1 -1
  80. data/tracks/ocaml/exercises/beer-song/.merlin +1 -1
  81. data/tracks/ocaml/exercises/binary-search/.merlin +1 -1
  82. data/tracks/ocaml/exercises/bob/.merlin +1 -1
  83. data/tracks/ocaml/exercises/bowling/.merlin +1 -1
  84. data/tracks/ocaml/exercises/change/.merlin +1 -1
  85. data/tracks/ocaml/exercises/difference-of-squares/.merlin +1 -1
  86. data/tracks/ocaml/exercises/etl/.merlin +1 -1
  87. data/tracks/ocaml/exercises/forth/.merlin +1 -1
  88. data/tracks/ocaml/exercises/grade-school/.merlin +1 -1
  89. data/tracks/ocaml/exercises/hamming/.merlin +1 -1
  90. data/tracks/ocaml/exercises/hangman/.merlin +1 -1
  91. data/tracks/ocaml/exercises/hello-world/.merlin +1 -1
  92. data/tracks/ocaml/exercises/hexadecimal/.merlin +1 -1
  93. data/tracks/ocaml/exercises/leap/.merlin +1 -1
  94. data/tracks/ocaml/exercises/list-ops/.merlin +1 -1
  95. data/tracks/ocaml/exercises/luhn/.merlin +1 -1
  96. data/tracks/ocaml/exercises/meetup/.merlin +1 -1
  97. data/tracks/ocaml/exercises/minesweeper/.merlin +1 -1
  98. data/tracks/ocaml/exercises/nucleotide-count/.merlin +1 -1
  99. data/tracks/ocaml/exercises/phone-number/.merlin +1 -1
  100. data/tracks/ocaml/exercises/prime-factors/.merlin +1 -1
  101. data/tracks/ocaml/exercises/raindrops/.merlin +1 -1
  102. data/tracks/ocaml/exercises/react/.merlin +1 -1
  103. data/tracks/ocaml/exercises/rectangles/.merlin +1 -1
  104. data/tracks/ocaml/exercises/rna-transcription/.merlin +1 -1
  105. data/tracks/ocaml/exercises/run-length-encoding/.merlin +1 -1
  106. data/tracks/ocaml/exercises/say/.merlin +1 -1
  107. data/tracks/ocaml/exercises/space-age/.merlin +1 -1
  108. data/tracks/ocaml/exercises/triangle/.merlin +1 -1
  109. data/tracks/ocaml/exercises/word-count/.merlin +1 -1
  110. data/tracks/ocaml/exercises/zipper/.merlin +1 -1
  111. data/tracks/typescript/config/maintainers.json +2 -2
  112. metadata +37 -12
  113. data/tracks/clojure/exercises/two-fer/README.md +0 -19
  114. data/tracks/clojure/exercises/two-fer/src/example.clj +0 -5
  115. data/tracks/clojure/exercises/two-fer/src/two_fer.clj +0 -5
  116. data/tracks/clojure/exercises/two-fer/test/two_fer_test.clj +0 -12
  117. data/tracks/erlang/exercises/pangram/include/exercism.hrl +0 -11
@@ -31,13 +31,18 @@ type TestMethodBodyAssert =
31
31
  { Sut: string
32
32
  Expected: string }
33
33
 
34
- type TestClass =
34
+ type TestFile =
35
35
  { Version: string
36
36
  ExerciseName: string
37
37
  TestModuleName: string
38
38
  TestedModuleName: string
39
39
  Namespaces: string list
40
- Methods: string list }
40
+ Methods: string list
41
+ Setup: string }
42
+
43
+ type TestFileFormat =
44
+ | Module
45
+ | Class
41
46
 
42
47
  module Logging =
43
48
  let setupLogger() =
@@ -23,17 +23,24 @@ type GeneratorExercise() =
23
23
  abstract member MapCanonicalDataCaseProperty : CanonicalDataCase * string * obj -> obj
24
24
 
25
25
  // Convert canonical data to representation used when rendering
26
- abstract member ToTestClass : CanonicalData -> TestClass
26
+ abstract member ToTestFile : CanonicalData -> TestFile
27
27
  abstract member ToTestMethod : int * CanonicalDataCase -> TestMethod
28
28
  abstract member ToTestMethodBody : CanonicalDataCase -> TestMethodBody
29
29
  abstract member ToTestMethodBodyAssert : CanonicalDataCase -> TestMethodBodyAssert
30
- abstract member ToTestMethodBodyAssertTemplate : CanonicalDataCase -> string
30
+
31
+ // Determine the templates to use when rendering
32
+ abstract member TestFileTemplate : string
33
+ abstract member TestMethodTemplate : int * CanonicalDataCase -> string
34
+ abstract member TestMethodBodyTemplate : CanonicalDataCase -> string
35
+ abstract member TestMethodBodyAssertTemplate : CanonicalDataCase -> string
36
+ abstract member TestFileFormat: TestFileFormat
31
37
 
32
38
  // Rendering of canonical data
33
39
  abstract member Render : CanonicalData -> string
34
- abstract member RenderTestMethod : int -> CanonicalDataCase -> string
40
+ abstract member RenderTestMethod : int * CanonicalDataCase -> string
35
41
  abstract member RenderTestMethodBody : CanonicalDataCase -> string
36
42
  abstract member RenderTestMethodName : CanonicalDataCase -> string
43
+ abstract member RenderSetup : CanonicalData -> string
37
44
 
38
45
  // Generic value/identifier rendering methods
39
46
  abstract member RenderValue : CanonicalDataCase * string * obj -> string
@@ -66,10 +73,10 @@ type GeneratorExercise() =
66
73
  member this.TestedModuleName = this.GetType().Name.Pascalize()
67
74
 
68
75
  member this.WriteToFile contents =
69
- let testClassPath = Path.Combine("..", "exercises", this.Name, sprintf "%s.fs" this.TestModuleName)
76
+ let testFilePath = Path.Combine("..", "exercises", this.Name, sprintf "%s.fs" this.TestModuleName)
70
77
 
71
- Directory.CreateDirectory(Path.GetDirectoryName(testClassPath)) |> ignore
72
- File.WriteAllText(testClassPath, contents)
78
+ Directory.CreateDirectory(Path.GetDirectoryName(testFilePath)) |> ignore
79
+ File.WriteAllText(testFilePath, contents)
73
80
 
74
81
  member this.Regenerate(canonicalData) =
75
82
  canonicalData
@@ -94,13 +101,16 @@ type GeneratorExercise() =
94
101
 
95
102
  // Convert canonical data to representation used when rendering
96
103
 
97
- default this.ToTestClass canonicalData =
104
+ default this.ToTestFile canonicalData =
105
+ let renderTestMethod i canonicalDataCase = this.RenderTestMethod(i, canonicalDataCase)
106
+
98
107
  { Version = canonicalData.Version
99
108
  ExerciseName = this.Name
100
109
  TestModuleName = this.TestModuleName
101
110
  TestedModuleName = this.TestedModuleName
102
111
  Namespaces = ["FsUnit.Xunit"; "Xunit"] @ this.AdditionalNamespaces
103
- Methods = List.mapi this.RenderTestMethod canonicalData.Cases }
112
+ Methods = List.mapi renderTestMethod canonicalData.Cases
113
+ Setup = this.RenderSetup canonicalData }
104
114
 
105
115
  default this.ToTestMethod (index, canonicalDataCase) =
106
116
  { Skip = index > 0
@@ -115,27 +125,50 @@ type GeneratorExercise() =
115
125
  { Sut = this.RenderSut canonicalDataCase
116
126
  Expected = this.RenderValueOrIdentifier (canonicalDataCase, "expected", canonicalDataCase.Expected) }
117
127
 
118
- default this.ToTestMethodBodyAssertTemplate canonicalDataCase =
128
+ // Determine the templates to use when rendering
129
+
130
+ default this.TestFileTemplate =
131
+ match this.TestFileFormat with
132
+ | Module -> "TestModule"
133
+ | Class -> "TestClass"
134
+
135
+ default this.TestMethodTemplate (_, _) =
136
+ match this.TestFileFormat with
137
+ | Module -> "TestFunction"
138
+ | Class -> "TestMember"
139
+
140
+ default this.TestMethodBodyTemplate _ =
141
+ match this.TestFileFormat with
142
+ | Module -> "TestFunctionBody"
143
+ | Class -> "TestMemberBody"
144
+
145
+ default this.TestMethodBodyAssertTemplate canonicalDataCase =
119
146
  match canonicalDataCase.Expected with
120
147
  | :? JArray as jArray when jArray.Count = 0 && not (List.contains "expected" (this.PropertiesWithIdentifier canonicalDataCase)) -> "AssertEmpty"
121
148
  | _ -> "AssertEqual"
122
149
 
150
+ default __.TestFileFormat = TestFileFormat.Module
151
+
123
152
  // Rendering of canonical data
124
153
 
125
154
  default this.Render canonicalData =
126
155
  canonicalData
127
- |> this.ToTestClass
128
- |> renderPartialTemplate "TestClass"
156
+ |> this.ToTestFile
157
+ |> renderPartialTemplate this.TestFileTemplate
158
+
159
+ default this.RenderTestMethod (index, canonicalDataCase) =
160
+ let template = this.TestMethodTemplate (index, canonicalDataCase)
129
161
 
130
- default this.RenderTestMethod index canonicalDataCase =
131
162
  (index, canonicalDataCase)
132
163
  |> this.ToTestMethod
133
- |> renderPartialTemplate "TestMethod"
164
+ |> renderPartialTemplate template
134
165
 
135
166
  default this.RenderTestMethodBody canonicalDataCase =
167
+ let template = this.TestMethodBodyTemplate canonicalDataCase
168
+
136
169
  canonicalDataCase
137
170
  |> this.ToTestMethodBody
138
- |> renderPartialTemplate "TestMethodBody"
171
+ |> renderPartialTemplate template
139
172
 
140
173
  default this.RenderTestMethodName canonicalDataCase =
141
174
  match this.UseFullMethodName canonicalDataCase with
@@ -144,7 +177,9 @@ type GeneratorExercise() =
144
177
  | true ->
145
178
  canonicalDataCase.DescriptionPath
146
179
  |> String.concat " - "
147
- |> String.upperCaseFirst
180
+ |> String.upperCaseFirst
181
+
182
+ default __.RenderSetup _ = ""
148
183
 
149
184
  // Generic value/identifier rendering methods
150
185
 
@@ -195,7 +230,7 @@ type GeneratorExercise() =
195
230
  |> List.choose renderArrangeProperty
196
231
 
197
232
  default this.RenderAssert canonicalDataCase =
198
- let template = this.ToTestMethodBodyAssertTemplate canonicalDataCase
233
+ let template = this.TestMethodBodyAssertTemplate canonicalDataCase
199
234
 
200
235
  canonicalDataCase
201
236
  |> this.ToTestMethodBodyAssert
@@ -121,7 +121,7 @@ let rec formatValue (value: obj) =
121
121
  | _ ->
122
122
  string value
123
123
 
124
- let formatCollection formatString collection =
124
+ let private formatCollection formatString collection =
125
125
  collection
126
126
  |> String.concat "; "
127
127
  |> sprintf formatString
@@ -132,7 +132,7 @@ let formatArray sequence = formatCollection "[|%s|]" sequence
132
132
 
133
133
  let formatSequence sequence = formatCollection "seq {%s}" sequence
134
134
 
135
- let formatMultiLineCollection (openPrefix, closePostfix) collection =
135
+ let private formatMultiLineCollection (openPrefix, closePostfix) collection indentation =
136
136
  match Seq.length collection with
137
137
  | 0 ->
138
138
  sprintf "%s%s" openPrefix closePostfix
@@ -153,15 +153,22 @@ let formatMultiLineCollection (openPrefix, closePostfix) collection =
153
153
  collection
154
154
  |> Seq.mapi formatLine
155
155
  |> Seq.toList
156
- |> List.map (indent 2)
156
+ |> List.map (indent indentation)
157
157
  |> String.concat "\n"
158
158
  |> sprintf "\n%s"
159
159
 
160
- let formatMultiLineList sequence = formatMultiLineCollection ("[", "]") sequence
161
160
 
162
- let formatMultiLineArray sequence = formatMultiLineCollection ("[|", "|]") sequence
161
+ let formatMultiLineListWithIndentation indentation sequence = formatMultiLineCollection ("[", "]") sequence indentation
163
162
 
164
- let formatMultiLineSequence sequence = formatMultiLineCollection ("seq {", "}") sequence
163
+ let formatMultiLineArrayWithIndentation indentation sequence = formatMultiLineCollection ("[|", "|]") sequence indentation
164
+
165
+ let formatMultiLineSequenceWithIndentation indentation sequence = formatMultiLineCollection ("seq {", "}") sequence indentation
166
+
167
+ let formatMultiLineList sequence = formatMultiLineListWithIndentation 2 sequence
168
+
169
+ let formatMultiLineArray sequence = formatMultiLineArrayWithIndentation 2 sequence
170
+
171
+ let formatMultiLineSequence sequence = formatMultiLineSequenceWithIndentation 2 sequence
165
172
 
166
173
  let formatMultiLineString strings =
167
174
  let length = Seq.length strings
@@ -4,6 +4,7 @@ open System
4
4
  open System.Globalization
5
5
  open Newtonsoft.Json.Linq
6
6
  open Formatting
7
+ open Rendering
7
8
  open Exercise
8
9
 
9
10
  type Acronym() =
@@ -61,7 +62,7 @@ type Allergies() =
61
62
  type Alphametics() =
62
63
  inherit GeneratorExercise()
63
64
 
64
- member __.formatMap<'TKey, 'TValue> (value: obj) =
65
+ member __.FormatMap<'TKey, 'TValue> (value: obj) =
65
66
  if isNull value then
66
67
  "None"
67
68
  else
@@ -77,7 +78,7 @@ type Alphametics() =
77
78
  else
78
79
  sprintf "%s |> Map.ofList |> Some" formattedList
79
80
 
80
- override this.RenderExpected (_, _, value) = this.formatMap<char, int> value
81
+ override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
81
82
 
82
83
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
83
84
 
@@ -164,7 +165,7 @@ type Clock() =
164
165
  let minute = clock.["minute"].ToObject<string>()
165
166
  sprintf "let %s = create %s %s" clockId hour minute
166
167
 
167
- member private this.renderPropertyValue canonicalDataCase property =
168
+ member private this.RenderPropertyValue canonicalDataCase property =
168
169
  this.RenderSutParameter (canonicalDataCase, property, Map.find property canonicalDataCase.Properties)
169
170
 
170
171
  override __.PropertiesWithIdentifier _ = ["clock1"; "clock2"]
@@ -177,8 +178,8 @@ type Clock() =
177
178
  override this.RenderArrange canonicalDataCase =
178
179
  match canonicalDataCase.Property with
179
180
  | "create" | "add" ->
180
- let hour = this.renderPropertyValue canonicalDataCase "hour"
181
- let minute = this.renderPropertyValue canonicalDataCase "minute"
181
+ let hour = this.RenderPropertyValue canonicalDataCase "hour"
182
+ let minute = this.RenderPropertyValue canonicalDataCase "minute"
182
183
  [sprintf "let clock = create %s %s" hour minute]
183
184
  | _ ->
184
185
  base.RenderArrange canonicalDataCase
@@ -188,7 +189,7 @@ type Clock() =
188
189
  | "create" ->
189
190
  sprintf "display clock"
190
191
  | "add" ->
191
- this.renderPropertyValue canonicalDataCase "add"
192
+ this.RenderPropertyValue canonicalDataCase "add"
192
193
  |> sprintf "add %s clock |> display"
193
194
  | "equal" ->
194
195
  "clock1 = clock2"
@@ -250,7 +251,7 @@ type Dominoes() =
250
251
  type Etl() =
251
252
  inherit GeneratorExercise()
252
253
 
253
- member __.formatMap<'TKey, 'TValue> (value: obj) =
254
+ member __.FormatMap<'TKey, 'TValue> (value: obj) =
254
255
  let input = value :?> JObject
255
256
  let dict = input.ToObject<Collections.Generic.Dictionary<'TKey, 'TValue>>();
256
257
  let formattedList =
@@ -263,9 +264,9 @@ type Etl() =
263
264
  else
264
265
  sprintf "%s |> Map.ofList" formattedList
265
266
 
266
- override this.RenderInput (_, _, value) = this.formatMap<int, List<char>> value
267
+ override this.RenderInput (_, _, value) = this.FormatMap<int, List<char>> value
267
268
 
268
- override this.RenderExpected (_, _, value) = this.formatMap<char, int> value
269
+ override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
269
270
 
270
271
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
271
272
 
@@ -323,6 +324,35 @@ type Grains() =
323
324
  | "-1" -> "Error \"Invalid input\""
324
325
  | x -> sprintf "Ok %sUL" x
325
326
 
327
+ type Grep() =
328
+ inherit GeneratorExercise()
329
+
330
+ override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
331
+
332
+ override __.RenderExpected (_, _, value) =
333
+ (value :?> JArray)
334
+ |> normalizeJArray
335
+ |> Seq.map formatValue
336
+ |> formatMultiLineListWithIndentation 3
337
+
338
+ override __.RenderSetup _ = renderPartialTemplate "Generators/GrepSetup" Map.empty<string, obj>
339
+
340
+ override __.RenderArrange canonicalDataCase =
341
+ base.RenderArrange canonicalDataCase @ [""; "createFiles() |> ignore"]
342
+
343
+ override __.IdentifierTypeAnnotation (canonicalDataCase, key, value) =
344
+ match key with
345
+ | "expected" ->
346
+ match value :?> JArray |> Seq.isEmpty with
347
+ | true -> Some "string list"
348
+ | false -> None
349
+ | _ ->
350
+ base.IdentifierTypeAnnotation(canonicalDataCase, key, value)
351
+
352
+ override __.AdditionalNamespaces = [typeof<System.IO.File>.Namespace]
353
+
354
+ override __.TestFileFormat = TestFileFormat.Class
355
+
326
356
  type Hamming() =
327
357
  inherit GeneratorExercise()
328
358
 
@@ -417,7 +447,7 @@ type Meetup() =
417
447
  override __.PropertiesUsedAsSutParameter _ =
418
448
  ["year"; "month"; "dayofweek"; "week"]
419
449
 
420
- override this.AdditionalNamespaces = [typeof<DateTime>.Namespace]
450
+ override __.AdditionalNamespaces = [typeof<DateTime>.Namespace]
421
451
 
422
452
  type Minesweeper() =
423
453
  inherit GeneratorExercise()
@@ -447,7 +477,7 @@ type NthPrime() =
447
477
  type NucleotideCount() =
448
478
  inherit GeneratorExercise()
449
479
 
450
- member __.formatMap<'TKey, 'TValue> (value: obj) =
480
+ member __.FormatMap<'TKey, 'TValue> (value: obj) =
451
481
  match Option.ofNonError value with
452
482
  | None ->
453
483
  "None"
@@ -464,7 +494,7 @@ type NucleotideCount() =
464
494
  else
465
495
  sprintf "%s |> Map.ofList |> Some" formattedList
466
496
 
467
- override this.RenderExpected (_, _, value) = this.formatMap<char, int> value
497
+ override this.RenderExpected (_, _, value) = this.FormatMap<char, int> value
468
498
 
469
499
  override this.PropertiesWithIdentifier canonicalDataCase = this.Properties canonicalDataCase
470
500
 
@@ -544,7 +574,7 @@ type PascalsTriangle() =
544
574
  | false -> None
545
575
  | _ -> base.IdentifierTypeAnnotation (canonicalDataCase, key, value)
546
576
 
547
- override __.ToTestMethodBodyAssertTemplate _ = "AssertEqual"
577
+ override __.TestMethodBodyAssertTemplate _ = "AssertEqual"
548
578
 
549
579
  type PerfectNumbers() =
550
580
  inherit GeneratorExercise()
@@ -770,7 +800,7 @@ type RunLengthEncoding() =
770
800
  | _ ->
771
801
  base.RenderSut canonicalDataCase
772
802
 
773
- override this.RenderTestMethodName canonicalDataCase =
803
+ override __.RenderTestMethodName canonicalDataCase =
774
804
  match canonicalDataCase.Property with
775
805
  | "consistency" ->
776
806
  base.RenderTestMethodName canonicalDataCase
@@ -7,6 +7,7 @@ open FSharp.Reflection
7
7
  open DotLiquid
8
8
  open DotLiquid.FileSystems
9
9
  open Formatting
10
+ open System.Collections
10
11
 
11
12
  type OutputFilter() =
12
13
  static member Format (input: string) = formatValue input
@@ -47,11 +48,17 @@ let rec private registerTypeTree templateDataType =
47
48
  registrations.[templateDataType] <- true
48
49
  for p in properties do registerTypeTree p.PropertyType
49
50
 
51
+ let private hashFromData (data: obj) =
52
+ match FSharpType.IsRecord (data.GetType()) with
53
+ | true -> Hash.FromAnonymousObject(data)
54
+ | false -> Hash.FromDictionary(data :?> IDictionary<string, obj>)
55
+
50
56
  let renderInlineTemplate template data =
51
57
  data.GetType() |> registerTypeTree
52
58
 
53
59
  let parsedTemplate = Template.Parse template
54
- parsedTemplate.Render(Hash.FromAnonymousObject(data))
60
+ let hash = hashFromData data
61
+ parsedTemplate.Render(hash)
55
62
 
56
63
  let renderPartialTemplate templateName data =
57
64
  let template = sprintf "{%% include \"%s\" %%}" templateName
@@ -0,0 +1,37 @@
1
+ let iliadFileName = "iliad.txt"
2
+ let iliadContents =
3
+ """Achilles sing, O Goddess! Peleus' son;
4
+ His wrath pernicious, who ten thousand woes
5
+ Caused to Achaia's host, sent many a soul
6
+ Illustrious into Ades premature,
7
+ And Heroes gave (so stood the will of Jove)
8
+ To dogs and to all ravening fowls a prey,
9
+ When fierce dispute had separated once
10
+ The noble Chief Achilles from the son
11
+ Of Atreus, Agamemnon, King of men."""
12
+
13
+ let midsummerNightFileName = "midsummer-night.txt"
14
+ let midsummerNightContents =
15
+ """I do entreat your grace to pardon me.
16
+ I know not by what power I am made bold,
17
+ Nor how it may concern my modesty,
18
+ In such a presence here to plead my thoughts;
19
+ But I beseech your grace that I may know
20
+ The worst that may befall me in this case,
21
+ If I refuse to wed Demetrius."""
22
+
23
+ let paradiseLostFileName = "paradise-lost.txt"
24
+ let paradiseLostContents =
25
+ """Of Mans First Disobedience, and the Fruit
26
+ Of that Forbidden Tree, whose mortal tast
27
+ Brought Death into the World, and all our woe,
28
+ With loss of Eden, till one greater Man
29
+ Restore us, and regain the blissful Seat,
30
+ Sing Heav'nly Muse, that on the secret top
31
+ Of Oreb, or of Sinai, didst inspire
32
+ That Shepherd, who first taught the chosen Seed"""
33
+
34
+ let createFiles() =
35
+ File.WriteAllText(iliadFileName, iliadContents)
36
+ File.WriteAllText(midsummerNightFileName, midsummerNightContents)
37
+ File.WriteAllText(paradiseLostFileName, paradiseLostContents)
@@ -7,7 +7,13 @@ open {{ namespace }}
7
7
  {%- endfor -%}
8
8
 
9
9
  open {{ TestedModuleName }}
10
+ {%- if Setup != empty -%}
10
11
 
11
- {%- for method in Methods -%}
12
- {{ method }}
13
- {%- endfor -%}
12
+ {{ Setup }}
13
+ {%- endif -%}
14
+
15
+ type {{ TestModuleName }}() =
16
+
17
+ {%- for method in Methods -%}
18
+ {{ method }}
19
+ {%- endfor -%}
@@ -0,0 +1,3 @@
1
+ [<Fact{% if Skip %}(Skip = "Remove to run test"){% endif %}>]
2
+ member this.``{{ Name }}`` () =
3
+ {{ Body }}
@@ -0,0 +1,4 @@
1
+ {%- for arrange in Arrange -%}
2
+ {{ arrange | indent | indent }}
3
+ {%- endfor -%}
4
+ {{ Assert | indent | indent }}