trackler 2.0.3.4 → 2.0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/all-your-base/canonical-data.json +21 -21
  3. data/common/exercises/wordy/description.md +24 -38
  4. data/common/exercises/wordy/metadata.yml +1 -1
  5. data/lib/trackler/version.rb +1 -1
  6. data/tracks/c/config.json +10 -0
  7. data/tracks/c/exercises/meetup/makefile +15 -0
  8. data/tracks/c/exercises/meetup/src/example.c +139 -0
  9. data/tracks/c/exercises/meetup/src/example.h +7 -0
  10. data/tracks/c/exercises/meetup/test/test_meetup.c +223 -0
  11. data/tracks/c/exercises/meetup/test/vendor/unity.c +1300 -0
  12. data/tracks/c/exercises/meetup/test/vendor/unity.h +274 -0
  13. data/tracks/c/exercises/meetup/test/vendor/unity_internals.h +701 -0
  14. data/tracks/crystal/config.json +12 -0
  15. data/tracks/crystal/exercises/pascals-triangle/spec/pascals_triangle_spec.cr +30 -0
  16. data/tracks/crystal/exercises/pascals-triangle/src/example.cr +19 -0
  17. data/tracks/crystal/exercises/pascals-triangle/src/pascals_triangle.cr +1 -0
  18. data/tracks/crystal/exercises/run-length-encoding/spec/run_length_encoding_spec.cr +36 -0
  19. data/tracks/crystal/exercises/run-length-encoding/src/example.cr +40 -0
  20. data/tracks/crystal/src/generator/exercises/pascals-triangle.cr +58 -0
  21. data/tracks/crystal/src/generator/exercises/run_length_encoding.cr +42 -0
  22. data/tracks/javascript/config.json +8 -1
  23. data/tracks/javascript/exercises/all-your-base/all-your-base.spec.js +141 -0
  24. data/tracks/javascript/exercises/all-your-base/example.js +59 -0
  25. data/tracks/javascript/exercises/word-count/example.js +5 -5
  26. data/tracks/javascript/exercises/word-count/word-count.spec.js +23 -8
  27. data/tracks/lua/SETUP.md +60 -7
  28. data/tracks/lua/config.json +9 -0
  29. data/tracks/lua/exercises/say/example.lua +4 -4
  30. data/tracks/lua/exercises/variable-length-quantity/example.lua +36 -0
  31. data/tracks/lua/exercises/variable-length-quantity/variable-length-quantity_spec.lua +73 -0
  32. data/tracks/objective-c/.travis.yml +1 -0
  33. data/tracks/objective-c/config.json +8 -0
  34. data/tracks/objective-c/docs/TESTS.md +1 -1
  35. data/tracks/objective-c/exercises/transpose/TransposeExample.h +7 -0
  36. data/tracks/objective-c/exercises/transpose/TransposeExample.m +59 -0
  37. data/tracks/objective-c/exercises/transpose/TransposeTest.m +150 -0
  38. data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
  39. data/tracks/ocaml/.gitignore +1 -0
  40. data/tracks/ocaml/tools/test-generator/Makefile +3 -0
  41. data/tracks/ocaml/tools/test-generator/src/controller.ml +11 -16
  42. data/tracks/ocaml/tools/test-generator/src/model.ml +4 -0
  43. data/tracks/ocaml/tools/test-generator/src/parser.ml +8 -1
  44. data/tracks/ocaml/tools/test-generator/src/special_cases.ml +5 -0
  45. data/tracks/ocaml/tools/test-generator/templates/all-your-base/template.ml +16 -0
  46. data/tracks/ocaml/tools/test-generator/test/model_test.ml +2 -0
  47. data/tracks/ocaml/tools/test-generator/test/parser_test.ml +8 -0
  48. data/tracks/perl5/docs/RESOURCES.md +57 -0
  49. data/tracks/perl5/exercises/hamming/Example.pm +7 -0
  50. data/tracks/perl5/exercises/hamming/hamming.t +17 -4
  51. data/tracks/perl5/exercises/rna-transcription/rna.t +4 -4
  52. data/tracks/perl6/.gitignore +2 -0
  53. data/tracks/perl6/config.json +5 -0
  54. data/tracks/perl6/exercises/phone-number/Example.pm +30 -0
  55. data/tracks/perl6/exercises/phone-number/cases.json +47 -0
  56. data/tracks/perl6/exercises/phone-number/phone.t +48 -0
  57. data/tracks/purescript/.gitignore +8 -0
  58. data/tracks/purescript/config.json +8 -3
  59. data/tracks/purescript/exercises/hello-world/bower.json +17 -0
  60. data/tracks/purescript/exercises/hello-world/examples/src/HelloWorld.purs +8 -0
  61. data/tracks/purescript/exercises/hello-world/src/HelloWorld.purs +6 -0
  62. data/tracks/purescript/exercises/hello-world/test/Main.purs +18 -0
  63. data/tracks/scala/exercises/leap/HINTS.md +4 -0
  64. data/tracks/scala/exercises/robot-name/HINTS.md +5 -0
  65. data/tracks/swift/docs/INSTALLATION.md +4 -1
  66. data/tracks/swift/exercises/accumulate/AccumulateTest.swift +1 -1
  67. data/tracks/swift/exercises/binary/BinaryExample.swift +4 -1
  68. data/tracks/swift/exercises/crypto-square/CryptoSquareExample.swift +3 -2
  69. data/tracks/swift/exercises/leap/LeapExample.swift +1 -3
  70. data/tracks/swift/exercises/pascals-triangle/PascalsTriangleTest.swift +1 -1
  71. data/tracks/swift/exercises/poker/PokerExample.swift +3 -3
  72. data/tracks/swift/exercises/poker/PokerTest.swift +38 -38
  73. data/tracks/swift/exercises/saddle-points/SaddlePointsTest.swift +1 -1
  74. data/tracks/swift/exercises/scrabble-score/ScrabbleScoreExample.swift +6 -3
  75. data/tracks/swift/exercises/series/SeriesTest.swift +1 -1
  76. data/tracks/swift/exercises/simple-linked-list/SimpleLinkedListExample.swift +2 -2
  77. data/tracks/swift/exercises/space-age/SpaceAgeExample.swift +10 -12
  78. data/tracks/swift/exercises/strain/StrainTest.swift +1 -1
  79. data/tracks/swift/exercises/tournament/TournamentExample.swift +2 -2
  80. data/tracks/swift/exercises/triangle/TriangleExample.swift +7 -3
  81. data/tracks/swift/exercises/wordy/WordyExample.swift +1 -2
  82. metadata +34 -3
  83. data/tracks/purescript/exercises/.keep +0 -0
