trackler 2.0.6.9 → 2.0.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/csharp/exercises/luhn/LuhnTest.cs +5 -5
  4. data/tracks/fsharp/exercises/luhn/LuhnTest.fs +5 -5
  5. data/tracks/fsharp/exercises/tree-building/Example.fs +6 -0
  6. data/tracks/fsharp/exercises/tree-building/TreeBuilding.fs +15 -0
  7. data/tracks/fsharp/exercises/tree-building/TreeBuildingTest.fs +97 -14
  8. data/tracks/go/config.json +1 -1
  9. data/tracks/go/exercises/TRACK_HINTS.md +1 -1
  10. data/tracks/ocaml/config.json +5 -0
  11. data/tracks/ocaml/exercises/dominoes/.merlin +3 -0
  12. data/tracks/ocaml/exercises/dominoes/Makefile +11 -0
  13. data/tracks/ocaml/exercises/dominoes/dominoes.mli +3 -0
  14. data/tracks/ocaml/exercises/dominoes/example.ml +51 -0
  15. data/tracks/ocaml/exercises/dominoes/test.ml +60 -0
  16. data/tracks/ruby/.travis.yml +0 -1
  17. data/tracks/ruby/README.md +13 -23
  18. data/tracks/ruby/Rakefile +19 -4
  19. data/tracks/ruby/bin/local-status-check +1 -1
  20. data/tracks/ruby/lib/tasks/exercise.rb +42 -0
  21. data/tracks/ruby/lib/tasks/exercise_test_tasks.rb +40 -0
  22. data/tracks/ruby/lib/tasks/exercise_tests_runner.rb +33 -0
  23. data/tracks/ruby/test/tasks/exercise_test.rb +46 -0
  24. data/tracks/ruby/test/tasks/exercise_test_tasks_test.rb +49 -0
  25. data/tracks/ruby/test/tasks/exercise_tests_runner_test.rb +64 -0
  26. data/tracks/ruby/test/test_helper.rb +10 -1
  27. data/tracks/scala/config.json +3 -0
  28. data/tracks/scala/exercises/luhn/build.sbt +2 -2
  29. data/tracks/scala/exercises/luhn/example.scala +19 -12
  30. data/tracks/scala/exercises/luhn/src/test/scala/LuhnTest.scala +18 -21
  31. metadata +13 -3
  32. data/tracks/ruby/Makefile +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b14825c924ae155ef47cfae4208988fc6fe0792a
4
- data.tar.gz: d95acda90518c0b892a492427df1449ada88ef61
3
+ metadata.gz: 953233b1b3c26056a61ba8b0155589068f8a106e
4
+ data.tar.gz: 8111432be32d72c9ee0b52448735add2f6a11333
5
5
  SHA512:
6
- metadata.gz: 6b246ba31cee380b84c8419cd4cc55ef0e52955888e5f1da274fff1956a71f9f5cb81e6f4625be50dc2d4a82d26650aee8372b2cde6377e3a149c083d681ae0d
7
- data.tar.gz: 2248d24225e54c4ea418a19cdf51e68140f5993e92d869866a0553023b6623ab83f9a385b1a408910db48a21bf398ea4c76bae8cb3876909020b818deb91d84c
6
+ metadata.gz: 0f3b82d836515898a1a27435d01d86748105835110af07ccd8d05a542a0735e24a7112b005cda5aed1e0dc7aa96cbf7daba2b212f44ac70b9225f021d3e7ba36
7
+ data.tar.gz: 49a6dc1f57ba27a0afa3af2260caf0d8cddcf49148566f893b2434c7dd44ba25ccc2efadd51d619193f5ee8d29e7f81443da39f89b34262d74791d4ae8a2488f
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.0.6.9"
2
+ VERSION = "2.0.6.10"
3
3
  end
@@ -4,11 +4,11 @@ using NUnit.Framework;
4
4
  public class LuhnTest
