trackler 2.0.8.1 → 2.0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/fsharp/exercises/list-ops/Example.fs +5 -5
  4. data/tracks/fsharp/exercises/list-ops/ListOpsTest.fs +2 -2
  5. data/tracks/go/exercises/TRACK_HINTS.md +6 -2
  6. data/tracks/go/exercises/series/asktoomuch_test.go +4 -4
  7. data/tracks/go/exercises/series/example.go +2 -0
  8. data/tracks/go/exercises/series/first_test.go +3 -3
  9. data/tracks/go/exercises/series/series_test.go +10 -2
  10. data/tracks/java/exercises/pangram/src/test/java/PangramsTest.java +6 -0
  11. data/tracks/javascript/exercises/robot-simulator/example.js +8 -1
  12. data/tracks/javascript/exercises/robot-simulator/robot-simulator.spec.js +4 -4
  13. data/tracks/julia/docs/ABOUT.md +12 -0
  14. data/tracks/julia/docs/INSTALLATION.md +2 -0
  15. data/tracks/julia/docs/RESOURCES.md +6 -0
  16. data/tracks/ocaml/exercises/hello-world/example.ml +1 -4
  17. data/tracks/ocaml/exercises/hello-world/hello_world.ml +1 -2
  18. data/tracks/ocaml/exercises/hello-world/hello_world.mli +2 -10
  19. data/tracks/ocaml/exercises/hello-world/test.ml +1 -3
  20. data/tracks/ocaml/exercises/luhn/test.ml +14 -14
  21. data/tracks/ocaml/tools/test-generator/src/parser.ml +2 -1
  22. data/tracks/ocaml/tools/test-generator/templates/hello-world/template.ml +1 -1
  23. data/tracks/python/.travis.yml +1 -0
  24. data/tracks/python/config.json +25 -0
  25. data/tracks/python/exercises/all-your-base/all_your_base_test.py +82 -0
  26. data/tracks/python/exercises/all-your-base/example.py +23 -0
  27. data/tracks/python/exercises/grep/example.py +57 -0
  28. data/tracks/python/exercises/grep/grep_test.py +225 -0
  29. data/tracks/python/exercises/linked-list/example.py +14 -0
  30. data/tracks/python/exercises/linked-list/linked_list.py +2 -1
  31. data/tracks/python/exercises/linked-list/linked_list_test.py +18 -0
  32. data/tracks/python/exercises/word-search/example.py +57 -0
  33. data/tracks/python/exercises/word-search/word_search.py +27 -0
  34. data/tracks/python/exercises/word-search/word_search_test.py +84 -0
  35. data/tracks/python/requirements-travis.txt +1 -1
  36. data/tracks/python/test/check-exercises.py +44 -19
  37. data/tracks/scala/config.json +9 -0
  38. data/tracks/scala/exercises/perfect-numbers/build.sbt +3 -0
  39. data/tracks/scala/exercises/perfect-numbers/example.scala +24 -0
  40. data/tracks/scala/exercises/perfect-numbers/src/main/scala/PerfectNumbers.scala +0 -0
  41. data/tracks/scala/exercises/perfect-numbers/src/test/scala/PerfectNumbersTest.scala +62 -0
  42. data/tracks/typescript/Makefile +8 -0
  43. metadata +13 -2
