Skip to content

Generators refactoring#601

Merged
ErikSchierboom merged 97 commits intoexercism:masterfrom
ErikSchierboom:generators-refactoring
Jul 15, 2018
Merged

Generators refactoring#601
ErikSchierboom merged 97 commits intoexercism:masterfrom
ErikSchierboom:generators-refactoring

Conversation

@ErikSchierboom
Copy link
Copy Markdown
Member

This is to test the newly enabled WIP plugin (see exercism/discussions#217 (comment)). And it will also give insight into how my refactoring attempt is progressing.

@ErikSchierboom ErikSchierboom changed the title WIP Generators refactoring Generators refactoring Jul 8, 2018
@ErikSchierboom
Copy link
Copy Markdown
Member Author

Finally, after much work, I'm done with my huge generators refactoring. It has become even bigger that the F# equivalent, and it contains the following improvements:

  • Simplified extension points available to generators to three virtual methods.
  • Removed as many of the classes the user should know about.
  • Greatly simplified rendering code.
  • Make data rendering code generic (handle any dictionary/array/list instead of only a couple of hardcoded ones).
  • Many places in which the generator code has been simplified.
  • Fixed a bug where the test methods were not always in the correct order when using nested canonical data cases.
  • Made canonical data and canonical data case classes immutable.
  • Allow testing of properties and constructors.
  • Use ValueTuple<T> where possible.
  • Add MultilineString class to allow generators to be explicit on how they want the data to be output.
  • Add helper method to render enumerations.
  • Remove unused code.
  • Updated documentation with more examples of common use cases.
  • Restructured namespaces to make the code have a better structure.
  • And just overall many, many improvements to make the code more readable.

CC @robkeim @jpreese

@ErikSchierboom ErikSchierboom requested a review from jpreese July 8, 2018 18:35
@ErikSchierboom
Copy link
Copy Markdown
Member Author

@robkeim @jpreese If this PR is too big too review, no sweat. If you do want to review, it might be best to just check out this branch and examine the code locally.

@robkeim
Copy link
Copy Markdown
Contributor

robkeim commented Jul 9, 2018

@ErikSchierboom I'm feeling brave... I'll take a look :)

@ErikSchierboom
Copy link
Copy Markdown
Member Author

@robkeim Great! I'm really interested in what you think.

Copy link
Copy Markdown
Contributor

@robkeim robkeim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work @ErikSchierboom! Super cool stuff 👍

Added a few comments and reviewed through CollatatzConjecture so far.

Comment thread docs/GENERATORS.md Outdated
Additional methods added using this override will be added to the bottom of the test suite.
In some case, you might want to override the parameters that are used as input parameters.

An example of this is the [two fer]() generator, which does not use any input parameters when the `"name"` input parameter is set to `null`:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing url here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread docs/GENERATORS.md Outdated

If a test method tests an instance method, you can also specify which parameters to use as constructor parameters (the others will be input parameters, unless specified otherwise).

An example of this is the [matrix]() generator, which specifies that the `"string"` parameter should be passed as a constructor parameter:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread docs/GENERATORS.md Outdated
Some test methods want to verify that an exception is being thrown.

Here the **Assert** is being overridden. The assert needs to call additional functions, but only if the property is `consistency`. Otherwise, render the assert as usual.
An example of this is the [RNA transcription]() generator, which defines that some test methods should throws an `ArgumentException`:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing url here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread docs/GENERATORS.md Outdated

This method allows you to customize the output of the test class. Only in rare cases would you want to override this method. The most common use case to override this method, is to add additional (helper) methods to the test suite.

