trackler 2.0.8.51 → 2.0.8.52

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/tracks/cpp/.editorconfig +21 -0
  4. data/tracks/cpp/exercises/anagram/anagram_test.cpp +2 -1
  5. data/tracks/cpp/exercises/nucleotide-count/example.cpp +5 -1
  6. data/tracks/cpp/exercises/nucleotide-count/nucleotide_count_test.cpp +5 -0
  7. data/tracks/cpp/exercises/queen-attack/queen_attack_test.cpp +8 -5
  8. data/tracks/elixir/config.json +8 -0
  9. data/tracks/elixir/exercises/hello-world/hello_world.exs +1 -1
  10. data/tracks/elixir/exercises/scale-generator/example.exs +119 -0
  11. data/tracks/elixir/exercises/scale-generator/scale_generator.exs +83 -0
  12. data/tracks/elixir/exercises/scale-generator/scale_generator_test.exs +282 -0
  13. data/tracks/go/README.md +17 -4
  14. data/tracks/go/gen/gen.go +85 -15
  15. data/tracks/java/exercises/pascals-triangle/src/example/java/PascalsTriangleGenerator.java +21 -0
  16. data/tracks/java/exercises/pascals-triangle/src/test/java/PascalsTriangleGeneratorTest.java +86 -0
  17. data/tracks/javascript/.github/stale.yml +0 -0
  18. data/tracks/javascript/exercises/leap/HINT.md +52 -0
  19. data/tracks/javascript/exercises/leap/leap.js +6 -2
  20. data/tracks/objective-c/docs/TESTS.md +5 -4
  21. data/tracks/purescript/config.json +8 -0
  22. data/tracks/purescript/exercises/crypto-square/bower.json +18 -0
  23. data/tracks/purescript/exercises/crypto-square/examples/src/CryptoSquare.purs +63 -0
  24. data/tracks/purescript/exercises/crypto-square/src/CryptoSquare.purs +6 -0
  25. data/tracks/purescript/exercises/crypto-square/test/Main.purs +92 -0
  26. data/tracks/ruby/exercises/hello-world/.meta/.version +1 -1
  27. data/tracks/ruby/exercises/hello-world/example.tt +7 -5
  28. data/tracks/ruby/exercises/hello-world/hello_world_test.rb +4 -15
  29. data/tracks/ruby/lib/hello_world_cases.rb +5 -5
  30. metadata +14 -6
  31. data/tracks/clojurescript/.github/ISSUE_TEMPLATE.md +0 -9
  32. data/tracks/cpp/exercises/queen-attack/require_equal_containers.h +0 -88
  33. data/tracks/java/exercises/pascals-triangle/src/example/java/PascalsTriangle.java +0 -26
  34. data/tracks/java/exercises/pascals-triangle/src/test/java/PascalsTriangleTest.java +0 -85
@@ -181,10 +181,23 @@ directory within each exercise that makes use of a test cases generator. This
181
181
  *.meta* directory will be ignored when a user fetches an exercise.
182
182
 
183
183
  Whenever the shared JSON data changes, the test cases will need to be regenerated.
184
- To do this, make sure that the **x-common** repository has been cloned in the same
185
- parent-directory as the **xgo** repository. Then navigate into the **xgo**
186
- directory and run `go run exercises/<exercise>/.meta/gen.go`. You should see
187
- that the `<exercise>/cases_test.go` file has changed. Commit the change.
184
+ The generator will first look for a local copy of the **x-common** repository.
185
+ If there isn't one it will attempt to get the relevant json data for the
186
+ exercise from the **x-common** repository on GitHub.
187
+
188
+ To use a local copy of the **x-common** repository, make sure that it has been
189
+ cloned into the same parent-directory as the **xgo** repository.
190
+
191
+ ```sh
192
+ $ tree -L 1 .
193
+ .
194
+ ├── x-common
195
+ └── xgo
196
+ ```
197
+
198
+ To regenerate the test cases, navigate into the **xgo** directory and run
199
+ `go run exercises/<exercise>/.meta/gen.go`. You should see that the
200
+ `<exercise>/cases_test.go` file has changed. Commit the change.
188
201
 
189
202
  ## Pull requests
190
203
 
@@ -7,18 +7,20 @@ import (
7
7
  "fmt"
8
8
  "go/format"
9
9
  "io/ioutil"
10
+ "log"
11
+ "net/http"
10
12
  "os"
11
13
  "os/exec"
12
14
  "path/filepath"
13
15
  "runtime"
14
16
  "text/template"
17
+ "time"
15
18
  )
16
19
 
