trackler 2.0.0.1 → 2.0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bump-content +3 -1
  3. data/bin/verify-metadata +2 -2
  4. data/common/exercises/alphametics/canonical-data.json +19 -9
  5. data/common/exercises/food-chain/canonical-data.json +7 -1
  6. data/common/exercises/grains/canonical-data.json +66 -0
  7. data/common/exercises/raindrops/description.md +4 -5
  8. data/common/exercises/triangle/canonical-data.json +81 -54
  9. data/lib/trackler/version.rb +1 -1
  10. data/tracks/c/config.json +26 -19
  11. data/tracks/c/exercises/allergies/makefile +15 -0
  12. data/tracks/c/exercises/allergies/src/allergies.h +21 -0
  13. data/tracks/c/exercises/allergies/src/example.c +32 -0
  14. data/tracks/c/exercises/allergies/src/example.h +26 -0
  15. data/tracks/c/exercises/allergies/test/test_allergies.c +203 -0
  16. data/tracks/c/exercises/allergies/test/vendor/unity.c +1300 -0
  17. data/tracks/c/exercises/allergies/test/vendor/unity.h +274 -0
  18. data/tracks/c/exercises/allergies/test/vendor/unity_internals.h +701 -0
  19. data/tracks/c/exercises/atbash-cipher/makefile +16 -0
  20. data/tracks/c/exercises/atbash-cipher/src/example.c +71 -0
  21. data/tracks/c/exercises/atbash-cipher/src/example.h +7 -0
  22. data/tracks/c/exercises/atbash-cipher/test/test_atbash_cipher.c +113 -0
  23. data/tracks/c/exercises/atbash-cipher/test/vendor/unity.c +1300 -0
  24. data/tracks/c/exercises/atbash-cipher/test/vendor/unity.h +274 -0
  25. data/tracks/c/exercises/atbash-cipher/test/vendor/unity_internals.h +701 -0
  26. data/tracks/c/exercises/phone-number/makefile +16 -0
  27. data/tracks/c/exercises/phone-number/src/example.c +66 -0
  28. data/tracks/c/exercises/phone-number/src/example.h +8 -0
  29. data/tracks/c/exercises/phone-number/test/test_phone_number.c +108 -0
  30. data/tracks/c/exercises/phone-number/test/vendor/unity.c +1300 -0
  31. data/tracks/c/exercises/phone-number/test/vendor/unity.h +274 -0
  32. data/tracks/c/exercises/phone-number/test/vendor/unity_internals.h +701 -0
  33. data/tracks/csharp/config.json +8 -0
  34. data/tracks/csharp/exercises/bowling/BowlingTest.cs +188 -33
  35. data/tracks/csharp/exercises/bowling/Example.cs +38 -9
  36. data/tracks/csharp/exercises/rectangles/Example.cs +91 -0
  37. data/tracks/csharp/exercises/rectangles/RectanglesTest.cs +133 -0
  38. data/tracks/elisp/docs/INSTALLATION.org +1 -1
  39. data/tracks/elixir/config.json +8 -66
  40. data/tracks/elixir/docs/LEARNING.md +1 -1
  41. data/tracks/elixir/exercises/diamond/diamond_test.exs +12 -12
  42. data/tracks/elixir/exercises/grep/example.exs +92 -0
  43. data/tracks/elixir/exercises/grep/grep.exs +6 -0
  44. data/tracks/elixir/exercises/grep/grep_test.exs +259 -0
  45. data/tracks/elixir/exercises/markdown/markdown.exs +59 -2
  46. data/tracks/elixir/exercises/nucleotide-count/nucleotide_count_test.exs +4 -4
  47. data/tracks/elixir/exercises/phone-number/phone_number_test.exs +5 -0
  48. data/tracks/fsharp/exercises/bowling/BowlingTest.fs +158 -43
  49. data/tracks/fsharp/exercises/bowling/Example.fs +53 -24
  50. data/tracks/go/config.json +5 -0
  51. data/tracks/go/exercises/diamond/diamond_test.go +227 -0
  52. data/tracks/go/exercises/diamond/example.go +47 -0
  53. data/tracks/go/exercises/food-chain/example.go +1 -1
  54. data/tracks/go/exercises/food-chain/food_chain_test.go +30 -6
  55. data/tracks/go/exercises/nucleotide-count/example.go +21 -8
  56. data/tracks/go/exercises/nucleotide-count/nucleotide_count_test.go +45 -37
  57. data/tracks/haskell/exercises/anagram/test/Tests.hs +1 -11
  58. data/tracks/java/bin/journey-test.sh +165 -128
  59. data/tracks/java/docs/ABOUT.md +5 -8
  60. data/tracks/java/exercises/hello-world/build.gradle +0 -6
  61. data/tracks/java/exercises/hello-world/src/test/java/HelloWorldTest.java +0 -1
  62. data/tracks/java/exercises/meetup/build.gradle +0 -1
  63. data/tracks/java/exercises/meetup/src/example/java/Meetup.java +9 -7
  64. data/tracks/java/exercises/meetup/src/test/java/MeetupTest.java +185 -188
  65. data/tracks/lua/config.json +0 -73
  66. data/tracks/lua/exercises/bowling/bowling_spec.lua +92 -48
  67. data/tracks/lua/exercises/bowling/example.lua +4 -1
  68. data/tracks/objective-c/config.json +9 -30
  69. data/tracks/objective-c/exercises/pangram/PangramExample.h +7 -0
  70. data/tracks/objective-c/exercises/pangram/PangramExample.m +21 -0
  71. data/tracks/objective-c/exercises/pangram/PangramTest.m +51 -0
  72. data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
  73. data/tracks/ocaml/README.md +46 -1
  74. data/tracks/ocaml/SETUP.md +21 -2
  75. data/tracks/ocaml/config.json +48 -78
  76. data/tracks/perl5/README.md +15 -8
  77. data/tracks/perl5/testall.pl +5 -5
  78. data/tracks/php/config.json +26 -34
  79. data/tracks/php/docs/ABOUT.md +15 -0
  80. data/tracks/php/exercises/allergies/allergies_test.php +121 -0
  81. data/tracks/php/exercises/allergies/example.php +64 -0
  82. data/tracks/php/exercises/etl/etl_test.php +52 -0
  83. data/tracks/php/exercises/etl/example.php +12 -0
  84. data/tracks/php/exercises/nucleotide-count/example.php +25 -0
  85. data/tracks/php/exercises/nucleotide-count/nucleotide-count_test.php +36 -0
  86. data/tracks/php/exercises/pig-latin/example.php +25 -29
  87. data/tracks/php/exercises/pig-latin/pig-latin_test.php +26 -19
  88. data/tracks/php/exercises/space-age/example.php +65 -0
  89. data/tracks/php/exercises/space-age/space-age_test.php +70 -0
  90. data/tracks/php/exercises/triangle/example.php +43 -0
  91. data/tracks/php/exercises/triangle/triangle_test.php +140 -0
  92. data/tracks/pony/exercises/anagram/example.pony +6 -6
  93. data/tracks/pony/exercises/anagram/test.pony +3 -4
  94. data/tracks/pony/exercises/bob/test.pony +23 -23
  95. data/tracks/pony/exercises/difference-of-squares/test.pony +11 -11
  96. data/tracks/pony/exercises/hamming/example.pony +3 -3
  97. data/tracks/pony/exercises/hamming/test.pony +16 -16
  98. data/tracks/pony/exercises/hello-world/test.pony +5 -4
  99. data/tracks/pony/exercises/leap/test.pony +8 -8
  100. data/tracks/python/config.json +18 -0
  101. data/tracks/python/exercises/diamond/diamond_test.py +33 -0
  102. data/tracks/python/exercises/diamond/example.py +15 -0
  103. data/tracks/python/exercises/linked-list/example.py +47 -0
  104. data/tracks/python/exercises/linked-list/linked_list.py +13 -0
  105. data/tracks/python/exercises/linked-list/linked_list_test.py +49 -0
  106. data/tracks/python/exercises/list-ops/example.py +55 -0
  107. data/tracks/python/exercises/list-ops/list_ops.py +38 -0
  108. data/tracks/python/exercises/list-ops/list_ops_test.py +136 -0
  109. data/tracks/ruby/bin/generate +22 -2
  110. data/tracks/ruby/config.json +12 -83
  111. data/tracks/ruby/exercises/allergies/allergies_test.rb +0 -1
  112. data/tracks/ruby/exercises/atbash-cipher/atbash_cipher_test.rb +0 -1
  113. data/tracks/ruby/exercises/beer-song/beer_song_test.rb +1 -2
  114. data/tracks/ruby/exercises/binary/example.rb +0 -1
  115. data/tracks/ruby/exercises/binary-search-tree/binary_search_tree_test.rb +1 -1
  116. data/tracks/ruby/exercises/bowling/.version +1 -0
  117. data/tracks/ruby/exercises/bowling/bowling_test.rb +109 -133
  118. data/tracks/ruby/exercises/bowling/example.rb +7 -7
  119. data/tracks/ruby/exercises/bowling/example.tt +27 -0
  120. data/tracks/ruby/exercises/circular-buffer/circular_buffer_test.rb +0 -2
  121. data/tracks/ruby/exercises/clock/example.rb +0 -2
  122. data/tracks/ruby/exercises/connect/connect_test.rb +0 -1
  123. data/tracks/ruby/exercises/custom-set/custom_set_test.rb +0 -1
  124. data/tracks/ruby/exercises/diamond/diamond_test.rb +0 -1
  125. data/tracks/ruby/exercises/etl/etl_test.rb +1 -1
  126. data/tracks/ruby/exercises/house/house_test.rb +0 -1
  127. data/tracks/ruby/exercises/isogram/isogram_test.rb +2 -2
  128. data/tracks/ruby/exercises/largest-series-product/example.tt +0 -3
  129. data/tracks/ruby/exercises/largest-series-product/largest_series_product_test.rb +0 -4
  130. data/tracks/ruby/exercises/linked-list/linked_list_test.rb +1 -1
  131. data/tracks/ruby/exercises/meetup/meetup_test.rb +0 -1
  132. data/tracks/ruby/exercises/nth-prime/example.tt +0 -2
  133. data/tracks/ruby/exercises/nth-prime/nth_prime_test.rb +0 -2
  134. data/tracks/ruby/exercises/ocr-numbers/ocr_numbers_test.rb +1 -2
  135. data/tracks/ruby/exercises/protein-translation/protein_translation_test.rb +0 -1
  136. data/tracks/ruby/exercises/proverb/proverb_test.rb +1 -3
  137. data/tracks/ruby/exercises/queen-attack/example.rb +3 -1
  138. data/tracks/ruby/exercises/queen-attack/queen_attack_test.rb +34 -8
  139. data/tracks/ruby/exercises/robot-simulator/robot_simulator_test.rb +1 -1
  140. data/tracks/ruby/exercises/strain/strain_test.rb +2 -2
  141. data/tracks/ruby/exercises/tournament/.version +1 -0
  142. data/tracks/ruby/exercises/tournament/example.rb +54 -0
  143. data/tracks/ruby/exercises/tournament/example.tt +23 -0
  144. data/tracks/ruby/exercises/tournament/tournament_test.rb +92 -0
  145. data/tracks/ruby/exercises/transpose/.version +1 -0
  146. data/tracks/ruby/exercises/transpose/example.rb +14 -0
  147. data/tracks/ruby/exercises/transpose/example.tt +22 -0
  148. data/tracks/ruby/exercises/transpose/transpose_test.rb +303 -0
  149. data/tracks/ruby/lib/bowling_cases.rb +46 -0
  150. data/tracks/ruby/lib/isogram_cases.rb +1 -1
  151. data/tracks/ruby/lib/tournament_cases.rb +45 -0
  152. data/tracks/ruby/lib/transpose_cases.rb +45 -0
  153. data/tracks/rust/config.json +2 -0
  154. data/tracks/rust/exercises/bowling/.gitignore +7 -0
  155. data/tracks/rust/exercises/bowling/Cargo.toml +3 -0
  156. data/tracks/rust/exercises/bowling/example.rs +134 -0
  157. data/tracks/rust/exercises/bowling/tests/bowling.rs +373 -0
  158. data/tracks/rust/exercises/grains/.gitignore +7 -0
  159. data/tracks/rust/exercises/grains/Cargo.toml +3 -0
  160. data/tracks/rust/exercises/grains/example.rs +11 -0
  161. data/tracks/rust/exercises/grains/src/lib.rs +7 -0
  162. data/tracks/rust/exercises/grains/tests/grains.rs +63 -0
  163. data/tracks/rust/problems.md +2 -0
  164. data/tracks/scala/README.md +38 -0
  165. data/tracks/scala/config.json +20 -74
  166. data/tracks/scala/exercises/accumulate/src/test/scala/accumulate_test.scala +4 -0
  167. data/tracks/scala/exercises/allergies/src/test/scala/allergies_test.scala +11 -0
  168. data/tracks/scala/exercises/alphametics/build.sbt +6 -0
  169. data/tracks/scala/exercises/alphametics/example.scala +125 -0
  170. data/tracks/scala/exercises/alphametics/src/main/scala/.keep +0 -0
  171. data/tracks/scala/exercises/alphametics/src/test/scala/AlphameticsTest.scala +62 -0
  172. data/tracks/scala/exercises/atbash-cipher/src/test/scala/atbash_test.scala +8 -0
  173. data/tracks/scala/exercises/bank-account/src/test/scala/BankAccountTest.scala +4 -0
  174. data/tracks/scala/exercises/binary/src/test/scala/binary_test.scala +13 -0
  175. data/tracks/scala/exercises/binary-search-tree/src/test/scala/BstTest.scala +11 -0
  176. data/tracks/scala/exercises/bowling/Example.scala +116 -0
  177. data/tracks/scala/exercises/bowling/build.sbt +3 -0
  178. data/tracks/scala/exercises/bowling/src/main/scala/Bowling.scala +11 -0
  179. data/tracks/scala/exercises/bowling/src/test/scala/BowlingSuite.scala +237 -0
  180. data/tracks/scala/exercises/clock/src/test/scala/ClockTest.scala +50 -0
  181. data/tracks/scala/exercises/connect/README.md +17 -0
  182. data/tracks/scala/exercises/connect/src/test/scala/ConnectTest.scala +7 -0
  183. data/tracks/scala/exercises/crypto-square/src/test/scala/{CrytpoSquareTest.scala → CryptoSquareTest.scala} +9 -0
  184. data/tracks/scala/exercises/custom-set/src/test/scala/CustomSetTest.scala +36 -0
  185. data/tracks/scala/exercises/difference-of-squares/src/test/scala/squares_test.scala +8 -0
  186. data/tracks/scala/exercises/forth/src/test/scala/ForthTest.scala +22 -0
  187. data/tracks/scala/exercises/hexadecimal/src/test/scala/HexadecimalTest.scala +8 -0
  188. data/tracks/scala/exercises/kindergarten-garden/src/test/scala/GardenTest.scala +5 -0
  189. data/tracks/scala/exercises/largest-series-product/src/test/scala/SeriesTest.scala +2 -0
  190. data/tracks/scala/exercises/linked-list/src/test/scala/DequeTest.scala +4 -0
  191. data/tracks/scala/exercises/luhn/src/test/scala/LuhnTest.scala +4 -0
  192. data/tracks/scala/exercises/matrix/src/test/scala/MatrixTest.scala +2 -0
  193. data/tracks/scala/exercises/minesweeper/src/test/scala/MinesweeperTest.scala +6 -0
  194. data/tracks/scala/exercises/nth-prime/src/test/scala/PrimeTest.scala +5 -0
  195. data/tracks/scala/exercises/ocr-numbers/src/test/scala/OcrTest.scala +15 -0
  196. data/tracks/scala/exercises/octal/src/test/scala/OctalTest.scala +7 -0
  197. data/tracks/scala/exercises/parallel-letter-frequency/src/test/scala/FrequencyTest.scala +8 -0
  198. data/tracks/scala/exercises/pascals-triangle/src/test/scala/PascalsTriangleTest.scala +5 -0
  199. data/tracks/scala/exercises/pig-latin/src/test/scala/PigLatinTest.scala +4 -0
  200. data/tracks/scala/exercises/pythagorean-triplet/src/test/scala/PythagoreanTripletTest.scala +3 -0
  201. data/tracks/scala/exercises/queen-attack/src/test/scala/QueensTest.scala +5 -0
  202. data/tracks/scala/exercises/robot-simulator/src/test/scala/RobotTest.scala +16 -8
  203. data/tracks/scala/exercises/say/src/test/scala/SayTest.scala +34 -17
  204. data/tracks/scala/exercises/scrabble-score/src/test/scala/scrabble_score_test.scala +6 -0
  205. data/tracks/scala/exercises/secret-handshake/src/test/scala/SecretHandshakeTest.scala +18 -9
  206. data/tracks/scala/exercises/series/src/test/scala/SeriesTest.scala +4 -2
  207. data/tracks/scala/exercises/sieve/src/test/scala/SieveTest.scala +8 -4
  208. data/tracks/scala/exercises/simple-cipher/src/test/scala/CipherTest.scala +17 -9
  209. data/tracks/scala/exercises/sublist/src/test/scala/sublist_test.scala +17 -0
  210. data/tracks/scala/exercises/trinary/src/test/scala/TrinaryTest.scala +14 -7
  211. data/tracks/scala/exercises/wordy/src/test/scala/WordProblemTest.scala +28 -14
  212. data/tracks/scala/project/Build.scala +3 -3
  213. data/tracks/scala/testgen/src/main/scala/BowlingTestGenerator.scala +57 -0
  214. data/tracks/sml/config.json +41 -6
  215. data/tracks/sml/exercises/flatten-array/example.sml +6 -0
  216. data/tracks/sml/exercises/flatten-array/test_flatten_array.sml +10 -0
  217. data/tracks/sml/exercises/nth-prime/example.sml +46 -0
  218. data/tracks/sml/exercises/nth-prime/test_nth_prime.sml +14 -0
  219. data/tracks/sml/exercises/raindrops/example.sml +9 -0
  220. data/tracks/sml/exercises/raindrops/raindrops.sml +2 -0
  221. data/tracks/sml/exercises/raindrops/test_raindrops.sml +95 -0
  222. data/tracks/swift/config.json +269 -328
  223. data/tracks/swift/exercises/pangram/PangramExample.swift +17 -0
  224. data/tracks/swift/exercises/pangram/PangramTest.swift +43 -0
  225. data/tracks/swift/xcodeProject/xSwift.xcodeproj/project.pbxproj +16 -0
  226. metadata +95 -3
