You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The various file names and file paths have changed.
This breaks the documentation into three logical sections targeting
the tasks that the reader will likely want to choose from:
* regenerating the exercise
* changing a test suite
* implementing a new generator
@@ -65,50 +65,163 @@ Note that flags which have an attached value, like above, must take the form
65
65
### Generated Test Suites
66
66
67
67
If you find an `example.tt` file in a problem directory, then the test suite is
68
-
generated from shared data. In this case changing the test file itself will
69
-
not be enough.
68
+
generated from shared data, which can be found in the exercise definition in the [x-common][]
69
+
repository.
70
70
71
-
You will need to have cloned [the shared metadata](https://github.com/exercism/x-common)
72
-
at the same level as the xruby repository. E.g.
71
+
Typically you will want to do one of the following:
72
+
73
+
*[Regenerate the test suite](#regenerating-an-exercise) based on updated canonical data
74
+
*[Make changes to a generated exercise](#changing-a-generated-exercise)
75
+
*[Implement a new generator](#implementing-a-generator)
76
+
77
+
Generated exercises depend on the [the shared metadata][x-common], which must be
78
+
cloned to the same directory that contains your clone of the xruby repository:
73
79
74
80
```
75
81
tree -L 1 ~/code/exercism
76
82
├── x-common
77
83
└── xruby
78
84
```
79
85
80
-
1.`xruby/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`.
81
-
1.`x-common/$PROBLEM.json` - the shared inputs and outputs for the problem.
82
-
1.`lib/$PROBLEM.rb` - the logic for turning the data into tests.
83
-
1.`xruby/bin/generate $PROBLEM` - the command to actually generate the test suite.
84
-
1.`.version` - used to keep track of the version of the test files as the data changes.
86
+
#### Regenerating an Exercise
87
+
88
+
From within the xruby directory, run the following command, where $PROBLEM is the slug
89
+
of the exercise, e.g. `clock` or `atbash-cipher`:
90
+
91
+
```
92
+
bin/generate $PROBLEM
93
+
```
94
+
95
+
#### Changing a Generated Exercise
96
+
97
+
The `$PROBLEM/$PROBLEM_test.rb` will never be edited directly.
98
+
99
+
There are two reasons why a test suite might change:
100
+
101
+
1. the tests are wrong (an incorrect expectation, a missing edge case, etc)
102
+
1. there might be issues with the style or boilerplate
103
+
104
+
In the first case, the changes need to be made to the `canonical-data.json` file for
105
+
the exercise, which lives in the x-common repository.
106
+
107
+
```
108
+
../x-common/exercises/$PROBLEM/
109
+
├── canonical-data.json
110
+
├── description.md
111
+
└── metadata.yml
112
+
```
113
+
114
+
This change will need to be submitted as a pull request to the x-common repository. This pull
115
+
request needs to be merged before you can regenerate the exercise.
85
116
86
-
Additionally, there is some common generator logic in `lib/generator.rb`.
117
+
Changes that don't have to do directly with the test inputs and outputs, will either need to be
118
+
made to `exercises/$PROBLEM/example.tt` or `lib/$PROBLEM_cases.rb`. Then you can regenerate the
119
+
exercise with `bin/generate $PROBLEM`.
87
120
88
-
For example, take a look at the `hamming.json` file in the x-common repository, as well
89
-
as the following files in the xruby repository:
121
+
#### Implementing a Generator
90
122
91
-
1.`hamming/example.tt`
92
-
1.`bin/generate hamming`
93
-
1.`lib/hamming.rb`
94
-
1.`lib/generator.rb`
123
+
You will need to implement three files to create a generator:
95
124
96
-
The `hamming/hamming_test.rb` will never be edited directly. If there's a missing test case,
97
-
then additional inputs/outputs should be submitted to the x-common repository.
125
+
1.`exercises/$PROBLEM/example.tt` - the Erb template for the test file, `$PROBLEM_test.rb`.
126
+
1.`exercises/$PROBLEM/.meta/.version` - used to keep track of the version of the test files as the data changes.
127
+
1.`lib/$PROBLEM_cases.rb` - the logic for turning the data into tests.
98
128
99
-
Changes to the test suite (style, boilerplate, etc) will probably have to be made to
100
-
`example.tt`.
129
+
You will not need to touch the top-level script, `bin/generate`.
101
130
102
-
### Exercise Generators
131
+
The `bin/generate` command relies on some common logic implemented in `lib/generator.rb`.
132
+
You probably won't need to touch that, either.
103
133
104
-
If you wish to create a new generator, or edit an existing one, the generators currently live in the lib directory and are named `$PROBLEM_cases.rb`. For example, the hamming generator is `lib/hamming_cases.rb`.
134
+
The `lib/$PROBLEM_cases.rb` file should contain a small class that wraps the JSON for a single test case:
105
135
106
-
All generators currently adhere to a common public interface, and must define the following three methods:
136
+
```
137
+
require 'exercise_cases'
138
+
139
+
class ProblemNameCase < OpenStruct
140
+
def test_name
141
+
'test_%s' % description.gsub(/[ -]/, '_')
142
+
end
143
+
144
+
def workload
145
+
# implement main logic of test here
146
+
end
147
+
148
+
def skipped
149
+
index.zero? ? '# skip' : 'skip'
150
+
end
151
+
end
152
+
```
153
+
154
+
Instead of `ProblemName` use the name of the actual problem. This is important, since
155
+
the generator script will infer the name of the class from the argument that is passed.
156
+
157
+
This class must implement the following methods:
107
158
108
159
-`test_name` - Returns the name of the test (i.e `test_one_equals_one`)
109
160
-`workload` - Returns the main syntax for the test. This will vary depending on the test generator and its underlying implementation
110
161
-`skipped` - Returns skip syntax (i.e. `skip` or `# skip`)
111
162
163
+
Beyond that, you can implement any helper methods that you need.
164
+
165
+
Below this class, implement a small loop that will generate all the test cases by reading the
166
+
`canonical-data.json` file, and looping through the test cases.
167
+
168
+
You will need to adjust the logic to match the structure of the canonical data.
169
+
170
+
For example, if there is a single top-level key named "cases", then you can loop through
171
+
them as follows:
172
+
173
+
```
174
+
ProblemNameCases = proc do |data|
175
+
JSON.parse(data)['cases'].map.with_index do |row, i|
176
+
ProblemNameCase.new(row.merge('index' => i))
177
+
end
178
+
end
179
+
```
180
+
181
+
If there are multiple sections, then you will need to loop through the sections, and then
182
+
loop through each of the cases in an inner loop:
183
+
184
+
```
185
+
ProblemNameCases = proc do |data|
186
+
i = 0
187
+
json = JSON.parse(data)
188
+
cases = []
189
+
%w(section1 section2 etc).each do |section|
190
+
json[section]['cases'].each do |row|
191
+
row = row.merge(row.merge('index' => i, 'section' => section))
192
+
cases << ProblemNameCase.new(row)
193
+
i += 1
194
+
end
195
+
end
196
+
cases
197
+
end
198
+
```
199
+
200
+
Finally, you need to create a text template, `example.tt`, as the bases for the test suite.
201
+
202
+
Start with the following boilerplate, and adjust as necessary:
203
+
204
+
```
205
+
#!/usr/bin/env ruby
206
+
gem 'minitest', '>= 5.0.0'
207
+
require 'minitest/autorun'
208
+
require_relative '$PROBLEM'
209
+
210
+
# Common test data version: <%= abbreviated_commit_hash %>
211
+
class ProblemNameTest < Minitest::Test<% test_cases.each do |test_case| %>
0 commit comments