5
5
  {
6
6
  [TestCase("1", ExpectedResult = false)] // single digit strings can not be valid
7
- [TestCase("0", ExpectedResult = false, Ignore = "Remove to run test")] // a single zero is invalid
8
- [TestCase("046 454 286", ExpectedResult = true, Ignore = "Remove to run test")] // valid Canadian SIN
9
- [TestCase("046 454 287", ExpectedResult = false, Ignore = "Remove to run test")] // invalid Canadian SIN
10
- [TestCase("8273 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test")] // invalid credit card
11
- [TestCase("827a 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test")] // strings that contain non-digits are not valid
7
+ [TestCase("0", ExpectedResult = false, Ignore = "Remove to run test case")] // a single zero is invalid
8
+ [TestCase("046 454 286", ExpectedResult = true, Ignore = "Remove to run test case")] // valid Canadian SIN
9
+ [TestCase("046 454 287", ExpectedResult = false, Ignore = "Remove to run test case")] // invalid Canadian SIN
10
+ [TestCase("8273 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test case")] // invalid credit card
11
+ [TestCase("827a 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test case")] // strings that contain non-digits are not valid
12
12
  public bool ValidateChecksum(string number)
13
13
  {
14
14
  return Luhn.IsValid(number);
@@ -4,10 +4,10 @@ open NUnit.Framework
4
4
  open Luhn
5
5
 
6
6
  [<TestCase("1", ExpectedResult = false)>] // single digit strings can not be valid
7
- [<TestCase("0", ExpectedResult = false, Ignore = "Remove to run test")>] // a single zero is invalid
8
- [<TestCase("046 454 286", ExpectedResult = true, Ignore = "Remove to run test")>] // valid Canadian SIN
9
- [<TestCase("046 454 287", ExpectedResult = false, Ignore = "Remove to run test")>] // invalid Canadian SIN
10
- [<TestCase("8273 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test")>] // invalid credit card
11
- [<TestCase("827a 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test")>] // strings that contain non-digits are not valid
7
+ [<TestCase("0", ExpectedResult = false, Ignore = "Remove to run test case")>] // a single zero is invalid
8
+ [<TestCase("046 454 286", ExpectedResult = true, Ignore = "Remove to run test case")>] // valid Canadian SIN
9
+ [<TestCase("046 454 287", ExpectedResult = false, Ignore = "Remove to run test case")>] // invalid Canadian SIN
10
+ [<TestCase("8273 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test case")>] // invalid credit card
11
+ [<TestCase("827a 1232 7352 0569", ExpectedResult = false, Ignore = "Remove to run test case")>] // strings that contain non-digits are not valid
12
12
  let ``Validate checksum`` number =
13
13
  valid number
@@ -5,6 +5,12 @@ type Tree =
5
5
  | Branch of int * Tree list
6
6
  | Leaf of int
7
7
 
8
+ let recordId = function Branch (id, _) | Leaf id -> id
9
+
10
+ let isBranch = function Branch _ -> true | Leaf _ -> false
11
+
12
+ let children = function Branch (_, children') -> children' | Leaf _ -> []
13
+
8
14
  let rootNodeRecordId = 0
9
15
 
10
16
  let addOrAppend key value map =
@@ -5,6 +5,21 @@ type Tree =
5
5
  | Branch of int * Tree list
6
6
  | Leaf of int
7
7
 
8
+ let recordId t =
9
+ match t with
10
+ | Branch (id, c) -> id
11
+ | Leaf id -> id
12
+
13
+ let isBranch t =
14
+ match t with
15
+ | Branch (id, c) -> true
16
+ | Leaf id -> false
17
+
18
+ let children t =
19
+ match t with
20
+ | Branch (id, c) -> c
21
+ | Leaf id -> []
22
+
8
23
  let buildTree records =
9
24
  let records' = List.sortBy (fun x -> x.RecordId) records
10
25
 
@@ -10,8 +10,12 @@ let ``One node`` () =
10
10
  [
11
11
  { RecordId = 0; ParentId = 0 }
12
12
  ]
13
- let expected = Leaf 0
14
- Assert.That(buildTree input, Is.EqualTo(expected))
13
+
14
+ let tree = buildTree input
15
+
16
+ Assert.That(isBranch tree, Is.False)
17
+ Assert.That(recordId tree, Is.EqualTo(0))
18
+ Assert.That(children tree, Is.EqualTo([]))
15
19
 
16
20
  [<Test>]
17
21
  let ``Three nodes in order`` () =
@@ -21,8 +25,18 @@ let ``Three nodes in order`` () =
21
25
  { RecordId = 1; ParentId = 0 };
22
26
  { RecordId = 2; ParentId = 0 };
23
27
  ]
24
- let expected = Branch (0, [Leaf 1; Leaf 2])
25
- Assert.That(buildTree input, Is.EqualTo(expected))
28
+
29
+ let tree = buildTree input
30
+
31
+ Assert.That(isBranch tree, Is.True)
32
+ Assert.That(recordId tree, Is.EqualTo(0))
33
+ Assert.That(children tree |> List.length, Is.EqualTo(2))
34
+
35
+ Assert.That(children tree |> List.item 0 |> isBranch, Is.False)
36
+ Assert.That(children tree |> List.item 0 |> recordId, Is.EqualTo(1))
37
+
38
+ Assert.That(children tree |> List.item 1 |> isBranch, Is.False)
39
+ Assert.That(children tree |> List.item 1 |> recordId, Is.EqualTo(2))
26
40
 
27
41
  [<Test>]
28
42
  let ``Three nodes in reverse order`` () =
@@ -32,8 +46,18 @@ let ``Three nodes in reverse order`` () =
32
46
  { RecordId = 1; ParentId = 0 };
33
47
  { RecordId = 0; ParentId = 0 };
34
48
  ]
35
- let expected = Branch (0, [Leaf 1; Leaf 2])
36
- Assert.That(buildTree input, Is.EqualTo(expected))
49
+
50
+ let tree = buildTree input
51
+
52
+ Assert.That(isBranch tree, Is.True)
53
+ Assert.That(recordId tree, Is.EqualTo(0))
54
+ Assert.That(children tree |> List.length, Is.EqualTo(2))
55
+
56
+ Assert.That(children tree |> List.item 0 |> isBranch, Is.False)
57
+ Assert.That(children tree |> List.item 0 |> recordId, Is.EqualTo(1))
58
+
59
+ Assert.That(children tree |> List.item 1 |> isBranch, Is.False)
60
+ Assert.That(children tree |> List.item 1 |> recordId, Is.EqualTo(2))
37
61
 
38
62
  [<Test>]
39
63
  let ``More than two children`` () =
@@ -44,8 +68,21 @@ let ``More than two children`` () =
44
68
  { RecordId = 1; ParentId = 0 };
45
69
  { RecordId = 0; ParentId = 0 };
46
70
  ]
47
- let expected = Branch (0, [Leaf 1; Leaf 2; Leaf 3])
48
- Assert.That(buildTree input, Is.EqualTo(expected))
71
+
72
+ let tree = buildTree input
73
+
74
+ Assert.That(isBranch tree, Is.True)
75
+ Assert.That(recordId tree, Is.EqualTo(0))
76
+ Assert.That(children tree |> List.length, Is.EqualTo(3))
77
+
78
+ Assert.That(children tree |> List.item 0 |> isBranch, Is.False)
79
+ Assert.That(children tree |> List.item 0 |> recordId, Is.EqualTo(1))
80
+
81
+ Assert.That(children tree |> List.item 1 |> isBranch, Is.False)
82
+ Assert.That(children tree |> List.item 1 |> recordId, Is.EqualTo(2))
83
+
84
+ Assert.That(children tree |> List.item 2 |> isBranch, Is.False)
85
+ Assert.That(children tree |> List.item 2 |> recordId, Is.EqualTo(3))
49
86
 