17
- // dirMetadata is the location of the x-common repository
18
- // on the filesystem.
19
- // We're making the assumption that the x-common repository
20
- // has been cloned to the same parent directory as the xgo
21
- // repository. E.g.
20
+ // dirMetadata is the location of the x-common repository on the filesystem.
21
+ // We're making the assumption that the x-common repository has been cloned to
22
+ // the same parent directory as the xgo repository.
23
+ // E.g.
22
24
  //
23
25
  // $ tree -L 1 .
24
26
  // .
@@ -31,7 +33,21 @@ var dirMetadata string
31
33
  // the exercise directory. Falls back to the present working directory.
32
34
  var dirExercise string
33
35
 
34
- // Header tells how the test data was generated, for display in the header of cases_test.go
36
+ // genClient creates an http client with a 10 second timeout so we don't get
37
+ // stuck waiting for a response.
38
+ var genClient = &http.Client{Timeout: 10 * time.Second}
39
+
40
+ const (
41
+ // canonicalDataURL is the URL for the raw canonical-data.json data,
42
+ // requires exercise name.
43
+ canonicalDataURL = "https://raw.githubusercontent.com/exercism/x-common/master/exercises/%s/canonical-data.json"
44
+ // commitsURL is the GitHub api endpoint for the canonical-data.json
45
+ // file commit history, requires exercise name.
46
+ commitsURL = "https://api.github.com/repos/exercism/x-common/commits?path=exercises/%s/canonical-data.json"
47
+ )
48
+
49
+ // Header tells how the test data was generated, for display in the header of
50
+ // cases_test.go
35
51
  type Header struct {
36
52
  // Ori is a deprecated short name for Origin.
37
53
  // TODO: Remove Ori once everything switches to Origin.
@@ -70,11 +86,21 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
70
86
  return errors.New("unable to determine current path")
71
87
  }
72
88
  jFile := filepath.Join("exercises", exercise, "canonical-data.json")
73
- // find and read the json source file
74
- jPath, jOrigin, jCommit := getPath(jFile)
89
+ // try to find and read the local json source file
90
+ log.Printf("[LOCAL] fetching %s test data\n", exercise)
91
+ jPath, jOrigin, jCommit := getLocal(jFile)
92
+ if jPath != "" {
93
+ log.Printf("[LOCAL] source: %s\n", jPath)
94
+ }
75
95
  jSrc, err := ioutil.ReadFile(filepath.Join(jPath, jFile))
76
96
  if err != nil {
77
- return err
97
+ // fetch json data remotely if there's no local file
98
+ log.Println("[LOCAL] No test data found")
99
+ log.Printf("[REMOTE] fetching %s test data\n", exercise)
100
+ jSrc, jOrigin, jCommit, err = getRemote(exercise)
101
+ if err != nil {
102
+ return err
103
+ }
78
104
  }
79
105
 
80
106
  // unmarshal the json source to a Go structure
@@ -91,7 +117,7 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
91
117
  Version string
92
118
  }
93
119
  if err := json.Unmarshal(jSrc, &commonMetadata); err != nil {
94
- return fmt.Errorf(`Didn't contain version: %v`, err)
120
+ return fmt.Errorf(`didn't contain version: %v`, err)
95
121
  }
96
122
 
97
123
  // package up a little meta data
@@ -107,7 +133,7 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
107
133
 
108
134
  // render the Go test cases
109
135
  var b bytes.Buffer