@@ -0,0 +1,23 @@
1
+ def from_digits(digits, base):
2
+ return sum(n * base ** i for i, n in enumerate(reversed(digits)))
3
+
4
+
5
+ def to_digits(number, base_to):
6
+ result = []
7
+ while number > 0:
8
+ result.append(number % base_to)
9
+ number //= base_to
10
+ return result[::-1] # list(reversed(result))
11
+
12
+
13
+ def rebase(from_base, digits, to_base):
14
+ if (from_base < 2):
15
+ raise ValueError("Invalid input base.")
16
+
17
+ if (to_base < 2):
18
+ raise ValueError("Invalid output base.")
19
+
20
+ if any(True for d in digits if d < 0 or d >= from_base):
21
+ raise ValueError("Invalid input digit.")
22
+
23
+ return to_digits(from_digits(digits, from_base), to_base)
@@ -0,0 +1,57 @@
1
+ def matches(line, pattern, flags):
2
+ if '-i' in flags: # case-insensitive
3
+ line = line.lower()
4
+ pattern = pattern.lower()
5
+
6
+ if '-x' in flags: # match entire lines
7
+ if len(pattern) != len(line.rstrip()):
8
+ return False
9
+
10
+ if '-v' in flags: # invert matching
11
+ return pattern not in line
12
+
13
+ return pattern in line
14
+
15
+
16
+ def format_files(matched_lines):
17
+ result = ''
18
+
19
+ for file_name, _, _ in matched_lines:
20
+ if file_name not in result:
21
+ result += file_name + '\n'
22
+
23
+ return result
24
+
25
+
26
+ def format_lines(matched_lines, files, flags):
27
+ result = []
28
+
29
+ for file_name, line_number, line in matched_lines:
30
+ line_result = ""
31
+
32
+ if len(files) > 1:
33
+ line_result += file_name + ':'
34
+
35
+ if '-n' in flags:
36
+ line_result += str(line_number) + ':'
37
+
38
+ line_result += line
39
+
40
+ result.append(line_result)
41
+
42
+ return ''.join(result)
43
+
44
+
45
+ def grep(pattern, files, flags=''):
46
+ matched_lines = []
47
+
48
+ for file_name in files:
49
+ with open(file_name) as f:
50
+ for line_number, line in enumerate(f.readlines(), start=1):
51
+ if matches(line, pattern, flags):
52
+ matched_lines.append((file_name, line_number, line))
53
+
54
+ if '-l' in flags:
55
+ return format_files(matched_lines)
56
+
57
+ return format_lines(matched_lines, files, flags)
@@ -0,0 +1,225 @@
1
+ import os
2
+ import unittest
3
+
4
+ from grep import grep
5
+
6
+
7
+ ILIADFILENAME = 'iliad.txt'
8
+ ILIADCONTENTS = '''Achilles sing, O Goddess! Peleus' son;
9
+ His wrath pernicious, who ten thousand woes
10
+ Caused to Achaia's host, sent many a soul
11
+ Illustrious into Ades premature,
12
+ And Heroes gave (so stood the will of Jove)
13
+ To dogs and to all ravening fowls a prey,
14
+ When fierce dispute had separated once
15
+ The noble Chief Achilles from the son
16
+ Of Atreus, Agamemnon, King of men.
17
+ '''
18
+
19
+ MIDSUMMERNIGHTFILENAME = 'midsummer-night.txt'
20
+ MIDSUMMERNIGHTCONTENTS = '''I do entreat your grace to pardon me.
21
+ I know not by what power I am made bold,
22
+ Nor how it may concern my modesty,
23
+ In such a presence here to plead my thoughts;
24
+ But I beseech your grace that I may know
25
+ The worst that may befall me in this case,
26
+ If I refuse to wed Demetrius.
27
+ '''
28
+
29
+ PARADISELOSTFILENAME = 'paradise-lost.txt'
30
+ PARADISELOSTCONTENTS = '''Of Mans First Disobedience, and the Fruit
31
+ Of that Forbidden Tree, whose mortal tast
32
+ Brought Death into the World, and all our woe,
33
+ With loss of Eden, till one greater Man
34
+ Restore us, and regain the blissful Seat,
35
+ Sing Heav'nly Muse, that on the secret top
36
+ Of Oreb, or of Sinai, didst inspire
37
+ That Shepherd, who first taught the chosen Seed
38
+ '''
39
+
40
+
41
+ def remove_file(file_name):
42
+ try:
43
+ os.remove(file_name)
44
+ except OSError:
45
+ pass
46
+
47
+
48
+ def create_file(name, contents):
49
+ with open(name, 'w') as f:
50
+ f.write(contents)
51
+
52
+
53
+ class GrepTest(unittest.TestCase):
54
+
55
+ @classmethod
56
+ def setUpClass(self):
57
+ create_file(ILIADFILENAME, ILIADCONTENTS)
58
+ create_file(MIDSUMMERNIGHTFILENAME, MIDSUMMERNIGHTCONTENTS)
59
+ create_file(PARADISELOSTFILENAME, PARADISELOSTCONTENTS)
60
+
61
+ @classmethod
62
+ def tearDownClass(self):
63
+ remove_file(ILIADFILENAME)
64
+ remove_file(MIDSUMMERNIGHTFILENAME)
65
+ remove_file(PARADISELOSTFILENAME)
66
+
67
+ def test_one_file_one_match_no_flags(self):
68
+ self.assertMultiLineEqual(
69
+ grep("Agamemnon", [ILIADFILENAME]),
70
+ "Of Atreus, Agamemnon, King of men.\n"
71
+ )
72
+
73
+ def test_one_file_one_match_print_line_numbers_flag(self):
74
+ self.assertMultiLineEqual(
75
+ grep("Forbidden", [PARADISELOSTFILENAME], "-n"),
76
+ "2:Of that Forbidden Tree, whose mortal tast\n"
77
+ )
78
+
79
+ def test_one_file_one_match_case_insensitive_flag(self):
80
+ self.assertMultiLineEqual(
81
+ grep("FORBIDDEN", [PARADISELOSTFILENAME], "-i"),
82
+ "Of that Forbidden Tree, whose mortal tast\n"
83
+ )
84
+
85
+ def test_one_file_one_match_print_file_names_flag(self):
86
+ self.assertMultiLineEqual(
87
+ grep("Forbidden", [PARADISELOSTFILENAME], "-l"),
88
+ PARADISELOSTFILENAME + '\n'
89
+ )
90
+
91
+ def test_one_file_one_match_match_entire_lines_flag(self):
92
+ self.assertMultiLineEqual(
93
+ grep("With loss of Eden, till one greater Man", [PARADISELOSTFILENAME], "-x"),
94
+ "With loss of Eden, till one greater Man\n"
95
+ )
96
+
97
+ def test_one_file_one_match_multiple_flags(self):
98
+ self.assertMultiLineEqual(
99
+ grep("OF ATREUS, Agamemnon, KIng of MEN.", [ILIADFILENAME], "-n -i -x"),
100
+ "9:Of Atreus, Agamemnon, King of men.\n"
101
+ )
102
+
103
+ def test_one_file_several_matches_no_flags(self):
104
+ self.assertMultiLineEqual(
105
+ grep("may", [MIDSUMMERNIGHTFILENAME]),
106
+ ("Nor how it may concern my modesty,\n"
107
+ "But I beseech your grace that I may know\n"
108
+ "The worst that may befall me in this case,\n")
109
+ )
110
+
111
+ def test_one_file_several_matches_print_line_numbers_flag(self):
112
+ self.assertMultiLineEqual(
113
+ grep("may", [MIDSUMMERNIGHTFILENAME], "-n"),
114
+ ("3:Nor how it may concern my modesty,\n"
115
+ "5:But I beseech your grace that I may know\n"
116
+ "6:The worst that may befall me in this case,\n")
117
+ )
118
+
119
+ def test_one_file_several_matches_match_entire_lines_flag(self):
120
+ self.assertMultiLineEqual(
121
+ grep("may", [MIDSUMMERNIGHTFILENAME], "-x"),
122
+ ""
123
+ )
124
+
125
+ def test_one_file_several_matches_case_insensitive_flag(self):
126
+ self.assertMultiLineEqual(
127
+ grep("ACHILLES", [ILIADFILENAME], "-i"),
128
+ ("Achilles sing, O Goddess! Peleus' son;\n"
129
+ "The noble Chief Achilles from the son\n")
130
+ )
131
+
132
+ def test_one_file_several_matches_inverted_flag(self):
133
+ self.assertMultiLineEqual(
134
+ grep("Of", [PARADISELOSTFILENAME], "-v"),
135
+ ("Brought Death into the World, and all our woe,\n"
136
+ "With loss of Eden, till one greater Man\n"
137
+ "Restore us, and regain the blissful Seat,\n"
138
+ "Sing Heav'nly Muse, that on the secret top\n"
139
+ "That Shepherd, who first taught the chosen Seed\n")
140
+ )
141
+
142
+ def test_one_file_no_matches_various_flags(self):
143
+ self.assertMultiLineEqual(
144
+ grep("Gandalf", [ILIADFILENAME], "-n -l -x -i"),
145
+ ""
146
+ )
147
+
148
+ def test_multiple_files_one_match_no_flags(self):
149
+ self.assertMultiLineEqual(
150
+ grep("Agamemnon", [ILIADFILENAME, MIDSUMMERNIGHTFILENAME, PARADISELOSTFILENAME]),
151
+ "iliad.txt:Of Atreus, Agamemnon, King of men.\n"
152
+ )
153
+
154
+ def test_multiple_files_several_matches_no_flags(self):
155
+ self.assertMultiLineEqual(
156
+ grep("may", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"]),
157
+ ("midsummer-night.txt:Nor how it may concern my modesty,\n"
158
+ "midsummer-night.txt:But I beseech your grace that I may know\n"
159
+ "midsummer-night.txt:The worst that may befall me in this case,\n")
160
+ )
161
+
162
+ def test_multiple_files_several_matches_print_line_numbers_flag(self):
163
+ self.assertMultiLineEqual(
164
+ grep("that", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"], "-n"),
165
+ ("midsummer-night.txt:5:But I beseech your grace that I may know\n"
166
+ "midsummer-night.txt:6:The worst that may befall me in this case,\n"
167
+ "paradise-lost.txt:2:Of that Forbidden Tree, whose mortal tast\n"
168
+ "paradise-lost.txt:6:Sing Heav'nly Muse, that on the secret top\n")
169
+ )
170
+
171
+ def test_multiple_files_one_match_print_file_names_flag(self):
172
+ self.assertMultiLineEqual(
173
+ grep("who", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"], "-l"),
174
+ ILIADFILENAME + '\n' + PARADISELOSTFILENAME + '\n'
175
+ )
176
+
177
+ def test_multiple_files_several_matches_case_insensitive_flag(self):
178
+ self.assertMultiLineEqual(
179
+ grep("TO", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"], "-i"),
180
+ ("iliad.txt:Caused to Achaia's host, sent many a soul\n"
181
+ "iliad.txt:Illustrious into Ades premature,\n"
182
+ "iliad.txt:And Heroes gave (so stood the will of Jove)\n"
183
+ "iliad.txt:To dogs and to all ravening fowls a prey,\n"
184
+ "midsummer-night.txt:I do entreat your grace to pardon me.\n"
185
+ "midsummer-night.txt:In such a presence here to plead my thoughts;\n"
186
+ "midsummer-night.txt:If I refuse to wed Demetrius.\n"
187
+ "paradise-lost.txt:Brought Death into the World, and all our woe,\n"
188
+ "paradise-lost.txt:Restore us, and regain the blissful Seat,\n"
189
+ "paradise-lost.txt:Sing Heav'nly Muse, that on the secret top\n")
190
+ )
191
+
192
+ def test_multiple_files_several_matches_inverted_flag(self):
193
+ self.assertMultiLineEqual(
194
+ grep("a", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"], "-v"),
195
+ ("iliad.txt:Achilles sing, O Goddess! Peleus' son;\n"
196
+ "iliad.txt:The noble Chief Achilles from the son\n"
197
+ "midsummer-night.txt:If I refuse to wed Demetrius.\n")
198
+ )
199
+
200
+ def test_multiple_files_one_match_match_entire_lines_flag(self):
201
+ self.assertMultiLineEqual(
202
+ grep("But I beseech your grace that I may know",
203
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"],
204
+ "-x"),
205
+ "midsummer-night.txt:But I beseech your grace that I may know\n"
206
+ )
207
+
208
+ def test_multiple_files_one_match_multiple_flags(self):
209
+ self.assertMultiLineEqual(
210
+ grep("WITH LOSS OF EDEN, TILL ONE GREATER MAN",
211
+ ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"],
212
+ "-n -i -x"),
213
+ "paradise-lost.txt:4:With loss of Eden, till one greater Man\n"
214
+ )
215
+
216
+ def test_multiple_files_no_matches_various_flags(self):
217
+ self.assertMultiLineEqual(
218
+ grep("Frodo", ["iliad.txt", "midsummer-night.txt", "paradise-lost.txt"],
219
+ "-n -l -x -i"),
220
+ ""
221
+ )
222
+
223
+
224
+ if __name__ == '__main__':
225
+ unittest.main()
@@ -9,6 +9,7 @@ class LinkedList(object):
9
9
  def __init__(self):
10
10
  self.head = None
11
11
  self.tail = None
12
+ self.length = 0
12
13
 
13
14
  def push(self, value):
14
15
  new_node = Node(value)
@@ -18,6 +19,7 @@ class LinkedList(object):
18
19
  new_node.prev = self.tail
19
20
  self.tail.next = new_node
20
21
  self.tail = new_node
22
+ self.length += 1
21
23
 
22
24
  def pop(self):
23
25
  node = self.tail
@@ -26,6 +28,7 @@ class LinkedList(object):
26
28
  else:
27
29
  self.tail = self.tail.prev
28
30
  self.tail.next = None
31
+ self.length -= 1
29
32
  return node.value
30
33
 
31
34
  def shift(self):
@@ -35,6 +38,7 @@ class LinkedList(object):
35
38
  else:
36
39
  self.head = self.head.next
37
40
  self.head.prev = None
41
+ self.length -= 1
38
42
  return node.value
39
43
 
40
44
  def unshift(self, value):
@@ -45,3 +49,13 @@ class LinkedList(object):
45
49
  new_node.next = self.head
46
50
  self.head.prev = new_node
47
51
  self.head = new_node
52
+ self.length += 1
53
+
54
+ def __len__(self):
55
+ return self.length
56
+
57
+ def __iter__(self):
58
+ current_node = self.head
59
+ while (current_node):
60
+ yield current_node.value
61
+ current_node = current_node.next
@@ -1,4 +1,5 @@
1
1
  # Skeleton file for the Python "linked-list" exercise.
2
+ # Implement the LinkedList class
2
3
 
3
4
 
4
5
  class Node(object):
@@ -10,4 +11,4 @@ class Node(object):
10
11
 
11
12
  class LinkedList(object):
12
13
  def __init__(self):
13
- pass # Complete the Deque class ...
14
+ pass
@@ -44,6 +44,24 @@ class LinkedListTests(unittest.TestCase):
44
44
  self.assertEqual(50, self.list.pop())
45
45
  self.assertEqual(30, self.list.shift())
46
46
 
47
+ @unittest.skip("extra-credit")
48
+ def test_length(self):
49
+ self.list.push(10)
50
+ self.list.push(20)
51
+ self.assertEqual(2, len(self.list))
52
+ self.list.shift()
53
+ self.assertEqual(1, len(self.list))
54
+ self.list.pop()
55
+ self.assertEqual(0, len(self.list))
56
+
57
+ @unittest.skip("extra-credit")
58
+ def test_iterator(self):
59
+ self.list.push(10)
60
+ self.list.push(20)
61
+ iterator = iter(self.list)
62
+ self.assertEqual(10, next(iterator))
63
+ self.assertEqual(20, next(iterator))
64
+
47
65
 
48
66
  if __name__ == '__main__':
49
67
  unittest.main()
@@ -0,0 +1,57 @@
1
+ import copy
2
+
3
+
4
+ class Point(object):
5
+ def __init__(self, x, y):
6
+ self.x = x
7
+ self.y = y
8
+
9
+ def __repr__(self):
10
+ return 'Point({}:{})'.format(self.x, self.y)
11
+
12
+ def __add__(self, other):
13
+ return Point(self.x + other.x, self.y + other.y)
14
+
15
+ def __sub__(self, other):
16
+ return Point(self.x - other.x, self.y - other.y)
17
+
18
+ def __eq__(self, other):
19
+ return self.x == other.x and self.y == other.y
20
+
21
+ def __ne__(self, other):
22
+ return not(self == other)
23
+
24
+
25
+ DIRECTIONS = (Point(1, 0), Point(1, -1), Point(1, 1), Point(-1, -1),
26
+ Point(0, -1), Point(0, 1), Point(-1, 1), Point(-1, 0))
27
+
28
+
29
+ class WordSearch(object):
30
+ def __init__(self, puzzle):
31
+ self.rows = puzzle.split()
32
+ self.width = len(self.rows[0])
33
+ self.height = len(self.rows)
34
+
35
+ def find_char(self, coordinate):
36
+ if coordinate.x < 0 or coordinate.x >= self.width:
37
+ return
38
+ if coordinate.y < 0 or coordinate.y >= self.height:
39
+ return
40
+ return self.rows[coordinate.y][coordinate.x]
41
+
42
+ def find(self, word, position, direction):
43
+ current = copy.copy(position)
44
+ for letter in word:
45
+ if self.find_char(current) != letter:
46
+ return
47
+ current += direction
48
+ return position, current - direction
49
+
50
+ def search(self, word):
51
+ positions = (Point(x, y) for x in range(self.width) for y in range(self.height))
52
+ for pos in positions:
53
+ for d in DIRECTIONS:
54
+ result = self.find(word, pos, d)
55
+ if result:
56
+ return result
57
+ return None