@@ -65,6 +65,8 @@
65
65
  E94ACA151D41763800D56CC2 /* AllYourBaseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E94ACA141D41763800D56CC2 /* AllYourBaseTest.m */; };
66
66
  E951B6B71D4294E6009EB5B6 /* AllergiesExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E951B6B61D4294E6009EB5B6 /* AllergiesExample.m */; };
67
67
  E951B6B91D429550009EB5B6 /* AllergiesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E951B6B81D429550009EB5B6 /* AllergiesTest.m */; };
68
+ E96993981DF60E1E009EA223 /* TransposeExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E96993971DF60E1E009EA223 /* TransposeExample.m */; };
69
+ E969939A1DF60E5F009EA223 /* TransposeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E96993991DF60E5F009EA223 /* TransposeTest.m */; };
68
70
  E99D1D811D5533BF0006A303 /* SumOfMultiplesExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E99D1D801D5533BF0006A303 /* SumOfMultiplesExample.m */; };
69
71
  E99D1D831D5533D80006A303 /* SumOfMultiplesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E99D1D821D5533D80006A303 /* SumOfMultiplesTest.m */; };
70
72
  E9A7B2F71DA5AC37009056B6 /* LargestSeriesProductExample.m in Sources */ = {isa = PBXBuildFile; fileRef = E9A7B2F61DA5AC37009056B6 /* LargestSeriesProductExample.m */; };