50
87
  [<Test>]
51
88
  let ``Binary tree`` () =
@@ -59,9 +96,32 @@ let ``Binary tree`` () =
59
96
  { RecordId = 0; ParentId = 0 };
60
97
  { RecordId = 6; ParentId = 2 }
61
98
  ]
62
- let expected = Branch (0, [ Branch (1, [Leaf 4; Leaf 5]);
63
- Branch (2, [Leaf 3; Leaf 6]) ])
64
- Assert.That(buildTree input, Is.EqualTo(expected))
99
+
100
+ let tree = buildTree input
101
+
102
+ Assert.That(isBranch tree, Is.True)
103
+ Assert.That(recordId tree, Is.EqualTo(0))
104
+ Assert.That(children tree |> List.length, Is.EqualTo(2))
105
+
106
+ Assert.That(children tree |> List.item 0 |> isBranch, Is.True)
107
+ Assert.That(children tree |> List.item 0 |> recordId, Is.EqualTo(1))
108
+ Assert.That(children tree |> List.item 0 |> children |> List.length, Is.EqualTo(2))
109
+
110
+ Assert.That(children tree |> List.item 0 |> children |> List.item 0 |> isBranch, Is.False)
111
+ Assert.That(children tree |> List.item 0 |> children |> List.item 0 |> recordId, Is.EqualTo(4))
112
+
113
+ Assert.That(children tree |> List.item 0 |> children |> List.item 1 |> isBranch, Is.False)
114
+ Assert.That(children tree |> List.item 0 |> children |> List.item 1 |> recordId, Is.EqualTo(5))
115
+
116
+ Assert.That(children tree |> List.item 1 |> isBranch, Is.True)
117
+ Assert.That(children tree |> List.item 1 |> recordId, Is.EqualTo(2))
118
+ Assert.That(children tree |> List.item 1 |> children |> List.length, Is.EqualTo(2))
119
+
120
+ Assert.That(children tree |> List.item 1 |> children |> List.item 0 |> isBranch, Is.False)
121
+ Assert.That(children tree |> List.item 1 |> children |> List.item 0 |> recordId, Is.EqualTo(3))
122
+
123
+ Assert.That(children tree |> List.item 1 |> children |> List.item 1 |> isBranch, Is.False)
124
+ Assert.That(children tree |> List.item 1 |> children |> List.item 1 |> recordId, Is.EqualTo(6))
65
125
 
66
126
  [<Test>]
67
127
  let ``Unbalanced tree`` () =
@@ -75,9 +135,32 @@ let ``Unbalanced tree`` () =
75
135
  { RecordId = 0; ParentId = 0 };
76
136
  { RecordId = 6; ParentId = 2 }
77
137
  ]
78
- let expected = Branch (0, [ Branch (1, [Leaf 4]);
79
- Branch (2, [Leaf 3; Leaf 5; Leaf 6]) ])
80
- Assert.That(buildTree input, Is.EqualTo(expected))
138
+
139
+ let tree = buildTree input
140
+
141
+ Assert.That(isBranch tree, Is.True)
142
+ Assert.That(recordId tree, Is.EqualTo(0))
143
+ Assert.That(children tree |> List.length, Is.EqualTo(2))
144
+
145
+ Assert.That(children tree |> List.item 0 |> isBranch, Is.True)
146
+ Assert.That(children tree |> List.item 0 |> recordId, Is.EqualTo(1))
147
+ Assert.That(children tree |> List.item 0 |> children |> List.length, Is.EqualTo(1))
148
+
149
+ Assert.That(children tree |> List.item 0 |> children |> List.item 0 |> isBranch, Is.False)
150
+ Assert.That(children tree |> List.item 0 |> children |> List.item 0 |> recordId, Is.EqualTo(4))
151
+
152
+ Assert.That(children tree |> List.item 1 |> isBranch, Is.True)
153
+ Assert.That(children tree |> List.item 1 |> recordId, Is.EqualTo(2))
154
+ Assert.That(children tree |> List.item 1 |> children |> List.length, Is.EqualTo(3))
155
+
156
+ Assert.That(children tree |> List.item 1 |> children |> List.item 0 |> isBranch, Is.False)
157
+ Assert.That(children tree |> List.item 1 |> children |> List.item 0 |> recordId, Is.EqualTo(3))
158
+
159
+ Assert.That(children tree |> List.item 1 |> children |> List.item 1 |> isBranch, Is.False)
160
+ Assert.That(children tree |> List.item 1 |> children |> List.item 1 |> recordId, Is.EqualTo(5))
161
+
162
+ Assert.That(children tree |> List.item 1 |> children |> List.item 2 |> isBranch, Is.False)
163
+ Assert.That(children tree |> List.item 1 |> children |> List.item 2 |> recordId, Is.EqualTo(6))
81
164
 
82
165
  [<Test>]
83
166
  let ``Empty input`` () =
@@ -29,7 +29,7 @@
29
29
  "difficulty": 1,
30
30
  "slug": "hello-world",
31
31
  "topics": [
32
- "Control-flow (if-else statements)",
32
+ "Control-flow (conditionals)",
33
33
  "Optional values",
34
34
  "Strings",
35
35
  "Text formatting"
@@ -1,4 +1,4 @@
1
- To run the tests simply run the command `go test` in the exercise directory.
1
+ To run the tests run the command `go test` from within the exercise directory.
2
2
 
3
3
  If the test suite contains benchmarks, you can run these with the `-bench`
4
4
  flag:
@@ -141,6 +141,11 @@
141
141
  "difficulty": 7,
142
142
  "topics": []
143
143
  },
