trackler 2.1.0.31 → 2.1.0.32

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba0238c5efd0610f51d605a41a98489110c75117
4
- data.tar.gz: 3749d5108159a055ad4d2c68a99ed6297f01c272
3
+ metadata.gz: c5ad44a7e68d17060f904305997256916000928c
4
+ data.tar.gz: 262c51966c2eba2d2870792badd92f8f2f9ade76
5
5
  SHA512:
6
- metadata.gz: ba96c15d0f423acd0aee7ec87c11308d95bc8d634626361803a779bdbab47a278466de2baa348f698c628a95c3c0ab02e558f598aa6fcd4d65f19b2d9cdfbff4
7
- data.tar.gz: 70e84d13ae79a5d25eeba58d39ac848d2ae2b68c8d8c7f3d7c972e5beec589d58339005aa39fc1626242627fe1a041751b86e1bf7ff137c4a36621e73283ac2d
6
+ metadata.gz: 001fbb9c03793117bef7a7bad3c82ca75fe2ea41562b479a095dc505383e65edc6784a78de809a667ecd33c220f8789aa5f9a2889ca3c512682da5b0ff973545
7
+ data.tar.gz: 48e03ff57c34fa14be4bbef05786bcaf5928cc39feac666ce3c8139260bdbe9492e552f183c35a0829bd00f84b39d4d99629bf8196d014f72f768e269dc141c1
@@ -0,0 +1,3 @@
1
+ {
2
+ "slug": "coins"
3
+ }
@@ -0,0 +1 @@
1
+ This is the content of the docs/EXERCISE_README_INSERT.md file
@@ -1 +1 @@
1
- The SETUP.md file is deprecated, and exercises/TRACK_HINTS.md should be used.
1
+ The SETUP.md file is deprecated, and docs/EXERCISE_README_INSERT.md should be used.
@@ -119,15 +119,23 @@ module Trackler
119
119
  end
120
120
 
121
121
  def hints
122
- track_hints_filename = dir.join('exercises', 'TRACK_HINTS.md')
123
- unless File.exist?(track_hints_filename)
124
- track_hints_filename = dir.join('SETUP.md')
122
+ if File.exist?(track_hints_filename)
123
+ File.read(track_hints_filename)
124
+ else
125
+ ""
125
126
  end
126
- read track_hints_filename
127
127
  end
128
128
 
129
129
  private
130
130
 
131
+ def track_hints_filename
132
+ current = [File.join('docs', 'EXERCISE_README_INSERT.md')]
133
+ deprecated = [File.join('exercises', 'TRACK_HINTS.md'), 'SETUP.md']
134
+
135
+ filepaths = (current + deprecated).map { |name| dir.join(name) }
136
+ filepaths.find(-> { '' }) { |filepath| File.exist? filepath }
137
+ end
138
+
131
139
  # The slugs for the problems that are currently in the track.
132
140
  # We deprecated the old array of problem slugs in favor of an array
133
141
  # containing richer metadata about a given exercise.
@@ -202,13 +210,5 @@ module Trackler
202
210
  def png_icon
203
211
  @png_icon ||= Image.new(File.join(dir, "img/icon.png"))
204
212
  end
205
-
206
- def read(f)
207
- if File.exist?(f)
208
- File.read(f)
209
- else
210
- ""
211
- end
212
- end
213
213
  end
214
214
  end
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.1.0.31"
2
+ VERSION = "2.1.0.32"
3
3
  end
@@ -309,6 +309,15 @@
309
309
  "Parsing"
310
310
  ]
311
311
  },