@@ -150,6 +152,9 @@
150
152
  E951B6B51D4294E6009EB5B6 /* AllergiesExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AllergiesExample.h; path = ../../exercises/allergies/AllergiesExample.h; sourceTree = "<group>"; };
151
153
  E951B6B61D4294E6009EB5B6 /* AllergiesExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AllergiesExample.m; path = ../../exercises/allergies/AllergiesExample.m; sourceTree = "<group>"; };
152
154
  E951B6B81D429550009EB5B6 /* AllergiesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AllergiesTest.m; path = ../../exercises/allergies/AllergiesTest.m; sourceTree = "<group>"; };
155
+ E96993961DF60E1E009EA223 /* TransposeExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TransposeExample.h; path = ../../exercises/transpose/TransposeExample.h; sourceTree = "<group>"; };
156
+ E96993971DF60E1E009EA223 /* TransposeExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TransposeExample.m; path = ../../exercises/transpose/TransposeExample.m; sourceTree = "<group>"; };
157
+ E96993991DF60E5F009EA223 /* TransposeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TransposeTest.m; path = ../../exercises/transpose/TransposeTest.m; sourceTree = "<group>"; };
153
158
  E99D1D7F1D5533BF0006A303 /* SumOfMultiplesExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SumOfMultiplesExample.h; path = "../../exercises/sum-of-multiples/SumOfMultiplesExample.h"; sourceTree = "<group>"; };
154
159
  E99D1D801D5533BF0006A303 /* SumOfMultiplesExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SumOfMultiplesExample.m; path = "../../exercises/sum-of-multiples/SumOfMultiplesExample.m"; sourceTree = "<group>"; };
155
160
  E99D1D821D5533D80006A303 /* SumOfMultiplesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SumOfMultiplesTest.m; path = "../../exercises/sum-of-multiples/SumOfMultiplesTest.m"; sourceTree = "<group>"; };
@@ -214,6 +219,7 @@
214
219
  E9C1C0201D9D98B80015E86E /* SecretHandshake */,
215
220
  E9E8B6F61D519E340012F12C /* SpaceAge */,
216
221
  E99D1D7B1D5532C50006A303 /* SumOfMultiples */,
222
+ E96993951DF60DF1009EA223 /* Transpose */,
217
223
  E947A4DB1D81FDDA00633720 /* Triangle */,
218
224
  E9E8B6F71D519E3A0012F12C /* WordCount */,
219
225
  1E50BD001CB465C500FC128D /* Info.plist */,
@@ -307,6 +313,16 @@
307
313
  name = Triangle;
308
314
  sourceTree = "<group>";
309
315
  };