@@ -18,11 +18,11 @@ defmodule DiamondTest do
18
18
  test "letter C" do
19
19
  shape = Diamond.build_shape(?C)
20
20
  assert shape == """
21
- \s A
22
- \sB B
21
+ \s A \s
22
+ \sB B\s
23
23
  C C
24
- \sB B
25
- \s A
24
+ \sB B\s
25
+ \s A \s
26
26
  """
27
27
  end
28
28
 
@@ -30,15 +30,15 @@ defmodule DiamondTest do
30
30
  test "letter E" do
31
31
  shape = Diamond.build_shape(?E)
32
32
  assert shape == """
33
- \s A
34
- \s B B
35
- \s C C
36
- \sD D
33
+ \s A \s
34
+ \s B B \s
35
+ \s C C \s
36
+ \sD D\s
37
37
  E E
38
- \sD D
39
- \s C C
40
- \s B B
41
- \s A
38
+ \sD D\s
39
+ \s C C \s
40
+ \s B B \s
41
+ \s A \s
42
42
  """
43
43
  end
44
44
  end
@@ -0,0 +1,92 @@
1
+ defmodule Grep do
2
+ use Bitwise
3
+
4
+ @line_num_flag 1
5
+ @file_name 2
6
+ @case_insensitive 4
7
+ @invert 8
8
+ @entire_lines 16
9
+
10
+ defp parse_flag("-n"), do: @line_num_flag
11
+ defp parse_flag("-l"), do: @file_name
12
+ defp parse_flag("-i"), do: @case_insensitive
13
+ defp parse_flag("-v"), do: @invert
14
+ defp parse_flag("-x"), do: @entire_lines
15
+ defp parse_flag(_), do: 0
16
+
17
+ defp parse_flags(flags) do
18
+ flags
19
+ |> Enum.map(&parse_flag/1)
20
+ |> Enum.reduce(0, fn(a,b) -> a ||| b end)
21
+ end
22
+
23
+ defp has_flag(flags, flag), do: (flags &&& flag) > 0
24
+
25
+ defp is_match(pattern, flags) do
26
+ pat = if has_flag(flags, @entire_lines) do
27
+ "^#{pattern}$"
28
+ else
29
+ pattern
30
+ end
31
+ cas = if has_flag(flags, @case_insensitive) do
32
+ "i"
33
+ else
34
+ ""
35
+ end
36
+
37
+ regex = Regex.compile!(pat, cas)
38
+
39
+ fn line -> Regex.match?(regex, line) != has_flag(flags, @invert) end
40
+ end
41
+
42
+ defp matching_lines(pattern, flags, file) do
43
+ match_fn = is_match(pattern, flags)
44
+
45
+ File.stream!(file)
46
+ |> Enum.map(fn l -> String.trim_trailing(l, "\n") end)
47
+ |> Enum.with_index(1)
48
+ |> Enum.map(fn {l, i} -> {file, i, l} end)
49
+ |> Enum.filter(fn {_, _, l} -> match_fn.(l) end)
50
+ end
51
+
52
+ defp process_files(pattern, flags, files) do
53
+ files
54
+ |> Enum.filter(fn x -> !Enum.empty?(matching_lines(pattern, flags, x)) end)
55
+ end
56
+
57
+ defp line_formatter(flags, single_file?) do
58
+ print_nums? = has_flag(flags, @line_num_flag)
59
+
60
+ fn {f, ix, l} ->
61
+ case {single_file?, print_nums?} do
62
+ {true, true} -> "#{ix}:#{l}"
63
+ {false, true} -> "#{f}:#{ix}:#{l}"
64
+ {true, false} -> "#{l}"
65
+ {false, false} -> "#{f}:#{l}"
66
+ end
67
+ end
68
+ end
69
+
70
+ defp process_lines(pattern, flags, files) do
71
+ fmt = line_formatter(flags, length(files) == 1)
72
+
73
+ files
74
+ |> Enum.flat_map(fn x -> matching_lines(pattern, flags, x) end)
75
+ |> Enum.map(fmt)
76
+ end
77
+
78
+ @spec grep(String.t, [String.t], [String.t]) :: String.t
79
+ def grep(pattern, flag_args, files) do
80
+ flags = parse_flags(flag_args)
81
+
82
+ output = if has_flag(flags, @file_name) do
83
+ process_files(pattern, flags, files)
84
+ else
85
+ process_lines(pattern, flags, files)
86
+ end
87
+
88
+ output
89
+ |> Enum.map(fn l -> "#{l}\n" end)
90
+ |> Enum.reduce("", fn b,a -> "#{a}#{b}" end)
91
+ end
92
+ end
@@ -0,0 +1,6 @@
1
+ defmodule Grep do
2
+
3
+ @spec grep(String.t, [String.t], [String.t]) :: String.t
4
+ def grep(pattern, flags, files) do
5
+ end
6
+ end
@@ -0,0 +1,259 @@
1
+ if !System.get_env("EXERCISM_TEST_EXAMPLES") do
2
+ Code.load_file("grep.exs", __DIR__)
3
+ end
4
+
5
+ ExUnit.start
6
+ ExUnit.configure exclude: :pending, trace: true
7
+
8
+ defmodule GrepTest do
9
+ use ExUnit.Case
10
+
11
+ setup context do
12
+
13
+ if context[:files] do
14
+ File.write!("iliad.txt", """
15
+ Achilles sing, O Goddess! Peleus' son;
16
+ His wrath pernicious, who ten thousand woes
17
+ Caused to Achaia's host, sent many a soul
18
+ Illustrious into Ades premature,
19
+ And Heroes gave (so stood the will of Jove)
20
+ To dogs and to all ravening fowls a prey,
21
+ When fierce dispute had separated once
22
+ The noble Chief Achilles from the son
23
+ Of Atreus, Agamemnon, King of men.
24
+ """)
25
+
26
+ File.write!("midsummer-night.txt", """
27
+ I do entreat your grace to pardon me.
28
+ I know not by what power I am made bold,
29
+ Nor how it may concern my modesty,
30
+ In such a presence here to plead my thoughts;
31
+ But I beseech your grace that I may know
32
+ The worst that may befall me in this case,
33
+ If I refuse to wed Demetrius.
34
+ """
35
+ )
36
+
37
+ File.write!("paradise-lost.txt", """
38
+ Of Mans First Disobedience, and the Fruit
39
+ Of that Forbidden Tree, whose mortal tast
40
+ Brought Death into the World, and all our woe,
41
+ With loss of Eden, till one greater Man
42
+ Restore us, and regain the blissful Seat,
43
+ Sing Heav'nly Muse, that on the secret top
44
+ Of Oreb, or of Sinai, didst inspire
45
+ That Shepherd, who first taught the chosen Seed
46
+ """)
47
+
48
+ on_exit fn ->
49
+ File.rm!("iliad.txt")
50
+ File.rm!("midsummer-night.txt")
51
+ File.rm!("paradise-lost.txt")
52
+ end
53
+ end
54
+ end
55
+
56
+ @moduletag :files
57
+
58
+ describe "grepping a single file" do
59
+
60
+ test "one match, no flags" do
61
+ assert Grep.grep("Agamemnon", [], ["iliad.txt"]) ==
62
+ """
63
+ Of Atreus, Agamemnon, King of men.
64
+ """
65
+ end
66
+
67
+ @tag :pending
68
+ test "one match, print line numbers flag" do
69
+ assert Grep.grep("Forbidden", ["-n"], ["paradise-lost.txt"]) ==
70
+ """
71
+ 2:Of that Forbidden Tree, whose mortal tast
72
+ """
73
+ end
74
+
75
+ @tag :pending
76
+ test "one match, case-insensitive flag" do
77
+ assert Grep.grep("FORBIDDEN", ["-i"], ["paradise-lost.txt"]) ==
78
+ """
79
+ Of that Forbidden Tree, whose mortal tast
80
+ """
81
+ end
82
+
83
+ @tag :pending
84
+ test "one match, print file names flag" do
85
+ assert Grep.grep("Forbidden", ["-l"], ["paradise-lost.txt"]) ==
86
+ """
87
+ paradise-lost.txt
88
+ """
89
+ end
90
+
91
+ @tag :pending
92
+ test "one match, match entire lines flag" do
93
+ assert Grep.grep("With loss of Eden, till one greater Man",
94
+ ["-x"], ["paradise-lost.txt"]) ==
95
+ """
96
+ With loss of Eden, till one greater Man
97
+ """
98
+ end
99
+
100
+ @tag :pending
101
+ test "one match, multiple flags" do
102
+ assert Grep.grep("OF ATREUS, Agamemnon, KIng of MEN.",
103
+ ["-n", "-i", "-x"], ["iliad.txt"]) ==
104
+ """
105
+ 9:Of Atreus, Agamemnon, King of men.
106
+ """
107
+ end
108
+
109
+ @tag :pending
110
+ test "several matches, no flags" do
111
+ assert Grep.grep("may", [], ["midsummer-night.txt"]) ==
112
+ """
113
+ Nor how it may concern my modesty,
114
+ But I beseech your grace that I may know
115
+ The worst that may befall me in this case,
116
+ """
117
+ end
118
+
119
+ @tag :pending
120
+ test "several matches, print line numbers flag" do
121
+ assert Grep.grep("may", ["-n"], ["midsummer-night.txt"]) ==
122
+ """
123
+ 3:Nor how it may concern my modesty,
124
+ 5:But I beseech your grace that I may know
125
+ 6:The worst that may befall me in this case,
126
+ """
127
+ end
128
+
129
+ @tag :pending
130
+ test "several matches, match entire lines flag" do
131
+ assert Grep.grep("may", ["-x"], ["midsummer-night.txt"]) == ""
132
+ end
133
+
134
+ @tag :pending
135
+ test "several matches, case-insensitive flag" do
136
+ assert Grep.grep("ACHILLES", ["-i"], ["iliad.txt"]) ==
137
+ """
138
+ Achilles sing, O Goddess! Peleus' son;
139
+ The noble Chief Achilles from the son
140
+ """
141
+ end
142
+
143
+ @tag :pending
144
+ test "several matches, inverted flag" do
145
+ assert Grep.grep("Of", ["-v"], ["paradise-lost.txt"]) ==
146
+ """
147
+ Brought Death into the World, and all our woe,
148
+ With loss of Eden, till one greater Man
149
+ Restore us, and regain the blissful Seat,
150
+ Sing Heav'nly Muse, that on the secret top
151
+ That Shepherd, who first taught the chosen Seed
152
+ """
153
+ end
154
+
155
+ @tag :pending
156
+ test "no matches, various flags" do
157
+ assert Grep.grep("Gandalf", ["-n", "-l", "-x", "-i"], ["iliad.txt"]) == ""
158
+ end
159
+ end
160
+
161
+ describe "grepping multiples files at once" do
162
+
163
+ @tag :pending
164
+ test "one match, no flags" do
165
+ assert Grep.grep("Agamemnon", [],
166
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
167
+ """
168
+ iliad.txt:Of Atreus, Agamemnon, King of men.
169
+ """
170
+ end
171
+
172
+ @tag :pending
173
+ test "several matches, no flags" do
174
+ assert Grep.grep("may", [],
175
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
176
+ """
177
+ midsummer-night.txt:Nor how it may concern my modesty,
178
+ midsummer-night.txt:But I beseech your grace that I may know
179
+ midsummer-night.txt:The worst that may befall me in this case,
180
+ """
181
+ end
182
+
183
+ @tag :pending
184
+ test "several matches, print line numbers flag" do
185
+ assert Grep.grep("that", ["-n"],
186
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
187
+ """
188
+ midsummer-night.txt:5:But I beseech your grace that I may know
189
+ midsummer-night.txt:6:The worst that may befall me in this case,
190
+ paradise-lost.txt:2:Of that Forbidden Tree, whose mortal tast
191
+ paradise-lost.txt:6:Sing Heav'nly Muse, that on the secret top
192
+ """
193
+ end
194
+
195
+ @tag :pending
196
+ test "one match, print file names flag" do
197
+ assert Grep.grep("who", ["-l"],
198
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
199
+ """
200
+ iliad.txt
201
+ paradise-lost.txt
202
+ """
203
+ end
204
+
205
+ @tag :pending
206
+ test "several matches, case-insensitive flag" do
207
+ assert Grep.grep("TO", ["-i"],
208
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
209
+ """
210
+ iliad.txt:Caused to Achaia's host, sent many a soul
211
+ iliad.txt:Illustrious into Ades premature,
212
+ iliad.txt:And Heroes gave (so stood the will of Jove)
213
+ iliad.txt:To dogs and to all ravening fowls a prey,
214
+ midsummer-night.txt:I do entreat your grace to pardon me.
215
+ midsummer-night.txt:In such a presence here to plead my thoughts;
216
+ midsummer-night.txt:If I refuse to wed Demetrius.
217
+ paradise-lost.txt:Brought Death into the World, and all our woe,
218
+ paradise-lost.txt:Restore us, and regain the blissful Seat,
219
+ paradise-lost.txt:Sing Heav'nly Muse, that on the secret top
220
+ """
221
+ end
222
+
223
+ @tag :pending
224
+ test "several matches, inverted flag" do
225
+ assert Grep.grep("a", ["-v"],
226
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
227
+ """
228
+ iliad.txt:Achilles sing, O Goddess! Peleus' son;
229
+ iliad.txt:The noble Chief Achilles from the son
230
+ midsummer-night.txt:If I refuse to wed Demetrius.
231
+ """
232
+ end
233
+
234
+ @tag :pending
235
+ test "one match, match entire lines flag" do
236
+ assert Grep.grep("But I beseech your grace that I may know", ["-x"],
237
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
238
+ """
239
+ midsummer-night.txt:But I beseech your grace that I may know
240
+ """
241
+ end
242
+
243
+ @tag :pending
244
+ test "one match, multiple flags" do
245
+ assert Grep.grep("WITH LOSS OF EDEN, TILL ONE GREATER MAN",
246
+ ["-n", "-x", "-i"],
247
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) ==
248
+ """
249
+ paradise-lost.txt:4:With loss of Eden, till one greater Man
250
+ """
251
+ end
252
+
253
+ @tag :pending
254
+ test "no matches, various flags" do
255
+ assert Grep.grep("Frodo", ["-n", "-l", "-x", "i"],
256
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]) == ""
257
+ end
258
+ end
259
+ end
@@ -10,9 +10,66 @@ defmodule Markdown do
10
10
  iex> Markdown.parse("#Header!\n* __Bold Item__\n* _Italic Item_")
11
11
  "<h1>Header!</h1><ul><li><em>Bold Item</em></li><li><i>Italic Item</i></li></ul>"
12
12
  """
13
-
14
13
  @spec parse(String.t) :: String.t
15
- def parse(markdown) do
14
+ def parse(m) do
15
+ patch(Enum.join(Enum.map(String.split(m, "\n"), fn(t) -> process(t) end)))
16
+ end
17
+
18
+ defp process(t) do
19
+ if String.starts_with?(t, "#") || String.starts_with?(t, "*") do
20
+ if String.starts_with?(t, "#") do
21
+ enclose_with_header_tag(parse_header_md_level(t))
22
+ else
23
+ parse_list_md_level(t)
24
+ end
25
+ else
26
+ enclose_with_paragraph_tag(String.split(t))
27
+ end
28
+ end
29
+
30
+ defp parse_header_md_level(hwt) do
31
+ [h | t] = String.split(hwt)
32
+ {to_string(String.length(h)), Enum.join(t, " ")}
33
+ end
34
+
35
+ defp parse_list_md_level(l) do
36
+ t = String.split(String.trim_leading(l, "* "))
37
+ "<li>" <> join_words_with_tags(t) <> "</li>"
38
+ end
39
+
40
+ defp enclose_with_header_tag({hl, htl}) do
41
+ "<h" <> hl <> ">" <> htl <> "</h" <> hl <> ">"
42
+ end
43
+
44
+ defp enclose_with_paragraph_tag(t) do
45
+ "<p>#{join_words_with_tags(t)}</p>"
46
+ end
47
+
48
+ defp join_words_with_tags(t) do
49
+ Enum.join(Enum.map(t, fn(w) -> replace_md_with_tag(w) end), " ")
50
+ end
51
+
52
+ defp replace_md_with_tag(w) do
53
+ replace_suffix_md(replace_prefix_md(w))
54
+ end
55
+
56
+ defp replace_prefix_md(w) do
57
+ cond do
58
+ w =~ ~r/^#{"__"}{1}/ -> String.replace(w, ~r/^#{"__"}{1}/, "<strong>", global: false)
59
+ w =~ ~r/^[#{"_"}{1}][^#{"_"}+]/ -> String.replace(w, ~r/_/, "<em>", global: false)
60
+ true -> w
61
+ end
62
+ end
63
+
64
+ defp replace_suffix_md(w) do
65
+ cond do
66
+ w =~ ~r/#{"__"}{1}$/ -> String.replace(w, ~r/#{"__"}{1}$/, "</strong>")
67
+ w =~ ~r/[^#{"_"}{1}]/ -> String.replace(w, ~r/_/, "</em>")
68
+ true -> w
69
+ end
70
+ end
16
71
 
72
+ defp patch(l) do
73
+ String.replace_suffix(String.replace(l, "<li>", "<ul>" <> "<li>", global: false), "</li>", "</li>" <> "</ul>")
17
74
  end
18
75
  end
@@ -9,17 +9,17 @@ defmodule NucleotideCountTest do
9
9
  use ExUnit.Case
10
10
 
11
11
  # @tag :pending
12
- test "empty dna string has no adenosine" do
12
+ test "empty dna string has no adenine" do
13
13
  assert NucleotideCount.count('', ?A) == 0
14
14
  end
15
15
 
16
16
  @tag :pending
17
- test "repetitive cytidine gets counted" do
17
+ test "repetitive cytosine gets counted" do
18
18
  assert NucleotideCount.count('CCCCC', ?C) == 5
19
19
  end
20
20
 
21
21
  @tag :pending
22
- test "counts only thymidine" do
22
+ test "counts only thymine" do
23
23
  assert NucleotideCount.count('GGGGGTAACCCGG', ?T) == 1
24
24
  end
25
25
 
@@ -30,7 +30,7 @@ defmodule NucleotideCountTest do
30
30
  end
31
31
 
32
32
  @tag :pending
33
- test "repetitive sequence has only guanosine" do
33
+ test "repetitive sequence has only guanine" do
34
34
  expected = %{?A => 0, ?T => 0, ?C => 0, ?G => 8}
35
35
  assert NucleotideCount.histogram('GGGGGGGG') == expected
36
36
  end
@@ -37,6 +37,11 @@ defmodule PhoneTest do
37
37
  assert Phone.number("1a2a3a4a5a6a7a8a9a0a") == "0000000000"
38
38
  end
39
39
 
40
+ @tag :pending
41
+ test "invalid with correct number of characters but some are letters" do
42
+ assert Phone.number("1a2a3a4a5a") == "0000000000"
43
+ end
44
+
40
45
  @tag :pending
41
46
  test "area code" do
42
47
  assert Phone.area_code("1234567890") == "123"