312
+ {
313
+ "slug": "rotational-cipher",
314
+ "difficulty": 4,
315
+ "topics": [
316
+ "Strings",
317
+ "Algorithms",
318
+ "Transforming"
319
+ ]
320
+ },
312
321
  {
313
322
  "slug": "largest-series-product",
314
323
  "difficulty": 4,
@@ -210,6 +210,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZebraPuzzle", "zebra-puzzle
210
210
  EndProject
211
211
  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zipper", "zipper\Zipper.csproj", "{83504141-FF2A-427E-8A51-9FA0E9037A78}"
212
212
  EndProject
213
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RotationalCipher", "rotational-cipher\RotationalCipher.csproj", "{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}"
214
+ EndProject
213
215
  Global
214
216
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
215
217
  Debug|Any CPU = Debug|Any CPU
@@ -1468,6 +1470,18 @@ Global
1468
1470
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x64.Build.0 = Release|Any CPU
1469
1471
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x86.ActiveCfg = Release|Any CPU
1470
1472
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x86.Build.0 = Release|Any CPU
1473
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1474
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|Any CPU.Build.0 = Debug|Any CPU
1475
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|x64.ActiveCfg = Debug|x64
1476
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|x64.Build.0 = Debug|x64
1477
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|x86.ActiveCfg = Debug|x86
1478
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|x86.Build.0 = Debug|x86
1479
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|Any CPU.ActiveCfg = Release|Any CPU
1480
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|Any CPU.Build.0 = Release|Any CPU
1481
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|x64.ActiveCfg = Release|x64
1482
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|x64.Build.0 = Release|x64
1483
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|x86.ActiveCfg = Release|x86
1484
+ {DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|x86.Build.0 = Release|x86
1471
1485
  EndGlobalSection
1472
1486
  GlobalSection(SolutionProperties) = preSolution
1473
1487
  HideSolutionNode = FALSE
@@ -204,6 +204,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZebraPuzzle", "zebra-puzzle
204
204
  EndProject
205
205
  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zipper", "zipper\Zipper.csproj", "{83504141-FF2A-427E-8A51-9FA0E9037A78}"
206
206
  EndProject
207
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RotationalCipher", "rotational-cipher\RotationalCipher.csproj", "{F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}"
208
+ EndProject
207
209
  Global
208
210
  GlobalSection(SolutionConfigurationPlatforms) = preSolution
209
211
  Debug|Any CPU = Debug|Any CPU
@@ -1426,6 +1428,18 @@ Global
1426
1428
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x64.Build.0 = Release|Any CPU
1427
1429
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x86.ActiveCfg = Release|Any CPU
1428
1430
  {83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|x86.Build.0 = Release|Any CPU
1431
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1432
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|Any CPU.Build.0 = Debug|Any CPU
1433
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|x64.ActiveCfg = Debug|x64
1434
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|x64.Build.0 = Debug|x64
1435
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|x86.ActiveCfg = Debug|x86
1436
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Debug|x86.Build.0 = Debug|x86
1437
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|Any CPU.ActiveCfg = Release|Any CPU
1438
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|Any CPU.Build.0 = Release|Any CPU
1439
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|x64.ActiveCfg = Release|x64
1440
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|x64.Build.0 = Release|x64
1441
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|x86.ActiveCfg = Release|x86
1442
+ {F72CEE93-2F93-4408-8FCC-FBEB3AF0C285}.Release|x86.Build.0 = Release|x86
1429
1443
  EndGlobalSection
1430
1444
  GlobalSection(SolutionProperties) = preSolution
1431
1445
  HideSolutionNode = FALSE
@@ -0,0 +1,22 @@
1
+ using System;
2
+ using System.Linq;
3
+
4
+ public static class RotationalCipher
5
+ {
6
+ private const string LowerCaseLetters = "abcdefghijklmnopqrstuvwxyz";
7
+ private const string UpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
8
+
9
+ public static string Rotate(string text, int shiftKey)
10
+ => new string(text.Select(letter => Rotate(letter, shiftKey)).ToArray());
11
+
12
+ private static char Rotate(char letter, int shiftKey)
13
+ {
14
+ if (!char.IsLetter(letter))
15
+ return letter;
16
+
17
+ return Rotate(letter, shiftKey, char.IsLower(letter) ? LowerCaseLetters : UpperCaseLetters);
18
+ }
19
+
20
+ private static char Rotate(char letter, int shiftKey, string key)
21
+ => key[(key.IndexOf(letter) + shiftKey) % key.Length];
22
+ }
@@ -0,0 +1,9 @@
1
+ using System;
2
+
3
+ public static class RotationalCipher
4
+ {
5
+ public static string Rotate(string text, int shiftKey)
6
+ {
7
+ throw new NotImplementedException("You need to implement this function.");
8
+ }
9
+ }
@@ -0,0 +1,18 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <PropertyGroup>
4
+ <OutputType>Exe</OutputType>
5
+ <TargetFramework>netcoreapp1.0</TargetFramework>
6
+ </PropertyGroup>
7
+
8
+ <ItemGroup>
9
+ <Compile Remove="Example.cs" />
10
+ </ItemGroup>
11
+
12
+ <ItemGroup>
13
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
14
+ <PackageReference Include="xunit" Version="2.2.0" />
15
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
16
+ </ItemGroup>
17
+
18
+ </Project>
@@ -0,0 +1,64 @@
1
+ using Xunit;
2
+
3
+ public class RotationalCipherTest
4
+ {
5
+ [Fact]
6
+ public void Rotate_a_by_1()
7
+ {
8
+ Assert.Equal("b", RotationalCipher.Rotate("a", 1));
9
+ }
10
+
11
+ [Fact(Skip = "Remove to run test")]
12
+ public void Rotate_a_by_26_same_output_as_input()
13
+ {
14
+ Assert.Equal("a", RotationalCipher.Rotate("a", 26));
15
+ }
16
+
17
+ [Fact(Skip = "Remove to run test")]
18
+ public void Rotate_a_by_0_same_output_as_input()
19
+ {
20
+ Assert.Equal("a", RotationalCipher.Rotate("a", 0));
21
+ }
22
+
23
+ [Fact(Skip = "Remove to run test")]
24
+ public void Rotate_m_by_13()
25
+ {
26
+ Assert.Equal("z", RotationalCipher.Rotate("m", 13));
27
+ }
28
+
29
+ [Fact(Skip = "Remove to run test")]
30
+ public void Rotate_n_by_13_with_wrap_around_alphabet()
31
+ {
32
+ Assert.Equal("a", RotationalCipher.Rotate("n", 13));
33
+ }
34
+
35
+ [Fact(Skip = "Remove to run test")]
36
+ public void Rotate_capital_letters()
37
+ {
38
+ Assert.Equal("TRL", RotationalCipher.Rotate("OMG", 5));
39
+ }
40
+
41
+ [Fact(Skip = "Remove to run test")]
42
+ public void Rotate_spaces()
43
+ {
44
+ Assert.Equal("T R L", RotationalCipher.Rotate("O M G", 5));
45
+ }
46
+
47
+ [Fact(Skip = "Remove to run test")]
48
+ public void Rotate_numbers()
49
+ {
50
+ Assert.Equal("Xiwxmrk 1 2 3 xiwxmrk", RotationalCipher.Rotate("Testing 1 2 3 testing", 4));
51
+ }
52
+
53
+ [Fact(Skip = "Remove to run test")]
54
+ public void Rotate_punctuation()
55
+ {
56
+ Assert.Equal("Gzo'n zvo, Bmviyhv!", RotationalCipher.Rotate("Let's eat, Grandma!", 21));
57
+ }
58
+
59
+ [Fact(Skip = "Remove to run test")]
60
+ public void Rotate_all_letters()
61
+ {
62
+ Assert.Equal("Gur dhvpx oebja sbk whzcf bire gur ynml qbt.", RotationalCipher.Rotate("The quick brown fox jumps over the lazy dog.", 13));
63
+ }
64
+ }
@@ -0,0 +1,23 @@
1
+ using Generators.Data;
2
+ using Generators.Methods;
3
+
4
+ namespace Generators.Exercises
5
+ {
6
+ public class RotationalCipherExercise : EqualityExercise
7
+ {
8
+ public RotationalCipherExercise() : base("rotational-cipher")
9
+ {
10
+ }
11
+
12
+ protected override TestMethodData CreateTestMethodData(CanonicalData canonicalData, CanonicalDataCase canonicalDataCase, int index)
13
+ {
14
+ var testMethodData = base.CreateTestMethodData(canonicalData, canonicalDataCase, index);
15
+ testMethodData.CanonicalDataCase.Input = new[]
16
+ {
17
+ testMethodData.CanonicalDataCase.Data["text"],
18
+ testMethodData.CanonicalDataCase.Data["shiftKey"]
19
+ };
20
+ return testMethodData;
21
+ }
22
+ }
23
+ }
@@ -52,8 +52,12 @@ private static TestClass CreateTestClass(Exercise exercise)
52
52
  return exercise.CreateTestClass(canonicalData);
53
53
  }
54
54
 
55
- private static void SaveTestClassContentsToFile(string testClassFilePath, string testClassContents) =>
55
+ private static void SaveTestClassContentsToFile(string testClassFilePath, string testClassContents)
56
+ {
57
+ Directory.CreateDirectory(Path.GetDirectoryName(testClassFilePath));
56
58
  File.WriteAllText(testClassFilePath, testClassContents);
59
+ }
60
+
57
61
 
58
62
  private static string TestFilePath(Exercise exercise, TestClass testClass) => Path.Combine("..", "exercises", exercise.Name, TestFileName(testClass));
59
63
 
@@ -7,7 +7,7 @@ import org.junit.rules.ExpectedException;
7
7
  import static org.junit.Assert.assertEquals;
8
8
 
9
9
  /*
10
- * version: 1.0.0
10
+ * version: 1.1.0
11
11
  */
12
12
  public class CollatzCalculatorTest {
13
13
 
@@ -38,6 +38,12 @@ public class CollatzCalculatorTest {
38
38
  assertEquals(9, collatzCalculator.computeStepCount(12));
39
39
  }
40
40
 
41
+ @Ignore("Remove to run test")
42
+ @Test
43
+ public void testAVeryLargeInput() {
44
+ assertEquals(152, collatzCalculator.computeStepCount(1000000));
45
+ }
46
+
41
47
  @Ignore("Remove to run test")
42
48
  @Test
43
49
  public void testZeroIsConsideredInvalidInput() {
@@ -24,17 +24,26 @@ subtest 'Class methods', {
24
24
  }
25
25
 
26
26
  my $c-data;
27
- is ::($exercise).new(hour => .<hour>, minute => .<minute>).?time, |.<expected description> for @($c-data<cases>[0]<cases>);
28
- for @($c-data<cases>[1,2]) {
29
- for @(.<cases>) {
30
- my $clock = ::($exercise).new(hour => .<hour>, minute => .<minute>);
31
- $clock.?add-minutes(.<add>);
32
- is $clock.?time, |.<expected description>;
27
+ for @($c-data<cases>) {
28
+ for @(.<cases>) -> $case {
29
+ given $case<property> {
30
+ when 'create' {
31
+ is ::($exercise).new(hour => $case<hour>, minute => $case<minute>).?time, |$case<expected description>;
32
+ }
33
+ when 'add' {
34
+ my $clock = ::($exercise).new(hour => $case<hour>, minute => $case<minute>);
35
+ $clock.?add-minutes($case<add>);
36
+ is $clock.?time, |$case<expected description>;
37
+ }
38
+ when 'equal' {
39
+ is ::($exercise).new(hour => $case<clock1><hour>, minute => $case<clock1><minute>).?time eq
40
+ ::($exercise).new(hour => $case<clock2><hour>, minute => $case<clock2><minute>).?time,
41
+ |$case<expected description>;
42
+ }
43
+ when %*ENV<EXERCISM>.so { bail-out "no case for property '$case<property>'" }
44
+ }
33
45
  }
34
46
  }
35
- is ::($exercise).new(hour => .<clock1><hour>, minute => .<clock1><minute>).?time eq
36
- ::($exercise).new(hour => .<clock2><hour>, minute => .<clock2><minute>).?time,
37
- |.<expected description> for @($c-data<cases>[3]<cases>);
38
47
  todo 'optional test' unless %*ENV<EXERCISM>;
39
48
  is ::($exercise).new(:0hour,:0minute).?add-minutes(65).?time, '01:05', 'add-minutes method can be chained';
40
49
 
@@ -3,16 +3,25 @@ version: 1
3
3
  methods: time add-minutes
4
4
  plan: 54
5
5
  tests: |
6
- is ::($exercise).new(hour => .<hour>, minute => .<minute>).?time, |.<expected description> for @($c-data<cases>[0]<cases>);
7
- for @($c-data<cases>[1,2]) {
8
- for @(.<cases>) {
9
- my $clock = ::($exercise).new(hour => .<hour>, minute => .<minute>);
10
- $clock.?add-minutes(.<add>);
11
- is $clock.?time, |.<expected description>;
6
+ for @($c-data<cases>) {
7
+ for @(.<cases>) -> $case {
8
+ given $case<property> {
9
+ when 'create' {
10
+ is ::($exercise).new(hour => $case<hour>, minute => $case<minute>).?time, |$case<expected description>;
11
+ }
12
+ when 'add' {
13
+ my $clock = ::($exercise).new(hour => $case<hour>, minute => $case<minute>);
14
+ $clock.?add-minutes($case<add>);
15
+ is $clock.?time, |$case<expected description>;
16
+ }
17
+ when 'equal' {
18
+ is ::($exercise).new(hour => $case<clock1><hour>, minute => $case<clock1><minute>).?time eq
19
+ ::($exercise).new(hour => $case<clock2><hour>, minute => $case<clock2><minute>).?time,
20
+ |$case<expected description>;
21
+ }
22
+ when %*ENV<EXERCISM>.so { bail-out "no case for property '$case<property>'" }
23
+ }
12
24
  }
13
25
  }
14
- is ::($exercise).new(hour => .<clock1><hour>, minute => .<clock1><minute>).?time eq
15
- ::($exercise).new(hour => .<clock2><hour>, minute => .<clock2><minute>).?time,
16
- |.<expected description> for @($c-data<cases>[3]<cases>);
17
26
  todo 'optional test' unless %*ENV<EXERCISM>;
18
27
  is ::($exercise).new(:0hour,:0minute).?add-minutes(65).?time, '01:05', 'add-minutes method can be chained';
@@ -488,6 +488,14 @@
488
488
  "topics": [
489
489
  ]
490
490
  },
491
+ {
492
+ "slug": "scale-generator",
493
+ "difficulty": 3,
494
+ "topics": [
495
+ "strings",
496
+ "pattern matching"
497
+ ]
498
+ },
491
499
  {
492
500
  "slug": "protein-translation",
493
501
  "difficulty": 3,
@@ -0,0 +1,33 @@
1
+ class Scale(object):
2
+
3
+ ASCENDING_INTERVALS = ['m', 'M', 'A']
4
+ CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A',
5
+ 'A#', 'B']
6
+ FLAT_CHROMATIC_SCALE = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab',
7
+ 'A', 'Bb', 'B']
8
+ FLAT_KEYS = ['F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'd', 'g', 'c', 'f', 'bb',
9
+ 'eb']
10
+
11
+ def __init__(self, tonic, scale_name, pattern=None):
12
+ self.tonic = tonic.capitalize()
13
+ self.name = self.tonic + ' ' + scale_name
14
+ self.pattern = pattern
15
+ self.chromatic_scale = (self.FLAT_CHROMATIC_SCALE
16
+ if tonic in self.FLAT_KEYS else
17
+ self.CHROMATIC_SCALE)
18
+ self.pitches = self._assign_pitches()
19
+
20
+ def _assign_pitches(self):
21
+ if self.pattern is None:
22
+ return self._reorder_chromatic_scale()
23
+ last_index = 0
24
+ pitches = []
25
+ scale = self._reorder_chromatic_scale()
26
+ for i, interval in enumerate(self.pattern):
27
+ pitches.append(scale[last_index])
28
+ last_index += self.ASCENDING_INTERVALS.index(interval) + 1
29
+ return pitches
30
+
31
+ def _reorder_chromatic_scale(self):
32
+ index = self.chromatic_scale.index(self.tonic)
33
+ return self.chromatic_scale[index:] + self.chromatic_scale[:index]
@@ -0,0 +1,3 @@
1
+ class Scale(object):
2
+ def __init__(self):
3
+ pass
@@ -0,0 +1,120 @@
1
+ import unittest
2
+
3
+ from scale_generator import Scale
4
+
5
+
6
+ class ScaleGeneratorTest(unittest.TestCase):
7
+
8
+ def test_naming_scale(self):
9
+ chromatic = Scale('c', 'chromatic')
10
+ expected = 'C chromatic'
11
+ actual = chromatic.name
12
+ self.assertEqual(expected, actual)
13
+
14
+ def test_chromatic_scale(self):
15
+ chromatic = Scale('C', 'chromatic')
16
+ expected = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#',
17
+ 'B']
18
+ actual = chromatic.pitches
19
+ self.assertEqual(expected, actual)
20
+
21
+ def test_another_chromatic_scale(self):
22
+ chromatic = Scale('F', 'chromatic')
23
+ expected = ['F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B', 'C', 'Db', 'D', 'Eb',
24
+ 'E']
25
+ actual = chromatic.pitches
26
+ self.assertEqual(expected, actual)
27
+
28
+ def test_naming_major_scale(self):
29
+ major = Scale('G', 'major', 'MMmMMMm')
30
+ expected = 'G major'
31
+ actual = major.name
32
+ self.assertEqual(expected, actual)
33
+
34
+ def test_major_scale(self):
35
+ major = Scale('C', 'major', 'MMmMMMm')
36
+ expected = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
37
+ actual = major.pitches
38
+ self.assertEqual(expected, actual)
39
+
40
+ def test_another_major_scale(self):
41
+ major = Scale('G', 'major', 'MMmMMMm')
42
+ expected = ['G', 'A', 'B', 'C', 'D', 'E', 'F#']
43
+ actual = major.pitches
44
+ self.assertEqual(expected, actual)
45
+
46
+ def test_minor_scale(self):
47
+ minor = Scale('f#', 'minor', 'MmMMmMM')
48
+ expected = ['F#', 'G#', 'A', 'B', 'C#', 'D', 'E']
49
+ actual = minor.pitches
50
+ self.assertEqual(expected, actual)
51
+
52
+ def test_another_minor_scale(self):
53
+ minor = Scale('bb', 'minor', 'MmMMmMM')
54
+ expected = ['Bb', 'C', 'Db', 'Eb', 'F', 'Gb', 'Ab']
55
+ actual = minor.pitches
56
+ self.assertEqual(expected, actual)
57
+
58
+ def test_dorian_mode(self):
59
+ dorian = Scale('d', 'dorian', 'MmMMMmM')
60
+ expected = ['D', 'E', 'F', 'G', 'A', 'B', 'C']
61
+ actual = dorian.pitches
62
+ self.assertEqual(expected, actual)
63
+
64
+ def test_mixolydian_mode(self):
65
+ mixolydian = Scale('Eb', 'mixolydian', 'MMmMMmM')
66
+ expected = ['Eb', 'F', 'G', 'Ab', 'Bb', 'C', 'Db']
67
+ actual = mixolydian.pitches
68
+ self.assertEqual(expected, actual)
69
+
70
+ def test_lydian_mode(self):
71
+ lydian = Scale('a', 'lydian', 'MMMmMMm')
72
+ expected = ['A', 'B', 'C#', 'D#', 'E', 'F#', 'G#']
73
+ actual = lydian.pitches
74
+ self.assertEqual(expected, actual)
75
+
76
+ def test_phrygian_mode(self):
77
+ phrygian = Scale('e', 'phrygian', 'mMMMmMM')
78
+ expected = ['E', 'F', 'G', 'A', 'B', 'C', 'D']
79
+ actual = phrygian.pitches
80
+ self.assertEqual(expected, actual)
81
+
82
+ def test_locrian_mode(self):
83
+ locrian = Scale('g', 'locrian', 'mMMmMMM')
84
+ expected = ['G', 'Ab', 'Bb', 'C', 'Db', 'Eb', 'F']
85
+ actual = locrian.pitches
86
+ self.assertEqual(expected, actual)
87
+
88
+ def test_harmonic_minor(self):
89
+ harmonic_minor = Scale('d', 'harmonic_minor', 'MmMMmAm')
90
+ expected = ['D', 'E', 'F', 'G', 'A', 'Bb', 'Db']
91
+ actual = harmonic_minor.pitches
92
+ self.assertEqual(expected, actual)
93
+
94
+ def test_octatonic(self):
95
+ octatonic = Scale('C', 'octatonic', 'MmMmMmMm')
96
+ expected = ['C', 'D', 'D#', 'F', 'F#', 'G#', 'A', 'B']
97
+ actual = octatonic.pitches
98
+ self.assertEqual(expected, actual)
99
+
100
+ def test_hexatonic(self):
101
+ hexatonic = Scale('Db', 'hexatonic', 'MMMMMM')
102
+ expected = ['Db', 'Eb', 'F', 'G', 'A', 'B']
103
+ actual = hexatonic.pitches
104
+ self.assertEqual(expected, actual)
105
+
106
+ def test_pentatonic(self):
107
+ pentatonic = Scale('A', 'pentatonic', 'MMAMA')
108
+ expected = ['A', 'B', 'C#', 'E', 'F#']
109
+ actual = pentatonic.pitches
110
+ self.assertEqual(expected, actual)
111
+
112
+ def test_enigmatic(self):
113
+ enigmatic = Scale('G', 'enigmatic', 'mAMMMmM')
114
+ expected = ['G', 'G#', 'B', 'C#', 'D#', 'F', 'F#']
115
+ actual = enigmatic.pitches
116
+ self.assertEqual(expected, actual)
117
+
118
+
119
+ if __name__ == '__main__':
120
+ unittest.main()
@@ -1,9 +1,9 @@
1
1
  module BookKeeping
2
- VERSION = 3
2
+ VERSION = 4
3
3
  end
4
4
 
5
5
  class Isogram
6
- def self.is_isogram?(str)
6
+ def self.isogram?(str)
7
7
  letters = str.downcase.gsub(/[[:punct:]]| /, '').chars
8
8
  letters == letters.uniq
9
9
  end
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.1.0.31
4
+ version: 2.1.0.32
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-06-08 00:00:00.000000000 Z
11
+ date: 2017-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -475,6 +475,8 @@ files:
475
475
  - fixtures/tracks/animal/exercises/fish/included-via-symlink.txt
476
476
  - fixtures/tracks/animal/global/some-vendored-library
477
477
  - fixtures/tracks/animal/global/sub-global/other-some-vendor
478
+ - fixtures/tracks/coins/config.json
479
+ - fixtures/tracks/coins/docs/EXERCISE_README_INSERT.md
478
480
  - fixtures/tracks/fake/config.json
479
481
  - fixtures/tracks/fake/docs/ABOUT.org
480
482
  - fixtures/tracks/fake/docs/INSTALLATION.org
@@ -1807,6 +1809,10 @@ files:
1807
1809
  - tracks/csharp/exercises/roman-numerals/RomanNumerals.cs
1808
1810
  - tracks/csharp/exercises/roman-numerals/RomanNumerals.csproj
1809
1811
  - tracks/csharp/exercises/roman-numerals/RomanNumeralsTest.cs
1812
+ - tracks/csharp/exercises/rotational-cipher/Example.cs
1813
+ - tracks/csharp/exercises/rotational-cipher/RotationalCipher.cs
1814
+ - tracks/csharp/exercises/rotational-cipher/RotationalCipher.csproj
1815
+ - tracks/csharp/exercises/rotational-cipher/RotationalCipherTest.cs
1810
1816
  - tracks/csharp/exercises/run-length-encoding/Example.cs
1811
1817
  - tracks/csharp/exercises/run-length-encoding/RunLengthEncoding.cs
1812
1818
  - tracks/csharp/exercises/run-length-encoding/RunLengthEncoding.csproj
@@ -1953,6 +1959,7 @@ files:
1953
1959
  - tracks/csharp/generators/Exercises/PigLatinExercise.cs
1954
1960
  - tracks/csharp/generators/Exercises/RaindropsExercise.cs
1955
1961
  - tracks/csharp/generators/Exercises/RomanNumeralsExercise.cs
1962
+ - tracks/csharp/generators/Exercises/RotationalCipherExercise.cs
1956
1963
  - tracks/csharp/generators/Exercises/WordyExercise.cs
1957
1964
  - tracks/csharp/generators/Generators.csproj
1958
1965
  - tracks/csharp/generators/Generators.csproj.user
@@ -7164,6 +7171,9 @@ files:
7164
7171
  - tracks/python/exercises/say/example.py
7165
7172
  - tracks/python/exercises/say/say.py
7166
7173
  - tracks/python/exercises/say/say_test.py
7174
+ - tracks/python/exercises/scale-generator/example.py
7175
+ - tracks/python/exercises/scale-generator/scale_generator.py
7176
+ - tracks/python/exercises/scale-generator/scale_generator_test.py
7167
7177
  - tracks/python/exercises/scrabble-score/example.py
7168
7178
  - tracks/python/exercises/scrabble-score/scrabble_score.py
7169
7179
  - tracks/python/exercises/scrabble-score/scrabble_score_test.py