-
-
Notifications
You must be signed in to change notification settings - Fork 398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#722] New practice exercise yacht
#760
Conversation
Thank you for contributing to Based on the files changed in this PR, it would be good to pay attention to the following details when reviewing the PR:
Automated comment created by PR Commenter 🤖. |
exercises/practice/yacht/README.md
Outdated
@@ -0,0 +1,21 @@ | |||
# Yacht |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file can be deleted
exercises/practice/yacht/mix.exs
Outdated
[ | ||
app: :yacht, | ||
version: "0.1.0", | ||
# elixir: "~> 1.12", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While we encourage students to write using 1.12, our solution needs to be compatible back to 1.8 for the time being
# elixir: "~> 1.12", | |
# elixir: "~> 1.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, I'll edit this and make sure it works with 1.8. Thanks!
defmodule YachtTest do | ||
use ExUnit.Case | ||
|
||
@data Application.app_dir(:yacht, "priv/canonical-data.json") | ||
|> File.read!() | ||
|> Jason.decode!() | ||
|
||
for test_case <- @data["cases"] do | ||
test test_case["description"] do | ||
assert Yacht.score( | ||
unquote(test_case["input"]["category"]), | ||
unquote(test_case["input"]["dice"]) | ||
) == unquote(test_case["expected"]) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is pretty cool, but this is incompatible with the v3 test runner at present because it would require jason
to be available and as it is presently we don't have that build capacity. I don't want you to throw this away though, as I think there might be an application for this approach at some point.
In the mean time can you create a test suite file similar to how the other practice exercises are laid out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really awesome that you attempted to write a test generator! It is something that we would want to have in the track at some point, but it's a really big project that requires good planing beforehand and knowledge of how the track and the platform works. If you are interested in doing that, we should open a GitHub issue and talk about the requirements. There was a previous attempt that was abandoned (https://github.com/exercism/elixir/pull/521/files).
One of the requirements would be that the test generation needs to happen beforehand, not on the student's computer. The student needs to receive a ready test file with all of the test cases. The test file, in most exercises, is the only way to learn the requirements for the solution. The student shouldn't need to read canonical-data.json
to know how to solve the exercise. The student ideally should not even see the canonical-data.json
file 🙂. We want to encourage TDD, so the student also needs to be able to un-skip every test case one by one, and that's why all test files have pending tags for all tests but the first one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining the context around this and why this isn't a valid approach for the way the exercises work. I will definitely update this PR to include a test suite with the tests all explicitly written out so it will work as expected for students. I am interested in helping with that test file generation project, but I understand how it's separate and outside the scope of the exercises.
exercises/practice/yacht/mix.exs
Outdated
defp deps do | ||
[ | ||
{:jason, "~> 1.2"} | ||
] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use external dependencies in the test runner presently. See note down below about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only the test runner cannot handle external dependencies, we also have no process of explaining to students how external dependencies work and how to use them. If we were to allow external dependencies in exercises, we would need to edit a lot of student documentation on how to run the tests (e.g. mention that some exercises need mix install
before doing them) because many students are completely new to Elixir. It would also add a big problem of dependency version updates. We want to keep a broad range of Elixir versions in which the exercises can be solved, and sometimes it might not even be possible to have a single dependency version that runs on all Elixirs from 1.8 to 1.12. For all those reasons, we made a decision not to use any external dependencies for code that the student needs to run.
I think it's our fault that we didn't communicate this properly beforehand. This should be mentioned in CONTRIBUTING.md
🤔. I'll open a PR.
PS: let's not forget to remove the mix.lock
file from this PR 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, I will update the PR without the dependency. I mostly did this as a fun exercise for myself so please don't worry about it not being documented explicitly (the contributing documentation is very helpful). I had a feeling it might not fit in the project as-is but I'm happy to make the changes so it does.
@@ -0,0 +1,48 @@ | |||
# Generate tests.toml file from canonical-data.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting approach here, we haven't done anything like this yet to generate test files or test toml configurations so I think this might not work with our current set up for v3. Let me take a think what might need to change to accommodate this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I learned 2 days ago that Exercism already has a tool that generates tests.toml
files. It's a feature of configlet. @elibdev it's another failure on my part that I didn't mention this anywhere in the ticket or in the track's documentation. I'm going to open a PR that explains toml
files and how to generate them.
Great work on your part for automating this 👍 but this script can be deleted now 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, I'll delete this. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you a lot for the contribution 🎉. I am really sorry that I didn't write exhaustive documentation right away, which caused you to try very reasonable and clever automated approaches that need to be undone. I hope you have the time and motivation to do the changes, we would love to merge this PR with a new exercise 💜
I haven't edited the track config because I'm not sure how the difficulty would be rated.
Judging by your example solution, I would say... a 5? It's just a guess, it doesn't have to be perfect 😬
For "prerequisites", I would suggest:
"lists",
"cond",
"case",
"if",
"multiple-clause-functions",
"pattern-matching",
"guards",
"enum"
And for "practices", I would suggest "enum", but you would also need to remove "enum" from "practices" of another exercise, for example... Zebra Puzzle? There is a limit that a concept can be practiced by maximum 10 exercises.
exercises/practice/yacht/mix.exs
Outdated
defp deps do | ||
[ | ||
{:jason, "~> 1.2"} | ||
] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only the test runner cannot handle external dependencies, we also have no process of explaining to students how external dependencies work and how to use them. If we were to allow external dependencies in exercises, we would need to edit a lot of student documentation on how to run the tests (e.g. mention that some exercises need mix install
before doing them) because many students are completely new to Elixir. It would also add a big problem of dependency version updates. We want to keep a broad range of Elixir versions in which the exercises can be solved, and sometimes it might not even be possible to have a single dependency version that runs on all Elixirs from 1.8 to 1.12. For all those reasons, we made a decision not to use any external dependencies for code that the student needs to run.
I think it's our fault that we didn't communicate this properly beforehand. This should be mentioned in CONTRIBUTING.md
🤔. I'll open a PR.
PS: let's not forget to remove the mix.lock
file from this PR 🙂
defmodule YachtTest do | ||
use ExUnit.Case | ||
|
||
@data Application.app_dir(:yacht, "priv/canonical-data.json") | ||
|> File.read!() | ||
|> Jason.decode!() | ||
|
||
for test_case <- @data["cases"] do | ||
test test_case["description"] do | ||
assert Yacht.score( | ||
unquote(test_case["input"]["category"]), | ||
unquote(test_case["input"]["dice"]) | ||
) == unquote(test_case["expected"]) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really awesome that you attempted to write a test generator! It is something that we would want to have in the track at some point, but it's a really big project that requires good planing beforehand and knowledge of how the track and the platform works. If you are interested in doing that, we should open a GitHub issue and talk about the requirements. There was a previous attempt that was abandoned (https://github.com/exercism/elixir/pull/521/files).
One of the requirements would be that the test generation needs to happen beforehand, not on the student's computer. The student needs to receive a ready test file with all of the test cases. The test file, in most exercises, is the only way to learn the requirements for the solution. The student shouldn't need to read canonical-data.json
to know how to solve the exercise. The student ideally should not even see the canonical-data.json
file 🙂. We want to encourage TDD, so the student also needs to be able to un-skip every test case one by one, and that's why all test files have pending tags for all tests but the first one.
@@ -0,0 +1,48 @@ | |||
# Generate tests.toml file from canonical-data.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I learned 2 days ago that Exercism already has a tool that generates tests.toml
files. It's a feature of configlet. @elibdev it's another failure on my part that I didn't mention this anywhere in the ticket or in the track's documentation. I'm going to open a PR that explains toml
files and how to generate them.
Great work on your part for automating this 👍 but this script can be deleted now 🙂
|
||
def score("full house", dice) do | ||
full_house = | ||
Enum.frequencies(dice) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is only available from Elixir 1.10. One of the challenges of the example solution is that it needs to work in older versions too, currently we start testing from 1.7. I'm going to update the documentation to make this more explicit.
We had this problem with another exercise already 🙂 here:
elixir/exercises/practice/word-count/.meta/example.ex
Lines 27 to 33 in 0caae7f
defp frequencies(strings) do | |
# Enum.frequencies is only available from Elixir 1.10 | |
strings | |
|> Enum.reduce(%{}, fn word, count -> | |
Map.update(count, word, 1, &(&1 + 1)) | |
end) | |
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, I'll update my solution to not use Enum.frequencies/1
and will test it on Elixir 1.7 to make sure it works with that as well.
Thanks for all the feedback! I'll make the necessary changes that you've helpfully laid out. For the track config "practices" would it be better if I changed my solution to not use the |
No, don't worry about it! I think it's the nature of Exercism exrcises and Elixir's standard library that |
A couple things I wasn't sure about:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent ❤️ I left a small (optional) suggestion. The configlet / lint
is failing due to a typo in a filename, nothing serious.
Is that exercise UUID supposed to come from somewhere instead?
No, generating a new unique value is correct 👍
I think for this exercise the multiple clause matching does apply but I'm not sure if that's the right one to pick.
Sounds like a good pick to me! It's really hard to tell at the beginning. For existing exercises, we analyzed some community solutions to see which approaches people use the most. Here, we only have one solution... but I feel good about suggesting to students that they should solve this one with multiple clause functions 😄
@@ -0,0 +1,143 @@ | |||
defmodule YachtTest do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a typo in the file name
Co-authored-by: Angelika Tyborska <[email protected]>
All green = merge 🚀 Thank you again 💜. The next exercise won't be available on exercism.io until v3 is launched, but you will be able to check it out on v3 staging (https://exercism.lol/tracks/elixir). If you enjoyed adding a new exercise, I added a few more issues about more practice exercises 😇 |
Thank you for all your help, and I will check out the new exercise issues! 💜 |
This is my first contribution to this project, so I'm not sure if I've done everything right. I haven't edited the track config because I'm not sure how the difficulty would be rated. I would be happy to make any necessary changes to this PR. Thanks!