An example of this is the [Tournament](https://github.com/exercism/csharp/blob/master/generators/Exercises/Tournament.cs) generator, which adds a helper method to the test suite:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: tournament should be lowercase to be consistent with the other test names

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

{
var inputBase = 2;
var digits = new int[0];
var digits = Array.Empty<int>();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread exercises/bowling/BowlingTest.cs Outdated
{
var sut = new BowlingGame();
var previousRolls = new [] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7 };
var previousRolls = new[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these all on separate lines but the previous tests aren't? IMO it's probably better to have it on one line

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess there are a few other occurrences in the rest of this test file.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is me trying to be clever. Many of the input arrays have a very limited number of elements (e.g. 1 or 2), in which case rendering them over multiple lines would be overkill IMHO. The code that does this check can be found here. It essentially checks if it is not an array of arrays and if the rendered single line output would be less than or equal to 72 characters. If so, it is output as a single line.

This is of course completely up for debate. I'd be happy to hear your thoughts on this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I could do, is detect how many lines would end up being created. If there are more than a given number, say 8, then I could put multiple elements on a single line. Would that be an option?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robkeim I've given it some more thought, and I think I was attempting to be a bit too clever. I've removed the automatic multi-line rendering of single-dimensional arrays. Exercises can choose to opt-in themselves, should they want to do multi-line array initialization.

Comment thread exercises/go-counting/Example.cs Outdated
new ValueTuple<int, int>(col+1, row),
new ValueTuple<int, int>(col, row+1)
(col, row - 1),
(col-1, row),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super minor: missing spaces around the - here and the + below

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

var expected = new string[]
{
""
var minefield = new[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: the fact that each row is a separate line here vs in the expected it's on one line makes this definitely look like it wasn't handwritten.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread exercises/sieve/SieveTest.cs Outdated
public void Find_primes_up_to_1000()
{
var expected = new[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 };
var expected = new[]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be on one line or a few lines instead of one line per number

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

@jpreese
Copy link
Copy Markdown
Contributor

jpreese commented Jul 9, 2018

haha, oh man.. where to start. Yeah, let me check this out locally and try to make sense of it all. Should hopefully have some time later in the week.

@ErikSchierboom
Copy link
Copy Markdown
Member Author

Although I do think the commits are really useful to see the gradual evolution of the refactoring, I think that squashing this will be the way to go when merging this PR.

Comment thread docs/GENERATORS.md Outdated
#### Customize test data

As an example, if you wanted to change the default behavior so that when the `Input` value of a test is a negative number, an exception should be thrown, the code would look like this.
There are quite some generators that want to change the input or expected value.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence doesn't seem quite right

Comment thread docs/GENERATORS.md Outdated
As an example, if you wanted to change the default behavior so that when the `Input` value of a test is a negative number, an exception should be thrown, the code would look like this.
There are quite some generators that want to change the input or expected value.

An example of this is the [bracket-push](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/BracketPush.cs) generator, which input value with the key `"value"` requires some additional escaping:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence doesn't seem quite right

Comment thread docs/GENERATORS.md Outdated
Some test methods want to verify that an exception is being thrown.

Here the **Assert** is being overridden. The assert needs to call additional functions, but only if the property is `consistency`. Otherwise, render the assert as usual.
An example of this is the [rna-transcription](https://github.com/exercism/csharp/blob/master/generators/Exercises/Generators/RnaTranscription.cs) generator, which defines that some test methods should throws an `ArgumentException`:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should throw*

Comment thread docs/GENERATORS.md Outdated
#### Custom input/constructor parameters

Additional methods added using this override will be added to the bottom of the test suite.
In some case, you might want to override the parameters that are used as input parameters.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cases*

Comment thread docs/GENERATORS.md Outdated
}
```

Note that as mentioned before, the namespace of any thrown exception types are automaticall added to the list of namespaces.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

automatically*

@jpreese
Copy link
Copy Markdown
Contributor

jpreese commented Jul 14, 2018

That review destroyed by browser.

@ErikSchierboom
Copy link
Copy Markdown
Member Author

@jpreese Thanks for the review. I've updated the docs.

Copy link
Copy Markdown
Contributor

@robkeim robkeim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome job @ErikSchierboom!!! Super high quality code as always 👍

@ErikSchierboom ErikSchierboom merged commit e3142cb into exercism:master Jul 15, 2018
@ErikSchierboom ErikSchierboom deleted the generators-refactoring branch July 15, 2018 16:38
@ErikSchierboom
Copy link
Copy Markdown
Member Author

Thanks a ton for reviewing @robkeim and @jpreese!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants