Skip to content

Commit 4476d22

Browse files
authored
tidy up contrib docs (#151)
1 parent 7ebb011 commit 4476d22

3 files changed

Lines changed: 170 additions & 111 deletions

File tree

CONTRIBUTING.md

Lines changed: 168 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,42 @@
22

33
## **Do you want to report a bug?**
44

5-
- **Ensure the bug was not already reported** by searching the [forum](https://forum.exercism.org/c/programming/moonscript).
5+
- **Ensure the bug was not already reported** by searching the [forum][forum].
66

7-
- If you're unable to find an open conversation addressing the problem, [open a new one](https://forum.exercism.org/new-topic?category=moonscript). Be sure to include a **title and clear description**, as much relevant information as possible, and (when possible) a **code sample**.
7+
- If you're unable to find an open conversation addressing the problem, [open a new one][forum-new-topic].
8+
Be sure to include a **title and clear description**, as much relevant information as possible, and (when possible) a **code sample**.
89

910
## **Do you want to fix a bug?**
1011

11-
- **Ensure that the bug is [reported](#do-you-want-to-report-a-bug)**.
12+
- **Ensure that the bug is reported (see above)**.
1213
Only start fixing the bug when there is agreement on whether (and how) it should be fixed.
1314

14-
- Fix the bug and [submit a Pull Request](https://exercism.org/docs/building/github/contributors-pull-request-guide) to this repository.
15+
- Fix the bug and [submit a Pull Request][pr-guide] to this repository.
1516

1617
- Ensure the PR description clearly describes the problem and solution.
1718
Include a link to the bug's corresponding forum conversation.
1819

19-
- Before submitting, please read the [Contributors Pull Request Guide](https://exercism.org/docs/building/github/contributors-pull-request-guide) and [Pull Request Guide](https://exercism.org/docs/community/being-a-good-community-member/pull-requests).
20+
- Before submitting, please read the [Contributors Pull Request Guide][pr-guide] and [Pull Request Guide][pr-other-guide].
2021

2122
## **Do you intend to add a new feature or change an existing one?**
2223

23-
- **Ensure that the feature or change is discussed on the [forum](https://forum.exercism.org/c/programming/moonscript).**
24+
- **Ensure that the feature or change is discussed on the [forum][forum].**
2425
Only start adding the feature or change when there is agreement on whether (and how) it should be added or changed.
2526

26-
- Add the feature or change and [submit a Pull Request](https://exercism.org/docs/building/github/contributors-pull-request-guide) to this repository.
27+
- Add the feature or change and [submit a Pull Request][pr-guide] to this repository.
2728

2829
- Ensure the PR description clearly describes the problem and solution.
2930
Include a link to the bug's corresponding forum conversation.
3031

31-
- Before submitting, please read the [Contributors Pull Request Guide](https://exercism.org/docs/building/github/contributors-pull-request-guide) and [Pull Request Guide](https://exercism.org/docs/community/being-a-good-community-member/pull-requests).
32+
- Before submitting, please read the [Contributors Pull Request Guide][pr-guide] and [Pull Request Guide][pr-other-guide].
3233

3334
## **Do you want to add an exercise?**
3435

3536
- **Ensure that someone else isn't already adding it**
36-
- start with the [Practice exercises to implement](https://github.com/exercism/moonscript/issues/102) issue.
37-
- also search the [forum](https://forum.exercism.org/c/programming/moonscript) and the repository's [issues](https://github.com/exercism/moonscript/issues) and [pull requests](https://github.com/exercism/moonscript/pulls).
37+
- start with the [Practice exercises to implement][exercise-list] issue.
38+
- also search the [forum][forum] and the repository's [issues][gh-issues] and [pull requests][gh-pulls].
3839

39-
- If nobody is yet adding the exercise, [open a conversation](https://forum.exercism.org/c/programming/moonscript) and indicate you'd like to add the exercise.
40+
- If nobody is yet adding the exercise, [open a conversation][forum] and indicate you'd like to add the exercise.
4041

4142
### Creating a new Practice Exercise
4243

@@ -67,23 +68,7 @@
6768
6869
- If yes:
6970
70-
1. Edit the spec_generator.
71-
72-
This is a MoonScript module that returns a table with 2 or 3 elements:
73-
74-
- (required) _one_ of the following
75-
- `module_name`: (string) this is the left-hand side of `${module_name} = require '${slug_name}'` in the test file
76-
- `module_imports`: (list of strings) this is the list of names that appear in `import ${names} from require '${slug_name}'` in the test file
77-
- (required) `generate_test`: this is a function that creates the body of each test case. It takes 2 parameters:
78-
- `case` is the Lua object for the test case
79-
- `level`, default value 2, is the indentation level of the body.
80-
- (optional) `test_helpers`: (string) a block of code that gets added at the top of the top-level `describe` block.
81-
- (optional) `exclusions`: (list of tables) identifies things from the canonical data to exclude.
82-
- See `simple-linked-list` and `gigasecond` spec generators for examples.
83-
84-
Look to see how it's implemented for other exercises.
85-
The `space-age` one is interesting: it uses the test_helpers block to register a custom assertion, and has expected errors.
86-
71+
1. Edit the spec_generator -- see below for more details.
8772
8873
2. Run the generator script and review the new test suite.
8974
@@ -95,7 +80,7 @@
9580
9681
1. Create the example solution: `.meta/example.moon`
9782
98-
* follow the [style guide](./STYLE.md).
83+
* follow the [style guide][style].
9984
10085
1. Test it with
10186
@@ -113,3 +98,157 @@
11398
1. Revisit the exercise difficulty in config.json if the implementation was harder/easier than expected.
11499

115100
1. Run `bin/configlet lint` to ensure that the new exercise conforms to Exercism standards.
101+
102+
### The spec_generator
103+
104+
The spec_generator.moon file is a MoonScript module containing the functions necessary to generate the test suite for practice exercises.
105+
106+
It is located in `exercises/practice/${slug_name}/.meta/` directory.
107+
108+
It's a module that returns a table.
109+
110+
#### Elements of returned table
111+
112+
- (required) _one_ of the following
113+
- `module_name`: (string) this is the left-hand side of `${module_name} = require '${slug_name}'` in the test file
114+
- `module_imports`: (list of strings) this is the list of names that appear in `import ${names} from require '${slug_name}'` in the test file
115+
- (required) `generate_test`: this is a function that creates the body of each test case. It takes 2 parameters:
116+
- `case` is the Lua object for one test case taken from the canonical data.
117+
- `level`, default value 2, is the indentation level of the body.
118+
MoonScript is a whitespace-sensitive language, so we need to be careful about indenting the test functions properly.
119+
- (optional) `test_helpers`: (string) a block of code that gets added at the top of the top-level `describe` block.
120+
This might include required modules used in the tests, or helper functions, or (more interstingly) custom assertions, or even just helpful comments for students.
121+
- (optional) `exclusions`: (list of tables) identifies things from the canonical data to exclude.
122+
Normally, setting `include = false` in the tests.toml file is the preferred way to exclude individual tests, but sometimes you want to exclude a whole block of tests.
123+
- Examples: [`simple-linked-list`][simple-linked-list], [`gigasecond`][gigasecond]
124+
- (optional) `bonus`: (string) bonus tests to add to the spec file as extra challenge for the students.
125+
These tests are not executed by the test runner.
126+
- Examples: [`robot-name`][robot-name], [`custom-set`][custom-set]
127+
128+
##### Examples of custom assertions
129+
130+
- [`dnd-character`][dnd-character] -- `assert.between value, min, max`
131+
- [`space-age`][space-age] -- `assert.approx_equal #{case.expected}, result`
132+
- [`word-count`][word-count] -- `assert.has.same_kv result, expected`
133+
134+
#### Helper functions for formatting test cases
135+
136+
##### Functions in bin/generate-spec
137+
138+
These functions are exported from [`bin/generate-spec`][generate-spec-exported] for use in spec_generator modules
139+
140+
- `indent(text, level)` -- provide leading whitespace to the appropriate level.
141+
- `quote(str)` -- add quotation marks to the string, single or double as appropriate.
142+
- `is_empty(tbl)` -- predicate: is the table empty
143+
- `is_json_null(value)` -- predicate: is the value `json.null` from dkjson
144+
- `contains(tbl, value)` -- predicate: does the table contain the value (uses `==`)
145+
146+
##### Helper functions
147+
148+
We have a library of helper functions, useful for generating pretty tables mostly.
149+
150+
For example, to nicely format a list of words, or a list of strings over multiple lines, or to recursively format nested tables.
151+
152+
**Look in [`lib/test_helpers.moon`][test-helpers].**
153+
154+
Example:
155+
156+
```moonscript
157+
import int_list, string_list from require 'test_helpers'
158+
...
159+
{
160+
generate_test: (case, level) ->
161+
lines = {
162+
"input = #{int_list case.input.numbers}"
163+
"expected = #{string_list case.expected, level}"
164+
...
165+
```
166+
167+
##### Comparing tables deeply
168+
169+
The `assert.are.same t1, t2` assertion is used to compare tables deeply.
170+
171+
<details><summary>
172+
However when they don't match, by default busted does not show the whole object, which makes it hard for the student to see the difference.
173+
</summary>
174+
175+
Consider this `busted` output where something is different in the `...more` sections.
176+
177+
```none
178+
Failure → ./rest_api_spec.moon @ 251
179+
rest-api iou lender owes borrower less than new loan
180+
...uarocks/lib/luarocks/rocks-5.4/busted/2.3.0-1/bin/busted:7: Expected objects to be the same.
181+
Passed in:
182+
(table: 0x641e0548a540) {
183+
*[users] = {
184+
[1] = {
185+
[balance] = 1.0
186+
[name] = 'Adam'
187+
[owed_by] = { ... more }
188+
[owes] = { } }
189+
*[2] = {
190+
[balance] = -1.0
191+
[name] = 'Bob'
192+
[owed_by] = { }
193+
*[owes] = { ... more } } } }
194+
Expected:
195+
(table: 0x641e0548a620) {
196+
*[users] = {
197+
[1] = {
198+
[balance] = 1.0
199+
[name] = 'Adam'
200+
[owed_by] = { ... more }
201+
[owes] = { } }
202+
*[2] = {
203+
[balance] = -1.0
204+
[name] = 'Bob'
205+
[owed_by] = { }
206+
*[owes] = { ... more } } } }
207+
```
208+
</details>
209+
210+
The solution here is to configure the `assert` object,.
211+
In the spec_generator.moon module, add this:
212+
213+
```none
214+
-- we have deep tables to compare, display it all when not the same
215+
test_helpers: [[
216+
assert\set_parameter "TableFormatLevel", 4
217+
]]
218+
```
219+
220+
Here, the value `4` was chosen to reflect the max depth of the expected value:
221+
222+
```none
223+
...1...2...3...4
224+
{
225+
users: {
226+
{
227+
owed_by: {
228+
Bob: 3.0
229+
}
230+
balance: 3.0
231+
owes: {}
232+
name: "Adam"
233+
},
234+
...
235+
```
236+
237+
238+
[forum]: https://forum.exercism.org/c/programming/moonscript
239+
[forum-new-topic]: https://forum.exercism.org/new-topic?category=moonscript
240+
[pr-guide]: https://exercism.org/docs/building/github/contributors-pull-request-guide
241+
[pr-other-guide]: https://exercism.org/docs/community/being-a-good-community-member/pull-requests
242+
[exercise-list]: https://github.com/exercism/moonscript/issues/102
243+
[gh-issues]: https://github.com/exercism/moonscript/issues
244+
[gh-pulls]: https://github.com/exercism/moonscript/pulls
245+
[style]: ./STYLE.md
246+
[generate-spec-exported]: ./bin/generate-spec#L51
247+
[test-helpers]: ./lib/test_helpers.moon
248+
[space-age]: ./exercises/practice/space-age/.meta/spec_generator.moon
249+
[word-count]: ./exercises/practice/word-count/.meta/spec_generator.moon
250+
[dnd-character]: ./exercises/practice/dnd-character/.meta/spec_generator.moon
251+
[gigasecond]: ./exercises/practice/gigasecond/.meta/spec_generator.moon
252+
[simple-linked-list]: ./exercises/practice/simple-linked-list/.meta/spec_generator.moon
253+
[custom-set]: ./exercises/practice/custom-set/.meta/spec_generator.moon#L42
254+
[robot-name]: ./exercises/practice/robot-name/robot_name_spec.moon#L59

STYLE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ Pick a style that you think is particularly readable for the module you're creat
4848
4949
MyClassName
5050
```
51+
52+
However if the class definition is the last thing in the module, it's not necessary to explicitly return the class name.
5153

5254
* a module that defines some functions can return the functions defined inside a table (note the colon after the function name):
5355

exercises/test_helpers.md

Lines changed: 0 additions & 82 deletions
This file was deleted.

0 commit comments

Comments
 (0)