110
- if err = t.Execute(&b, &d); err != nil {
136
+ if err := t.Execute(&b, &d); err != nil {
111
137
  return err
112
138
  }
113
139
  // clean it up
@@ -119,17 +145,17 @@ func Gen(exercise string, j interface{}, t *template.Template) error {
119
145
  return ioutil.WriteFile(filepath.Join(dirExercise, "cases_test.go"), src, 0666)
120
146
  }
121
147
 
122
- func getPath(jFile string) (jPath, jOrigin, jCommit string) {
148
+ func getLocal(jFile string) (jPath, jOrigin, jCommit string) {
123
149
  // Ideally draw from a .json which is pulled from the official x-common
124
150
  // repository. For development however, accept a file in current directory
125
151
  // if there is no .json in source control. Also allow an override in any
126
152
  // case by environment variable.
127
- if jPath = os.Getenv("EXTEST"); jPath > "" {
153
+ if jPath := os.Getenv("EXTEST"); jPath > "" {
128
154
  return jPath, "local file", "" // override
129
155
  }
130
156
  c := exec.Command("git", "log", "-1", "--oneline", jFile)
131
157
  c.Dir = dirMetadata
132
- ori, err := c.Output()
158
+ origin, err := c.Output()
133
159
  if err != nil {
134
160
  return "", "local file", "" // no source control
135
161
  }
@@ -137,5 +163,49 @@ func getPath(jFile string) (jPath, jOrigin, jCommit string) {
137
163
  return "", "local file", "" // not in source control
138
164
  }
139
165
  // good. return source control dir and commit.
140
- return c.Dir, "exercism/x-common", string(bytes.TrimSpace(ori))
166
+ return c.Dir, "exercism/x-common", string(bytes.TrimSpace(origin))
167
+ }
168
+
169
+ func getRemote(exercise string) (body []byte, jOrigin string, jCommit string, err error) {
170
+ url := fmt.Sprintf(canonicalDataURL, exercise)
171
+ resp, err := genClient.Get(url)
172
+ if err != nil {
173
+ return []byte{}, "", "", err
174
+ }
175
+ if resp.StatusCode != http.StatusOK {
176
+ return []byte{}, "", "", fmt.Errorf("error fetching remote data: %s", resp.Status)
177
+ }
178
+ defer resp.Body.Close()
179
+ body, err = ioutil.ReadAll(resp.Body)
180
+ if err != nil {
181
+ return []byte{}, "", "", err
182
+ }
183
+ c, err := getRemoteCommit(exercise)
184
+ if err != nil {
185
+ // we always expect to have the commit in the cases_test.go
186
+ // file, so return the error if we can't fetch it
187
+ return []byte{}, "", "", err
188
+ }
189
+ log.Printf("[REMOTE] source: %s\n", url)
190
+ return body, "exercism/x-common", c, nil
191
+ }
192
+
193
+ func getRemoteCommit(exercise string) (string, error) {
194
+ type Commits struct {
195
+ Sha string
196
+ Commit struct {
197
+ Message string
198
+ }
199
+ }
200
+ resp, err := genClient.Get(fmt.Sprintf(commitsURL, exercise))
201
+ if err != nil {
202
+ return "", err
203
+ }
204
+ defer resp.Body.Close()
205
+ var c []Commits
206
+ err = json.NewDecoder(resp.Body).Decode(&c)
207
+ if err != nil {
208
+ return "", err
209
+ }
210
+ return fmt.Sprintf("%s %s", c[0].Sha[0:7], c[0].Commit.Message), nil
141
211
  }
@@ -0,0 +1,21 @@
1
+ class PascalsTriangleGenerator {
2
+
3
+ int[][] generateTriangle(int rows) {
4
+ if (rows < 0) {
5
+ throw new IllegalArgumentException("Rows can't be negative!");
6
+ }
7
+
8
+ int[][] triangle = new int[rows][];
9
+
10
+ for (int i = 0; i < rows; i++) {
11
+ triangle[i] = new int[i + 1];
12
+ triangle[i][0] = 1;
13
+ for (int j = 1; j < i; j++) {
14
+ triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j];
15
+ }
16
+ triangle[i][i] = 1;
17
+ }
18
+ return triangle;
19
+ }
20
+
21
+ }
@@ -0,0 +1,86 @@
1
+ import org.junit.Before;
2
+ import org.junit.Test;
3
+ import org.junit.Ignore;
4
+ import org.junit.Rule;
5
+ import org.junit.rules.ExpectedException;
6
+
7
+
8
+ import static org.junit.Assert.assertArrayEquals;
9
+ import static org.junit.Assert.assertEquals;
10
+
11
+ /*
12
+ * version: 1.0.0
13
+ */
14
+ public class PascalsTriangleGeneratorTest {
15
+
16
+ private PascalsTriangleGenerator pascalsTriangleGenerator;
17
+
18
+ @Before
19
+ public void setUp() {
20
+ pascalsTriangleGenerator = new PascalsTriangleGenerator();
21
+ }
22
+
23
+ @Rule
24
+ public ExpectedException thrown = ExpectedException.none();
25
+
26
+ @Test
27
+ public void testTriangleWithZeroRows() {
28
+ int[][] expectedOutput = new int[][]{};
29
+
30
+ assertArrayEquals(expectedOutput, pascalsTriangleGenerator.generateTriangle(0));
31
+ }
32
+
33
+ @Ignore
34
+ @Test
35
+ public void testTriangleWithOneRow() {
36
+ int[][] expectedOutput = new int[][]{
37
+ {1}
38
+ };
39
+
40
+ assertArrayEquals(expectedOutput, pascalsTriangleGenerator.generateTriangle(1));
41
+ }
42
+
43
+ @Ignore
44
+ @Test
45
+ public void testTriangleWithTwoRows() {
46
+ int[][] expectedOutput = new int[][]{
47
+ {1},
48
+ {1, 1}
49
+ };
50
+
51
+ assertArrayEquals(expectedOutput, pascalsTriangleGenerator.generateTriangle(2));
52
+ }
53
+
54
+ @Ignore
55
+ @Test
56
+ public void testTriangleWithThreeRows() {
57
+ int[][] expectedOutput = new int[][]{
58
+ {1},
59
+ {1, 1},
60
+ {1, 2, 1}
61
+ };
62
+
63
+ assertArrayEquals(expectedOutput, pascalsTriangleGenerator.generateTriangle(3));
64
+ }
65
+
66
+ @Ignore
67
+ @Test
68
+ public void testTriangleWithFourRows() {
69
+ int[][] expectedOutput = new int[][]{
70
+ {1},
71
+ {1, 1},
72
+ {1, 2, 1},
73
+ {1, 3, 3, 1}
74
+ };
75
+
76
+ assertArrayEquals(expectedOutput, pascalsTriangleGenerator.generateTriangle(4));
77
+ }
78
+
79
+ @Ignore
80
+ @Test
81
+ public void testValidatesNotNegativeRows() {
82
+ thrown.expect(IllegalArgumentException.class);
83
+ pascalsTriangleGenerator.generateTriangle(-1);
84
+ }
85
+
86
+ }
File without changes
@@ -0,0 +1,52 @@
1
+ This is the first test for this exercise:
2
+
3
+ ```javascript
4
+ it('is not very common', function() {
5
+ var year = new Year(2015);
6
+ expect(year.isLeap()).toBe(false);
7
+ });
8
+ ```
9
+
10
+ Each test in the exercise follows the same pattern:
11
+
12
+ 1. A new Year is instantiated with a value and stored in a variable: year.
13
+ 2. The test calls an instance method, isLeap(), from the variable `year`.
14
+
15
+ The `Year` function is a constructor, which means that it is specifically designed to provide a template for new objects.
16
+
17
+ When a new `Year` object is created:
18
+
19
+ ```javascript
20
+ var year = new Year(2015);
21
+ ```
22
+
23
+ We expect `year` to, at the very least, have a specific value (in this case 2015) assigned to it. Otherwise it would not represent an actual year.
24
+
25
+ This means that we must store the value passed as a parameter when the new `Year` is created (2015), so that the new `Year` can access it.
26
+
27
+ The way a constructor stores these fundamental values (instance variables) is like this:
28
+
29
+ ```javascript
30
+ var Constructor = function(input) {
31
+ this.value = input;
32
+ };
33
+ ```
34
+
35
+ The `this` in the constructor refers to the newly created instance of the `Constructor`.
36
+
37
+ Once the input (parameter) is stored in an instance variable, any instance methods, such as:
38
+
39
+ ```javascript
40
+ Constructor.prototype.instanceMethod = function() {
41
+ // this method can now access the input by calling `this.value`
42
+ };
43
+ ```
44
+
45
+ The instance method accesses the input using `this.value` (in this example).
46
+
47
+ This is why code needs to be written in two separate functions:
48
+
49
+ 1. The first function, `Year`, is a constructor that serves as a template for year objects that are created with their value (such as 2015).
50
+ This function needs to store the input when a new `Year` is created.
51
+ 2. The second function, isLeap(), is an instance method that is called from a new `year`.
52
+ This function (method) should contain the logic to determine if the given year is a leap year.
@@ -3,9 +3,13 @@
3
3
  // convenience to get you started writing code faster.
4
4
  //
5
5
 
6
- var Year = function() {};
6
+ var Year = function(input) {
7
+ //
8
+ // YOUR CODE GOES HERE
9
+ //
10
+ };
7
11
 
8
- Year.prototype.isLeap = function(input) {
12
+ Year.prototype.isLeap = function() {
9
13
  //
10
14
  // YOUR CODE GOES HERE
11
15
  //
@@ -29,19 +29,20 @@ __Note:__ If you receive the error "No visible `@interface` for ExerciseName dec
29
29
 
30
30
  ### A Test Runner
31
31
 
32
- An alternative to manually generating the project file is to use a test runner utility, written in ruby, that will create a project file for you with the test file, header file and source file.
32
+ An alternative to manually generating the project file is to use a test runner utility written in ruby, [`objc`](https://rubygems.org/gems/objc/), that will create a project file for you with the test file, header file and source file.
33
33
 
34
34
  ```bash
35
35
  $ gem install objc
36
- $ brew install xctool
37
36
  ```
38
37
 
39
38
  Run the tests with:
40
39
 
41
40
  ```bash
42
- $ objc ExerciseName
41
+ $ objc -x ExerciseName
43
42
  ```
44
43
 
45
- The objc utility uses the exercise name to find the test file, `ExerciseNameTest.m`, the header file, `ExerciseName.h` and source file `ExerciseName.m`. The files are inserted into a temporary Xcode Project and then `xctool` is used to run the tests for the project.
44
+ (Note the `-x`/`--xcodebuild` flag, which specifies using `xcodebuild` instead of `xctool`. The latter does not work with Xcode's latest releases.)
45
+
46
+ The objc utility uses the exercise name to find the test file, `ExerciseNameTest.m`, the header file, `ExerciseName.h` and source file `ExerciseName.m`. The files are inserted into a temporary Xcode Project and then `xcodebuild` is used to run the tests for the project.
46
47
 
47
48
  While `objc` makes it so you never have to launch Xcode to complete these exercises, the error messages and feedback through the command-line are not as clear as through the Xcode user interface.
@@ -136,6 +136,14 @@
136
136
  "topics": [
137
137
  "strings"
138
138
  ]
139
+ },
140
+ {
141
+ "slug": "crypto-square",
142
+ "difficulty": 1,
143
+ "topics": [
144
+ "strings",
145
+ "matrices"
146
+ ]
139
147
  }
140
148
  ],
141
149
  "deprecated": [
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "crypto-square",
3
+ "ignore": [
4
+ "**/.*",
5
+ "node_modules",
6
+ "bower_components",
7
+ "output"
8
+ ],
9
+ "dependencies": {
10
+ "purescript-prelude": "^3.0.0",
11
+ "purescript-strings": "^3.0.0",
12
+ "purescript-unicode": "^3.0.1"
13
+ },
14
+ "devDependencies": {
15
+ "purescript-psci-support": "^3.0.0",
16
+ "purescript-test-unit": "^11.0.0"
17
+ }
18
+ }
@@ -0,0 +1,63 @@
1
+ module CryptoSquare
2
+ ( normalizedPlaintext
3
+ , plaintextSegments
4
+ , encoded
5
+ , ciphertext
6
+ ) where
7
+
8
+ import Prelude
9
+ import Data.Array as A
10
+ import Data.Array (filter, fromFoldable, replicate, toUnfoldable, (:))
11
+ import Data.Char.Unicode (isAlphaNum)
12
+ import Data.Foldable (maximum)
13
+ import Data.Int (ceil, toNumber)
14
+ import Data.List (transpose)
15
+ import Data.Maybe (fromMaybe)
16
+ import Data.String (drop, fromCharArray, joinWith, length, take, toCharArray, toLower)
17
+ import Math (sqrt)
18
+
19
+ normalizedPlaintext :: String -> String
20
+ normalizedPlaintext
21
+ = toCharArray
22
+ >>> filter isAlphaNum
23
+ >>> fromCharArray
24
+ >>> toLower
25
+
26
+ plaintextSegments :: String -> Array String
27
+ plaintextSegments str = toSquare norm
28
+ where norm = normalizedPlaintext str
29
+ cols = sqrt (length norm # toNumber) # ceil
30
+ toSquare "" = []
31
+ toSquare s = take cols s : toSquare (drop cols s)
32
+
33
+ transposeArray :: forall a. Array (Array a) -> Array (Array a)
34
+ transposeArray
35
+ = toUnfoldable
36
+ >>> map toUnfoldable
37
+ >>> transpose
38
+ >>> map fromFoldable
39
+ >>> fromFoldable
40
+
41
+ encoded :: String -> String
42
+ encoded = plaintextSegments
43
+ >>> map toCharArray
44
+ >>> transposeArray
45
+ >>> map fromCharArray
46
+ >>> joinWith ""
47
+
48
+ spaces :: Int -> Array Char
49
+ spaces n = replicate n ' '
50
+
51
+ equalPad :: Array (Array Char) -> Array (Array Char)
52
+ equalPad arr = map pad arr
53
+ where width = fromMaybe 0 (maximum $ map A.length arr)
54
+ pad el = el <> spaces (width - A.length el)
55
+
56
+ ciphertext :: String -> String
57
+ ciphertext = plaintextSegments
58
+ >>> map toCharArray
59
+ >>> transposeArray
60
+ >>> equalPad
61
+ >>> map fromCharArray
62
+ >>> joinWith " "
63
+