144
+ {
145
+ "slug": "dominoes",
146
+ "difficulty": 7,
147
+ "topics": []
148
+ },
144
149
  {
145
150
  "slug": "custom-set",
146
151
  "difficulty": 8,
@@ -0,0 +1,3 @@
1
+ S *
2
+ B _build/**
3
+ PKG core oUnit
@@ -0,0 +1,11 @@
1
+ test: test.native
2
+ @./test.native
3
+
4
+ test.native: *.ml *.mli
5
+ @corebuild -r -quiet -pkg oUnit test.native
6
+
7
+ clean:
8
+ rm -rf _build
9
+ rm -f test.native
10
+
11
+ .PHONY: clean
@@ -0,0 +1,3 @@
1
+ type dominoe = (int * int)
2
+
3
+ val chain : dominoe list -> (dominoe list) option
@@ -0,0 +1,51 @@
1
+ (* Based off the Haskell solution by Tarmean at http://exercism.io/submissions/6dc2eef7e7eb469d8657111fc4389fc0 *)
2
+
3
+ open Core.Std
4
+
5
+ type dominoe = int * int
6
+
7
+ (* Functions from Haskell that I can't find in Core! *)
8
+
9
+ let zip_with (xs: 'a list) (ys: 'b list) ~(f: 'a -> 'b -> 'c) =
10
+ let rec go xs ys acc = match (xs,ys) with
11
+ | (x::xs,y::ys) -> go xs ys @@ (f x y)::acc
12
+ | _ -> acc
13
+ in
14
+ List.rev @@ go xs ys []
15
+
16
+ let tails (xs: 'a list): ('a list) list =
17
+ let rec go acc = function
18
+ | [] -> [] :: acc
19
+ | (x::xs) as l -> go (l :: acc) xs
20
+ in
21
+ List.rev @@ go [] xs
22
+
23
+ let inits (xs: 'a list): ('a list) list =
24
+ List.rev xs |> tails |> List.map ~f:List.rev |> List.rev
25
+
26
+ let listToOption = function
27
+ | [] -> None
28
+ | (x :: _) -> Some x
29
+
30
+ (* The implementation *)
31
+
32
+ let left (ds: dominoe list): int = ds |> List.hd_exn |> fst
33
+ let right (ds: dominoe list): int = ds |> List.last_exn |> snd
34
+ let choose_from (ls: 'a list): ('a * 'a list) list =
35
+ List.zip_exn ls @@ zip_with ~f:List.append (inits ls) (List.tl_exn (tails ls))
36
+
37
+ let rec attach_to path ((a, b), rest) =
38
+ let lp = left path in
39
+ if b = lp then go rest ((a,b)::path)
40
+ else if a = lp then go rest ((b,a)::path)
41
+ else []
42
+ and go stones path = match stones with
43
+ | [] -> if left path = right path then [path] else []
44
+ | _ -> let open List.Monad_infix in choose_from stones >>= attach_to path
45
+
46
+ let chain_non_empty (first: dominoe) (rest: dominoe list): (dominoe list) option =
47
+ listToOption @@ go rest [first]
48
+
49
+ let chain = function
50
+ | [] -> Some []
51
+ | first::rest -> chain_non_empty first rest
@@ -0,0 +1,60 @@
1
+ open Core.Std
2
+ open OUnit2
3
+ open Dominoes
4
+
5
+ let print_dominoe (d1, d2) = sprintf "(%d,%d)" d1 d2
6
+
7
+ let option_printer = function
8
+ | None -> "None"
9
+ | Some xs -> "Some [" ^ String.concat ~sep:";" (List.map xs ~f:print_dominoe) ^ "]"
10
+
11
+ let drop_1_right xs = List.rev xs |> List.tl_exn |> List.rev
12
+
13
+ let check_chain (chained: dominoe list) =
14
+ let assert_dominoes_match d1 d2 =
15
+ if snd d1 <> fst d2 then failwith @@ sprintf "%s and %s cannot be chained together" (print_dominoe d1) (print_dominoe d2) else () in
16
+ let consecutives = List.zip_exn (drop_1_right chained) (List.tl_exn chained) in
17
+ List.iter consecutives ~f:(fun (d1, d2) -> assert_dominoes_match d1 d2)
18
+
19
+ let assert_empty c = if List.is_empty c then () else failwith "Expected 0 length chain"
20
+
21
+ let assert_valid_chain input _ctxt =
22
+ match chain input with
23
+ | None -> failwith "Expecting a chain"
24
+ | Some(c) -> (if List.is_empty input then assert_empty else check_chain) c
25
+
26
+ let assert_no_chain input _ctxt =
27
+ assert_equal None (chain input) ~printer:option_printer
28
+
29
+ let assert_chain input hasChain =
30
+ if hasChain then assert_valid_chain input else assert_no_chain input
31
+
32
+ let tests = [
33
+ "empty input = empty output" >::
34
+ assert_chain [] true;
35
+ "singleton input = singleton output" >::
36
+ assert_chain [(1,1)] true;
37
+ "singleton that can't be chained" >::
38
+ assert_chain [(1,2)] false;
39
+ "three elements" >::
40
+ assert_chain [(1,2); (3,1); (2,3)] true;
41
+ "can reverse dominoes" >::
42
+ assert_chain [(1,2); (1,3); (2,3)] true;
43
+ "can't be chained" >::
44
+ assert_chain [(1,2); (4,1); (2,3)] false;
45
+ "disconnected - simple" >::
46
+ assert_chain [(1,1); (2,2)] false;
47
+ "disconnected - double loop" >::
48
+ assert_chain [(1,2); (2,1); (3,4); (4,3)] false;
49
+ "disconnected - single isolated" >::
50
+ assert_chain [(1,2); (2,3); (3,1); (4,4)] false;
51
+ "need backtrack" >::
52
+ assert_chain [(1,2); (2,3); (3,1); (2,4); (2,4)] true;
53
+ "separate loops" >::
54
+ assert_chain [(1,2); (2,3); (3,1); (1,1); (2,2); (3,3)] true;
55
+ "ten elements" >::
56
+ assert_chain [(1,2); (5,3); (3,1); (1,2); (2,4); (1,6); (2,3); (3,4); (5,6)] true;
57
+ ]
58
+
59
+ let () =
60
+ run_test_tt_main ("dominoes tests" >::: tests)
@@ -9,6 +9,5 @@ script:
9
9
  - rubocop -fs -D
10
10
  - bin/executable-tests-check
11
11
  - rake test
12
- - make test
13
12
  - bin/fetch-configlet
14
13
  - bin/configlet .
@@ -34,42 +34,32 @@ suite, you can run the file with a shim that temporarily disables them:
34
34
  ruby -I./lib -rdisable_skip exercise/exercise/filename_test.rb
35
35
  ```
36
36
 
37
- It is simpler to use the `make` tool which is available in the project
37
+ It is simpler to use the `rake` tool which is available in the project
38
38
  root. It will disable the skip calls for you automatically, it does the
39
39
  same thing as the above.
40
40
 
41
- If you would like to use the `make` tool to run a single test, while
41
+ If you would like to use the `rake` tool to run a single test while
42
42
  developing clock, for example, you can do something like this:
43
43
 
44
44
  ```sh
45
- ASSIGNMENT=clock ARGS='-p' make test-assignment
45
+ rake test:clock
46
46
  ```
47
47
 
48
- Where, "ASSIGNMENT" is the variable that holds the name of the lesson,
49
- clock.
50
-
51
- ARGS is where you can put additional arguments, here I am demonstrating
52
- the `-p` argument which may give you 'pride' output.
53
-
54
- If you use zsh, you can use the following function to make this process
55
- simple.
56
-
48
+ To pass arguments to the test command, like `-p` for example, you can run
49
+ the following:
57
50
  ```sh
58
- xtest () { ASSIGNMENT=$1 ARGS=$2 make test-assignment }
51
+ rake test:clock -- -p
59
52
  ```
60
53
 
61
- Then you can simply use the command and exercise name, such as:
62
-
63
- `xtest binary`
64
-
65
- Or if you would like to use an option such as displaying the test names
66
- rather than just the dots, for example:
67
-
68
- `xtest clock -v`
54
+ To show an example of running a limited number of tests, we will use the
55
+ "hamming" exercise with a pattern of "identical" to run (currently) two tests:
56
+ ```sh
57
+ rake test:hamming -- -p -n="/identical/"
58
+ ```
69
59
 
70
- Or with the pride reporter activated:
60
+ Note that flags which have an attached value, like above, must take the form
61
+ `-flag=value` and if `value` has spaces `-flag="value with spaces"`.
71
62
 
72
- `xtest robot-name -p`
73
63
 
74
64
  ### Generated Test Suites
75
65
 
data/tracks/ruby/Rakefile CHANGED
@@ -1,9 +1,24 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
3
 
4
- desc 'rake with no argument will run "rake test"'
5
- task default: :test
4
+ require_relative 'lib/tasks/exercise_test_tasks'
6
5
 
7
- Rake::TestTask.new do |task|
8
- task.pattern = 'test/**/*_test.rb'
6
+ task default: 'test'
7
+
8
+ desc 'Run individual exercises or run all development and exercise tests'
9
+ task :test do
10
+ Rake::Task['test:dev'].invoke
11
+ Rake::Task['test:exercises'].invoke
12
+ end
13
+
14
+ namespace :test do
15
+ flags = ARGV.drop_while { |e| e != '--' }.drop(1).join(' ')
16
+
17
+ desc 'Run all development tests located in the test directory'
18
+ Rake::TestTask.new :dev do |task|
19
+ task.options = flags
20
+ task.pattern = 'test/**/*_test.rb'
21
+ end
22
+
23
+ ExerciseTestTasks.new options: flags
9
24
  end
@@ -3,7 +3,7 @@
3
3
  puts "Starting #{__FILE__} checks..."
4
4
 
5
5
  commands_to_run = [
6
- 'make test',
6
+ 'rake test',
7
7
  'bundle exec rubocop -fs -D',
8
8
  'bin/executable-tests-check',
9
9
  ]
@@ -0,0 +1,42 @@
1
+ class Exercise
2
+ class << self
3
+ def all
4
+ exercise_names.map { |e| new(e) }
5
+ end
6
+
7
+ private
8
+
9
+ def exercise_names
10
+ FileList['exercises/*'].pathmap('%f').exclude('TRACK_HINTS.md')
11
+ end
12
+ end
13
+
14
+ attr_reader :name
15
+ alias :to_s :name
16
+
17
+ def initialize(name)
18
+ @name = name
19
+ end
20
+
21
+ def directory
22
+ "exercises/#{name}/."
23
+ end
24
+
25
+ def example_file
26
+ 'example.rb'
27
+ end
28
+
29
+ def testable_example_file
30
+ "#{base_file_name}.rb"
31
+ end
32
+
33
+ def test_file
34
+ "#{base_file_name}_test.rb"
35
+ end
36
+
37
+ private
38
+
39
+ def base_file_name
40
+ @_base_file_name ||= name.tr('-', '_')
41
+ end
42
+ end
@@ -0,0 +1,40 @@
1
+ require 'rake/dsl_definition'
2
+
3
+ require_relative 'exercise'
4
+ require_relative 'exercise_tests_runner'
5
+
6
+ class ExerciseTestTasks
7
+ include Rake::DSL
8
+
9
+ def initialize(options:, test_runner: ExerciseTestsRunner)
10
+ @options = options
11
+ @test_runner = test_runner
12
+
13
+ define
14
+ end
15
+
16
+ def define
17
+ define_task_for_all_exercises
18
+
19
+ exercises.each { |exercise| define_task_for(exercise) }
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :options, :test_runner
25
+
26
+ def exercises
27
+ @_exercises ||= Exercise.all
28
+ end
29
+
30
+ def define_task_for_all_exercises
31
+ desc 'Run the tests for all exercises'
32
+ task exercises: exercises
33
+ end
34
+
35
+ def define_task_for(exercise)
36
+ task exercise do
37
+ test_runner.new(exercise: exercise, test_options: options).run
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ require "rake/file_utils_ext"
2
+ require 'tmpdir'
3
+
4
+ class ExerciseTestsRunner
5
+ include Rake::FileUtilsExt
6
+
7
+ def initialize(exercise:, test_options: '')
8
+ @exercise = exercise
9
+ @test_options = test_options
10
+ end
11
+
12
+ def run
13
+ puts "\n\n#{'-'*64}\nrunning tests for: #{exercise}"
14
+
15
+ Dir.mktmpdir(exercise.name) do |dir|
16
+ setup_exercise_files_in(dir)
17
+ run_exercise_tests_in(dir)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :exercise, :test_options
24
+
25
+ def setup_exercise_files_in(dir)
26
+ FileUtils.cp_r exercise.directory, dir
27
+ FileUtils.mv "#{dir}/#{exercise.example_file}", "#{dir}/#{exercise.testable_example_file}"
28
+ end
29
+
30
+ def run_exercise_tests_in(dir)
31
+ ruby "-I lib -r disable_skip.rb #{dir}/#{exercise.test_file} #{test_options}"
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ require_relative '../test_helper'
2
+ require 'tmpdir'
3
+
4
+ class ExerciseTest < Minitest::Test
5
+ def test_all
6
+ Dir.mktmpdir('exercise-test') do |dir|
7
+ FileUtils.mkdir "#{dir}/test"
8
+ FileUtils.mkdir "#{dir}/test2"
9
+ FileUtils.touch "#{dir}/TRACK_HINTS.md"
10
+
11
+ FileList.stub :[], FileList["#{dir}/*"] do
12
+ assert_equal true, Exercise.all.all? { |e| e.instance_of?(Exercise) }
13
+ assert_equal ['test', 'test2'], Exercise.all.map(&:name)
14
+ end
15
+ end
16
+ end
17
+
18
+ def test_name
19
+ exercise = Exercise.new('name')
20
+ assert_equal 'name', exercise.name
21
+ end
22
+
23
+ def test_to_s
24
+ exercise = Exercise.new('name')
25
+ assert_equal 'name', exercise.to_s
26
+ end
27
+
28
+ def test_directory
29
+ exercise = Exercise.new('exercise_name')
30
+ assert_equal 'exercises/exercise_name/.', exercise.directory
31
+ end
32
+
33
+ def test_example_file
34
+ assert_equal 'example.rb', Exercise.new('').example_file
35
+ end
36
+
37
+ def test_testable_example_file
38
+ exercise = Exercise.new('all-your-base')
39
+ assert_equal 'all_your_base.rb', exercise.testable_example_file
40
+ end
41
+
42
+ def test_test_file
43
+ exercise = Exercise.new('all-your-base')
44
+ assert_equal 'all_your_base_test.rb', exercise.test_file
45
+ end
46
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../test_helper'
2
+
3
+ class ExerciseTestTasksTest < Minitest::Test
4
+ def test_all_exercises_task
5
+ setup_rake
6
+
7
+ Exercise.stub :all, ['test1', 'test2'] do
8
+ ExerciseTestTasks.new(options: '')
9
+
10
+ assert_equal ['test1', 'test2'], Rake::Task['exercises'].prerequisites
11
+ assert_equal 'Run the tests for all exercises', Rake::Task['exercises'].comment
12
+ end
13
+ end
14
+
15
+ def test_individual_exercise_tasks
16
+ setup_rake
17
+
18
+ Exercise.stub :all, ['test1', 'test2'] do
19
+ mock_test_runner_instance = Minitest::Mock.new
20
+ mock_test_runner_instance.expect :run, nil
21
+ mock_test_runner_instance.expect :run, nil
22
+
23
+ mock_test_runner = Minitest::Mock.new
24
+ mock_test_runner.expect(
25
+ :new,
26
+ mock_test_runner_instance,
27
+ [exercise: 'test1', test_options: '-p'],
28
+ )
29
+ mock_test_runner.expect(
30
+ :new,
31
+ mock_test_runner_instance,
32
+ [exercise: 'test2', test_options: '-p'],
33
+ )
34
+
35
+ ExerciseTestTasks.new(options: '-p', test_runner: mock_test_runner)
36
+
37
+ Rake::Task['test1'].invoke
38
+ Rake::Task['test2'].invoke
39
+
40
+ mock_test_runner.verify
41
+ mock_test_runner_instance.verify
42
+ end
43
+ end
44
+
45
+ def setup_rake
46
+ Rake.application = Rake::Application.new
47
+ Rake::TaskManager.record_task_metadata = true
48
+ end
49
+ end
@@ -0,0 +1,64 @@
1
+ require_relative '../test_helper'
2
+
3
+ class FakeExercise
4
+ def name
5
+ 'test'
6
+ end
7
+
8
+ alias :to_s :name
9
+
10
+ def directory
11
+ 'test/.'
12
+ end
13
+
14
+ def example_file
15
+ 'example.rb'
16
+ end
17
+
18
+ def testable_example_file
19
+ 'test.rb'
20
+ end
21
+
22
+ def test_file
23
+ 'test_test.rb'
24
+ end
25
+ end
26
+
27
+ class ExerciseTestsRunnerTest < Minitest::Test
28
+ def test_run
29
+ Dir.stub :mktmpdir, nil, 'dir' do
30
+ cp_mock = Minitest::Mock.new.expect(:call, nil, ['test/.', 'dir'])
31
+
32
+ mv_mock = Minitest::Mock.new.expect(
33
+ :call,
34
+ nil,
35
+ ['dir/example.rb', 'dir/test.rb'],
36
+ )
37
+
38
+ ruby_mock = Minitest::Mock.new.expect(
39
+ :call,
40
+ nil,
41
+ ['-I lib -r disable_skip.rb dir/test_test.rb -p'],
42
+ )
43
+
44
+ FileUtils.stub :cp_r, cp_mock do
45
+ FileUtils.stub :mv, mv_mock do
46
+ runner = ExerciseTestsRunner.new(
47
+ exercise: FakeExercise.new,
48
+ test_options: '-p',
49
+ )
50
+
51
+ runner.stub :ruby, ruby_mock do
52
+ assert_output "\n\n#{'-'*64}\nrunning tests for: test\n" do
53
+ runner.run
54
+ end
55
+ end
56
+
57
+ cp_mock.verify
58
+ mv_mock.verify
59
+ ruby_mock.verify
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -6,12 +6,21 @@ unless ENV['CI']
6
6
  require 'simplecov'
7
7
  SimpleCov.start do
8
8
  add_filter '/test/'
9
+
9
10
  add_group 'Generator' do |file|
10
11
  file.filename =~ /generator/
11
12
  end
13
+
14
+ add_group 'Tasks' do |file|
15
+ file.filename =~ /tasks/
16
+ end
17
+
12
18
  add_group 'Cases', '_cases.rb'
19
+
13
20
  add_group 'Other' do |file|
14
- !(file.filename =~ /_cases\.rb$/) && file.filename !~ /generator/
21
+ !(file.filename =~ /_cases\.rb$/) &&
22
+ file.filename !~ /generator/ &&
23
+ file.filename !~ /tasks/
15
24
  end
16
25
  end
17
26
  end
@@ -271,6 +271,9 @@
271
271
  "slug": "luhn",
272
272
  "difficulty": 1,
273
273
  "topics": [
274
+ "Strings",
275
+ "Algorithms",
276
+ "Transforming"
274
277
  ]
275
278
  },
276
279
  {
@@ -1,3 +1,3 @@
1
- scalaVersion := "2.11.7"
1
+ scalaVersion := "2.12.1"
2
2
 
3
- libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.5" % "test"
3
+ libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
@@ -1,23 +1,29 @@
1
- case class Luhn(number: Long) {
2
- lazy val checkDigit: Int = (number % 10).toInt
1
+ object Luhn {
3
2
 
4
- lazy val addends: List[Int] = {
5
- val zippedDigits = digits(number).zipWithIndex.reverse
3
+ def validate(numberStr: String): Boolean = {
4
+ def isCandidate(numberStr: String): Boolean =
5
+ numberStr.length > 1 &&
6
+ numberStr.forall(c => c.isDigit || c.isSpaceChar)
6
7
 
7
- zippedDigits.map{case (m, i) => if (isOdd(i)) dbl(m) else m}
8
- }
8
+ def toLong(numberStr: String): Long =
9
+ numberStr.filter(_.isDigit).toLong
9
10
 
10
- lazy val checksum: Int = addends.sum % 10
11
+ val number =
12
+ Option(numberStr) filter isCandidate map toLong
11
13
 
12
- lazy val isValid: Boolean = checksum % 10 == 0
14
+ number map (checksum(_) == 0) getOrElse false
15
+ }
13
16
 
14
- lazy val create: Long = {
15
- val m = number * 10
16
- val luhn = Luhn(m)
17
+ private def checkDigit(number: Long): Int = (number % 10).toInt
17
18
 
18
- if (luhn.isValid) m else m + (10 - luhn.checksum)
19
+ private def addends(number: Long): List[Int] = {
20
+ val zippedDigits = digits(number).zipWithIndex.reverse
21
+
22
+ zippedDigits.map{case (m, i) => if (isOdd(i)) dbl(m) else m}
19
23
  }
20
24
 
25
+ private def checksum(number: Long): Int = addends(number).sum % 10
26
+
21
27
  private def digits(n: Long): List[Int] = n match {
22
28
  case 0 => Nil
23
29
  case _ => List((n % 10).toInt) ++ digits(n / 10)
@@ -31,3 +37,4 @@ case class Luhn(number: Long) {
31
37
 
32
38
  private def isOdd(i: Int) = i % 2 == 1
33
39
  }
40
+
@@ -1,36 +1,33 @@
1
- import org.scalatest.{Matchers, FlatSpec}
1
+ import org.scalatest.{FunSuite, Matchers}
2
2
 
3
- class LuhnTest extends FlatSpec with Matchers {
4
- it should "create checkDigit" in {
5
- Luhn(34567).checkDigit should equal(7)
6
- Luhn(91370).checkDigit should equal(0)
7
- Luhn(0).checkDigit should equal(0)
3
+ class LuhnTest extends FunSuite with Matchers {
4
+ test("single digit strings can not be valid") {
5
+ Luhn.validate("1") should be (false)
8
6
  }
9
7
 
10
- it should "create addends" in {
8
+ test("A single zero is invalid") {
11
9
  pending
12
- Luhn(12121).addends should equal(List(1, 4, 1, 4, 1))
13
- Luhn(8631).addends should equal(List(7, 6, 6, 1))
10
+ Luhn.validate("0") should be (false)
14
11
  }
15
12
 
16
- it should "create checksum" in {
13
+ test("valid Canadian SIN") {
17
14
  pending
18
- // NOTE: this differs from the ruby and js, the checksum really should
19
- // be mod 10 like we are testing here.
20
- Luhn(4913).checksum should equal(2)
21
- Luhn(201773).checksum should equal(1)
15
+ Luhn.validate("046 454 286") should be (true)
22
16
  }
23
17
 
24
- it should "check validity" in {
18
+ test("invalid Canadian SIN") {
25
19
  pending
26
- Luhn(738).isValid should be (false)
27
- Luhn(8739567).isValid should be (true)
20
+ Luhn.validate("046 454 287") should be (false)
28
21
  }
29
22
 
30
- it should "create luhn values" in {
23
+ test("invalid credit card") {
31
24
  pending
32
- Luhn(123).create should be (1230)
33
- Luhn(873956).create should be (8739567)
34
- Luhn(837263756).create should be (8372637564L)
25
+ Luhn.validate("8273 1232 7352 0569") should be (false)
26
+ }
27
+
28
+ test("strings that contain non-digits are not valid") {
29
+ pending
30
+ Luhn.validate("827a 1232 7352 0569") should be (false)
35
31
  }
36
32
  }
33
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trackler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6.9
4
+ version: 2.0.6.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Katrina Owen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-11 00:00:00.000000000 Z
11
+ date: 2017-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -4913,6 +4913,11 @@ files:
4913
4913
  - tracks/ocaml/exercises/difference-of-squares/difference_of_squares.mli
4914
4914
  - tracks/ocaml/exercises/difference-of-squares/example.ml
4915
4915
  - tracks/ocaml/exercises/difference-of-squares/test.ml
4916
+ - tracks/ocaml/exercises/dominoes/.merlin
4917
+ - tracks/ocaml/exercises/dominoes/Makefile
4918
+ - tracks/ocaml/exercises/dominoes/dominoes.mli
4919
+ - tracks/ocaml/exercises/dominoes/example.ml
4920
+ - tracks/ocaml/exercises/dominoes/test.ml
4916
4921
  - tracks/ocaml/exercises/etl/.merlin
4917
4922
  - tracks/ocaml/exercises/etl/Makefile
4918
4923
  - tracks/ocaml/exercises/etl/etl.mli
@@ -5937,7 +5942,6 @@ files:
5937
5942
  - tracks/ruby/Gemfile
5938
5943
  - tracks/ruby/HINTS.md
5939
5944
  - tracks/ruby/LICENSE
5940
- - tracks/ruby/Makefile
5941
5945
  - tracks/ruby/README.md
5942
5946
  - tracks/ruby/Rakefile
5943
5947
  - tracks/ruby/bin/enable-executable
@@ -6235,6 +6239,9 @@ files:
6235
6239
  - tracks/ruby/lib/roman_numerals_cases.rb
6236
6240
  - tracks/ruby/lib/run_length_encoding_cases.rb
6237
6241
  - tracks/ruby/lib/sieve_cases.rb
6242
+ - tracks/ruby/lib/tasks/exercise.rb
6243
+ - tracks/ruby/lib/tasks/exercise_test_tasks.rb
6244
+ - tracks/ruby/lib/tasks/exercise_tests_runner.rb
6238
6245
  - tracks/ruby/lib/tournament_cases.rb
6239
6246
  - tracks/ruby/lib/transpose_cases.rb
6240
6247
  - tracks/ruby/lib/triangle_cases.rb
@@ -6256,6 +6263,9 @@ files:
6256
6263
  - tracks/ruby/test/generator/template_values_test.rb
6257
6264
  - tracks/ruby/test/generator_test.rb
6258
6265
  - tracks/ruby/test/grains_cases_test.rb
6266
+ - tracks/ruby/test/tasks/exercise_test.rb
6267
+ - tracks/ruby/test/tasks/exercise_test_tasks_test.rb
6268
+ - tracks/ruby/test/tasks/exercise_tests_runner_test.rb
6259
6269
  - tracks/ruby/test/test_helper.rb
6260
6270
  - tracks/ruby/test/wordy_cases_test.rb
6261
6271
  - tracks/rust/.git
data/tracks/ruby/Makefile DELETED
@@ -1,37 +0,0 @@
1
- .PHONY: test
2
-
3
- # assignments
4
- ASSIGNMENT ?= ""
5
- IGNOREDIRS := "^(\.git|bin|docs|lib|exercises)$$"
6
- ASSIGNMENTS = $(shell find ./exercises -maxdepth 1 -mindepth 1 -type d | awk -F/ '{print $$NF}' | sort | grep -Ev $(IGNOREDIRS))
7
-
8
- default: test
9
-
10
- # output directories
11
- TMPDIR ?= "/tmp/"
12
- OUTDIR := $(shell mktemp -d "$(TMPDIR)$(ASSIGNMENT).XXXXXXXXXX")
13
-
14
- # language specific config (tweakable per language)
15
- FILEEXT := "rb"
16
- EXAMPLE := "example.$(FILEEXT)"
17
- SRCFILE := "$(shell echo $(ASSIGNMENT) | sed 's/-/_/g')"
18
- TSTFILE := "$(SRCFILE)_test.$(FILEEXT)"
19
- # Any additional arguments, such as -p for pretty output and others
20
- ARGS ?= ""
21
-
22
- # single test
23
- test-assignment:
24
- @echo ""
25
- @echo ""
26
- @echo "----------------------------------------------------------------"
27
- @echo "running tests for: $(ASSIGNMENT)"
28
- @cp -r ./exercises/$(ASSIGNMENT)/* $(OUTDIR)
29
- @cp ./exercises/$(ASSIGNMENT)/$(EXAMPLE) $(OUTDIR)/$(SRCFILE).$(FILEEXT)
30
- @ruby -I./lib -rdisable_skip.rb $(OUTDIR)/$(TSTFILE) $(ARGS)
31
- @rm -rf $(OUTDIR)
32
-
33
- # all tests
34
- test:
35
- @for assignment in $(ASSIGNMENTS); do \
36
- ASSIGNMENT=$$assignment $(MAKE) -s test-assignment || exit 1;\
37
- done