316
+ E96993951DF60DF1009EA223 /* Transpose */ = {
317
+ isa = PBXGroup;
318
+ children = (
319
+ E96993961DF60E1E009EA223 /* TransposeExample.h */,
320
+ E96993971DF60E1E009EA223 /* TransposeExample.m */,
321
+ E96993991DF60E5F009EA223 /* TransposeTest.m */,
322
+ );
323
+ name = Transpose;
324
+ sourceTree = "<group>";
325
+ };
310
326
  E99D1D7B1D5532C50006A303 /* SumOfMultiples */ = {
311
327
  isa = PBXGroup;
312
328
  children = (
@@ -617,6 +633,7 @@
617
633
  1EFACAA31CCCAF3D006F2E69 /* AnagramExample.m in Sources */,
618
634
  E94ACA131D41760300D56CC2 /* AllYourBaseExample.m in Sources */,
619
635
  E94ACA151D41763800D56CC2 /* AllYourBaseTest.m in Sources */,
636
+ E96993981DF60E1E009EA223 /* TransposeExample.m in Sources */,
620
637
  E9C1C0291D9DB16B0015E86E /* AcronymExample.m in Sources */,
621
638
  1EFACAA41CCCAF3D006F2E69 /* AnagramTest.m in Sources */,
622
639
  E907FE921D87547D00B93DA9 /* ScrabbleScoreExample.m in Sources */,
@@ -669,6 +686,7 @@
669
686
  E9A7B2F91DA5AC55009056B6 /* LargestSeriesProductTest.m in Sources */,
670
687
  1EFACAAF1CCCAF3D006F2E69 /* LeapExample.m in Sources */,
671
688
  E9C1C0251D9D99620015E86E /* SecretHandshakeTest.m in Sources */,
689
+ E969939A1DF60E5F009EA223 /* TransposeTest.m in Sources */,
672
690
  E99D1D831D5533D80006A303 /* SumOfMultiplesTest.m in Sources */,
673
691
  1EFACAAA1CCCAF3D006F2E69 /* GradeSchoolTest.m in Sources */,
674
692
  );
@@ -3,6 +3,7 @@
3
3
  .DS_Store
4
4
  tmp
5
5
  *.native
6
+ *.byte
6
7
  _build/
7
8
  bin/configlet
8
9
  bin/configlet.exe
@@ -1,6 +1,9 @@
1
1
  test: test_gen.native
2
2
  @./all_tests.native
3
3
 
4
+ test_gen.byte: all_tests.native src/*.ml interfaces/*.mli test/*.ml
5
+ @ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is src,interfaces test_gen.byte
6
+
4
7
  test_gen.native: all_tests.native src/*.ml interfaces/*.mli test/*.ml
5
8
  @ocamlbuild -use-ocamlfind -tag thread -tag short_paths -cflags -strict-sequence -r -pkg core -pkg yojson -pkg ppx_deriving -pkg ppx_deriving.eq -pkg ppx_deriving.show -Is src,interfaces test_gen.native
6
9
 
@@ -23,26 +23,21 @@ let combine_files (template_files: (string * content) list) (canonical_data_file
23
23
 
24
24
  let generate_code ~(slug: string) ~(template_file: content) ~(canonical_data_file: content): (content, content) Result.t =
25
25
  let template = find_template template_file in
26
+ let edit_expected = edit_expected ~stringify:parameter_to_string ~slug in
27
+ let edit_parameters = edit_parameters ~slug in
28
+ let fill_in_template = fill_in_template edit_expected edit_parameters in
26
29
  let open Result.Monad_infix in
27
30
  Result.of_option template ("cannot recognize file for " ^ slug ^ " as a template") >>= fun template ->
28
- parse_json_text canonical_data_file |> Result.map_error ~f:show_error >>= (function
31
+ parse_json_text canonical_data_file
32
+ |> Result.map_error ~f:show_error >>= (function
29
33
  | Single cases ->
30
- Result.return (fill_in_template
31
- (edit_expected ~stringify:parameter_to_string ~slug)
32
- (edit_parameters ~slug)
33
- template.template
34
- slug
35
- cases |> fill_tests template);
34
+ fill_in_template template.template slug cases
35
+ |> fill_tests template
36
+ |> Result.return
36
37
  | Suite tests ->
37
- let x = List.map tests ~f:(fun {name;cases} ->
38
- (name, fill_in_template
39
- (edit_expected ~stringify:parameter_to_string ~slug)
40
- (edit_parameters ~slug)
41
- template.template
42
- name
43
- cases)
44
- ) in
45
- Result.return (fill_suite template x)
38
+ List.map tests ~f:(fun {name;cases} -> (name, fill_in_template template.template name cases))
39
+ |> fill_suite template
40
+ |> Result.return
46
41
  )
47
42
 
48
43
  let output_tests (files: (string * content * content) list) (output_folder: string): unit =
@@ -3,11 +3,13 @@ open Core.Std
3
3
  open Utils
4
4
 
5
5
  type parameter =
6
+ | Null
6
7
  | String of string
7
8
  | Float of float
8
9
  | Int of int
9
10
  | Bool of bool
10
11
  | StringList of (string list)
12
+ | IntList of (int list)
11
13
  | IntStringMap of ((string * int) list) [@@deriving eq, show]
12
14
 
13
15
  type 'a elements = (string * 'a) list [@@deriving eq, show]
@@ -28,10 +30,12 @@ let surround (ch: char) (s: string): string =
28
30
  Char.to_string ch ^ s ^ Char.to_string ch
29
31
 
30
32
  let parameter_to_string = function
33
+ | Null -> "null"
31
34
  | String s -> String.escaped s
32
35
  | Float f -> Float.to_string f
33
36
  | Int n -> Int.to_string n
34
37
  | Bool b -> Bool.to_string b
35
38
  | StringList xs -> "[" ^ String.concat ~sep:"; " (List.map ~f:(surround '\"' >> String.escaped) xs) ^ "]"
39
+ | IntList xs -> "[" ^ String.concat ~sep:"; " (List.map ~f:Int.to_string xs) ^ "]"
36
40
  | IntStringMap xs -> "[" ^ String.concat ~sep:"; "
37
41
  (List.map xs ~f:(fun (k,v) -> "(\"" ^ String.escaped k ^ "\", " ^ Int.to_string v ^ ")")) ^ "]"
@@ -12,12 +12,19 @@ let to_int_unsafe = function
12
12
  | `Int x -> x
13
13
  | _ -> failwith "need an int here"
14
14
 
15
+ let to_list_safe xs = match xs with
16
+ | [] -> Some (StringList [])
17
+ | `String x :: _ -> Some (StringList (List.map xs ~f:to_string))
18
+ | `Int x :: _ -> Some (IntList (List.map xs ~f:to_int_unsafe))
19
+ | _ -> None
20
+
15
21
  let to_parameter (s: json) = match s with
22
+ | `Null -> Some (Null)
16
23
  | `String x -> Some (String x)
17
24
  | `Float x -> Some (Float x)
18
25
  | `Int x -> Some (Int x)
19
26
  | `Bool x -> Some (Bool x)
20
- | `List x -> Some (StringList (List.map x ~f:to_string))
27
+ | `List x -> to_list_safe x
21
28
  | `Assoc x -> Some (IntStringMap (List.map x ~f:(fun (k,v) -> (k,to_int_unsafe v))))
22
29
  | _ -> None
23
30
 
@@ -7,6 +7,10 @@ let optional_int ~(none: int) = function
7
7
  | Int n -> "(Some " ^ Int.to_string n ^ ")"
8
8
  | x -> parameter_to_string x
9
9
 
10
+ let optional_int_list = function
11
+ | IntList xs -> "(Some " ^ String.concat ~sep:"; " (List.map ~f:Int.to_string xs) ^ ")"
12
+ | _ -> "None"
13
+
10
14
  let optional_int_or_string ~(none: int) = function
11
15
  | String s -> "(Some \"" ^ s ^ "\")"
12
16
  | Int n when n = none -> "None"
@@ -27,6 +31,7 @@ let optional_strings ~(f: string -> bool) (parameters: (string * string) list):
27
31
 
28
32
  let edit_expected ~(stringify: parameter -> string) ~(slug: string) ~(value: parameter) = match slug with
29
33
  | "hamming" -> optional_int ~none:(-1) value
34
+ | "all-your-base" -> optional_int_list value
30
35
  | "say" -> optional_int_or_string ~none:(-1) value
31
36
  | _ -> stringify value
32
37
 
@@ -0,0 +1,16 @@
1
+ open Core.Std
2
+ open OUnit2
3
+ open All_your_bases
4
+
5
+ let ae exp got _test_ctxt =
6
+ assert_equal exp got ~printer:Bool.to_string
7
+
8
+ let tests = [
9
+ (* TEST
10
+ "$description" >::
11
+ ae $expected (convert_bases $input_base $input_digits $output_base);
12
+ END TEST *)
13
+ ]
14
+
15
+ let () =
16
+ run_test_tt_main ("all-your-bases tests" >::: tests)
@@ -20,6 +20,8 @@ let model_tests = [
20
20
  ae "[\"a\"; \"bc\"; \"def\"]" @@ parameter_to_string (StringList ["a"; "bc"; "def"]);
21
21
  "string list parameter with escaped characters to string" >::
22
22
  ae "[\"a\\r\"; \"b\\nc\"; \"d\\tef\"]" @@ parameter_to_string (StringList ["a\r"; "b\nc"; "d\tef"]);
23
+ "int list parameter to string" >::
24
+ ae "[1; 2; 3; 4]" @@ parameter_to_string (IntList [1; 2; 3; 4]);
23
25
  "int string map parameter to string" >::
24
26
  ae "[(\"one\", 1); (\"two\", 1)]" @@ parameter_to_string (IntStringMap [("one", 1); ("two", 1)]);
25
27
  "int string map parameter to string with escaped characters in the keys" >::
@@ -40,6 +40,14 @@ let parser_tests = [
40
40
  ae (single [{description = "d1"; parameters = []; expected = Bool true}])
41
41
  (parse_json_text "{\"cases\" : [{\"description\" : \"d1\", \"expected\" : true}]}");
42
42
 
43
+ "parses a single element with a description and expected int list output" >::
44
+ ae (single [{description = "d1"; parameters = []; expected = IntList [1;2;3]}])
45
+ (parse_json_text "{\"cases\" : [{\"description\" : \"d1\", \"expected\" : [1, 2, 3]}]}");
46
+
47
+ "parses a single element with a description and expected null output" >::
48
+ ae (single [{description = "d1"; parameters = []; expected = Null}])
49
+ (parse_json_text "{\"cases\" : [{\"description\" : \"d1\", \"expected\" : null}]}");
50
+
43
51
  "parses a single element with an int key value pair" >::
44
52
  ae (single [{description = "d1"; parameters = [("input", Int 1996)]; expected = Bool true}])
45
53
  (parse_json_text "{\"cases\" : [{\"description\" : \"d1\", \"input\" : 1996, \"expected\" : true}]}");
@@ -0,0 +1,57 @@
1
+ ## Code Style and Linting
2
+
3
+ If you are looking for good general advices regarding Perl coding,
4
+ Damian Conway's [Perl Best Practices][PBP] is a good reference.
5
+
6
+ To prettify your code, you can use the module
7
+ [Perl-Tidy][PerlTidy].
8
+
9
+ To install with [cpanminus][]:
10
+
11
+ cpanm Perl-Tidy
12
+
13
+ or via the regular `cpan` install utility:
14
+
15
+ cpan Perl-Tidy
16
+
17
+ And then, you can use the provided `perltidy` utility program
18
+ to reformat your code.
19
+
20
+ # modify file in-place and save old version as some_script.pl.bak
21
+ $ perltidy -b some_script.pl
22
+
23
+ `perltidy` has a *lot* of configuration options to cater to every taste. They
24
+ are documented [here][perltidyDocs].
25
+
26
+ There is also [tidyview], a visual interface that allows you to
27
+ tweak the different options and immediately see the result.
28
+
29
+ If you want to enforce coding practices, there is also
30
+ [Perl::Critic][perlcritic]. It comes with the rules described in
31
+ the book *Perl Best Practices* mentioned previously, but plenty of
32
+ plugins exist, and it can be customized to fit any in-house coding
33
+ rules.
34
+
35
+ To install:
36
+
37
+ # via cpanminus
38
+ cpanm Perl-Critic
39
+
40
+ # via the classic 'cpan' installation tool
41
+ cpan Perl-Critic
42
+
43
+ To use:
44
+
45
+ $ perlcritic some_script.pl
46
+
47
+ The tool has many, many configuration tweaks, see its
48
+ [documentation][perlcriticdocs] for the full scoop on them.
49
+
50
+
51
+ [PBP]: http://shop.oreilly.com/product/9780596001735.do
52
+ [PerlTidy]: https://metacpan.org/release/Perl-Tidy
53
+ [cpanminus]: http://search.cpan.org/~miyagawa/App-cpanminus-1.7042
54
+ [perltidyDocs]: https://metacpan.org/pod/distribution/Perl-Tidy/docs/stylekey.pod
55
+ [tidyview]: https://sourceforge.net/projects/tidyview/
56
+ [perlcritic]: https://metacpan.org/release/Perl-Critic
57
+ [perlcriticdocs]: https://metacpan.org/pod/distribution/Perl-Critic/bin/perlcritic
@@ -3,10 +3,17 @@ package Example;
3
3
  use strict;
4
4
  use warnings;
5
5
 
6
+ use Carp;
7
+
6
8
  sub compute {
7
9
  my ($strand_a, $strand_b) = @_;
10
+
11
+ croak "DNA strands must be of equal length"
12
+ unless length $strand_a == length $strand_b;
13
+
8
14
  my $distance = $strand_a ^ $strand_b;
9
15
  $distance =~ s/\0//g;
16
+
10
17
  return (length $distance) - abs(length($strand_a) - length($strand_b));
11
18
  }
12
19
 
@@ -10,19 +10,32 @@ use lib $dir;
10
10
 
11
11
  my $module = $ENV{EXERCISM} ? 'Example' : 'Hamming';
12
12
 
13
- plan tests => 11;
13
+ plan tests => 12;
14
14
 
15
15
  ok -e "${dir}${module}.pm", "Missing $module.pm" or BAIL_OUT "You need to create file: $module.pm";
16
16
  eval "use $module";
17
17
  ok !$@, "Cannot load $module" or BAIL_OUT "Cannot load $module. Does it compile? Does it end with 1;?";
18
18
  can_ok $module, 'compute' or BAIL_OUT "Missing package $module; or missing sub compute()?";
19
19
 
20
+ sub dies_like(&$$) {
21
+ my( $code, $expected, $message ) = @_;
22
+ eval { $code->() };
23
+ like $@ => $expected, $message;
24
+ }
25
+
20
26
  my $sub = \&{"$module" . "::compute"};
21
27
  is $sub->('A', 'A'), 0, "identical strands";
28
+ is $sub->('A', 'G'), 1, "different strands";
22
29
  is $sub->('AG', 'CT'), 2, "completely different strands";
23
30
  is $sub->('AT', 'CT'), 1, "one hamming distance";
24
31
  is $sub->('GGACG', 'GGTCG'), 1, "one hamming distance, longer strands";
25
- is $sub->('AAAG', 'AAA'), 0, "ignore extra length on 1st strand";
26
- is $sub->('AAA', 'AAAG'), 0, "ignore extra length on 2nd strand";
27
32
  is $sub->('GATACA', 'GCATAA'), 4, "4 hamming distance";
28
- is $sub->('GGACGGATTCTG', 'AGGACGGATTCT'), 9, "9 hamming distance"
33
+ is $sub->('GGACGGATTCTG', 'AGGACGGATTCT'), 9, "9 hamming distance";
34
+
35
+ dies_like { $sub->('AAAG', 'AAA') }
36
+ qr/DNA strands must be of equal length/,
37
+ "extra length on 1st strand";
38
+
39
+ dies_like { $sub->('AAA', 'AAAG') }
40
+ qr/DNA strands must be of equal length/,
41
+ "extra length on 2nd strand";
@@ -11,10 +11,10 @@ use lib $dir;
11
11
  my $module = $ENV{EXERCISM} ? 'Example' : 'DNA';
12
12
 
13
13
  my @cases = (
14
- ['C', 'G', 'cytidine unchanged'],
15
- ['G', 'C', 'guanosine unchanged'],
16
- ['T', 'A', 'adenosine unchanged'],
17
- ['A', 'U', 'thymidine to uracil'],
14
+ ['C', 'G', 'cytosine unchanged'],
15
+ ['G', 'C', 'guanine unchanged'],
16
+ ['T', 'A', 'adenine unchanged'],
17
+ ['A', 'U', 'thymine to uracil'],
18
18
  ['ACGTGGTCTTAA', 'UGCACCAGAAUU', 'transcribes all occurences'],
19
19
  );
20
20
 
@@ -1,2 +1,4 @@
1
1
  bin/configlet
2
2
  bin/configlet.exe
3
+ # dir created when a Perl 6 module is used
4
+ .precomp
@@ -61,6 +61,11 @@
61
61
  "slug": "accumulate",
62
62
  "topics": []
63
63
  },
64
+ {
65
+ "difficulty": 1,
66
+ "slug": "phone-number",
67
+ "topics": []
68
+ },
64
69
  {
65
70
  "difficulty": 1,
66
71
  "slug": "rna-transcription",
@@ -0,0 +1,30 @@
1
+ use v6;
2
+
3
+ class X::Phone::Invalid is Exception {
4
+ has $.payload;
5
+ method message {"'$!payload' is not valid."}
6
+ }
7
+
8
+ class Phone {
9
+ has $.number;
10
+
11
+ method new (:$number!) {
12
+ my $validated = $number;
13
+ $validated ~~ s:g/<:!Decimal_Number>//;
14
+ $validated ~~ /^ 1? (\d ** 10) $/ ?? ($validated = ~$0) !! X::Phone::Invalid.new(:payload«$number»).throw;
15
+ self.bless(:number«$validated»);
16
+ }
17
+
18
+ method area-code {
19
+ $!number ~~ /\d**3/ and return ~$/;
20
+ }
21
+
22
+ method pretty {
23
+ $!number ~~ /
24
+ $<area-code> = \d**3
25
+ $<central-office-code> = \d**3
26
+ $<station-number> = \d**4
27
+ / and return "($<area-code>) $<central-office-code>-$<station-number>";
28
+ }
29
+ }
30
+
@@ -0,0 +1,47 @@
1
+ {
2
+ "valid": [
3
+ {
4
+ "input": 1234567890,
5
+ "number": "1234567890",
6
+ "area-code": "123",
7
+ "pretty": "(123) 456-7890",
8
+ "test": "10 digit integer"
9
+ },
10
+ {
11
+ "input": "+1 (234) 555-6789",
12
+ "number": "2345556789",
13
+ "area-code": "234",
14
+ "pretty": "(234) 555-6789",
15
+ "test": "11 digit formatted number"
16
+ },
17
+ {
18
+ "input": "1.379.555.2468",
19
+ "number": "3795552468",
20
+ "area-code": "379",
21
+ "pretty": "(379) 555-2468",
22
+ "test": "11 digit number containing separators"
23
+ }
24
+ ],
25
+ "invalid": [
26
+ {
27
+ "input": "",
28
+ "test": "empty input"
29
+ },
30
+ {
31
+ "input": "13579",
32
+ "test": "5 digit number"
33
+ },
34
+ {
35
+ "input": "123456789011",
36
+ "test": "12 digit number"
37
+ },
38
+ {
39
+ "input": "+2 (468) 555-1379",
40
+ "test": "11 digit number not beginning with 1"
41
+ },
42
+ {
43
+ "input": "phone number",
44
+ "test": "not a number"
45
+ }
46
+ ]
47
+ }