From 9adae4df1003b4e374fffb163dd5e1329b175494 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 20:06:55 +0200 Subject: [PATCH 1/9] Sync all outdated practice exercise docs --- .../binary-search/.docs/instructions.md | 2 +- .../practice/bowling/.docs/instructions.md | 2 +- .../crypto-square/.docs/instructions.md | 31 +++---- .../practice/darts/.docs/instructions.md | 2 +- .../practice/gigasecond/.docs/introduction.md | 4 +- exercises/practice/grep/.docs/instructions.md | 80 ++++--------------- .../linked-list/.docs/instructions.md | 4 +- .../matching-brackets/.docs/instructions.md | 1 + .../practice/meetup/.docs/instructions.md | 52 +++++++++--- .../practice/pangram/.docs/instructions.md | 2 +- .../practice/pangram/.docs/introduction.md | 4 +- .../resistor-color-trio/.docs/instructions.md | 8 +- .../saddle-points/.docs/instructions.md | 2 + exercises/practice/say/.docs/instructions.md | 10 --- .../secret-handshake/.docs/instructions.md | 1 + .../practice/sieve/.docs/instructions.md | 32 ++++---- .../practice/sieve/.docs/introduction.md | 7 ++ .../simple-cipher/.docs/instructions.md | 6 +- .../practice/space-age/.docs/instructions.md | 6 ++ .../practice/two-fer/.docs/instructions.md | 12 +-- 20 files changed, 125 insertions(+), 143 deletions(-) create mode 100644 exercises/practice/sieve/.docs/introduction.md diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md index d7f1c89922..aa1946cfb0 100644 --- a/exercises/practice/binary-search/.docs/instructions.md +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -11,7 +11,7 @@ Binary search only works when a list has been sorted. The algorithm looks like this: -- Find the middle element of a sorted list and compare it with the item we're looking for. +- Find the middle element of a *sorted* list and compare it with the item we're looking for. - If the middle element is our item, then we're done! - If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. - If the middle element is less than our item, we can eliminate that element and all the elements **before** it. diff --git a/exercises/practice/bowling/.docs/instructions.md b/exercises/practice/bowling/.docs/instructions.md index 48a2fedcf4..ddce7ee489 100644 --- a/exercises/practice/bowling/.docs/instructions.md +++ b/exercises/practice/bowling/.docs/instructions.md @@ -36,7 +36,7 @@ Frame 3 is (9 + 0) = 9 This means the current running total is 48. The tenth frame in the game is a special case. -If someone throws a strike or a spare then they get a fill ball. +If someone throws a spare or a strike then they get one or two fill balls respectively. Fill balls exist to calculate the total of the 10th frame. Scoring a strike or spare on the fill ball does not give the player more fill balls. The total value of the 10th frame is the total number of pins knocked down. diff --git a/exercises/practice/crypto-square/.docs/instructions.md b/exercises/practice/crypto-square/.docs/instructions.md index 8a489f6e2c..6c3826ee55 100644 --- a/exercises/practice/crypto-square/.docs/instructions.md +++ b/exercises/practice/crypto-square/.docs/instructions.md @@ -4,11 +4,10 @@ Implement the classic method for composing secret messages called a square code. Given an English text, output the encoded version of that text. -First, the input is normalized: the spaces and punctuation are removed -from the English text and the message is down-cased. +First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. -Then, the normalized characters are broken into rows. These rows can be -regarded as forming a rectangle when printed with intervening newlines. +Then, the normalized characters are broken into rows. +These rows can be regarded as forming a rectangle when printed with intervening newlines. For example, the sentence @@ -22,18 +21,16 @@ is normalized to: "ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" ``` -The plaintext should be organized in to a rectangle. The size of the -rectangle should be decided by the length of the message. +The plaintext should be organized into a rectangle as square as possible. +The size of the rectangle should be decided by the length of the message. -If `c` is the number of columns and `r` is the number of rows, then for -the rectangle `r` x `c` find the smallest possible integer `c` such that: +If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that: -- `r * c >= length(message)`, +- `r * c >= length of message`, - and `c >= r`, - and `c - r <= 1`. -Our normalized text is 54 characters long, dictating a rectangle with -`c = 8` and `r = 7`: +Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: ```text "ifmanwas" @@ -45,8 +42,7 @@ Our normalized text is 54 characters long, dictating a rectangle with "sroots " ``` -The coded message is obtained by reading down the columns going left to -right. +The coded message is obtained by reading down the columns going left to right. The message above is coded as: @@ -54,17 +50,14 @@ The message above is coded as: "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" ``` -Output the encoded text in chunks that fill perfect rectangles `(r X c)`, -with `c` chunks of `r` length, separated by spaces. For phrases that are -`n` characters short of the perfect rectangle, pad each of the last `n` -chunks with a single trailing space. +Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. +For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. ```text "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " ``` -Notice that were we to stack these, we could visually decode the -ciphertext back in to the original message: +Notice that were we to stack these, we could visually decode the ciphertext back in to the original message: ```text "imtgdvs" diff --git a/exercises/practice/darts/.docs/instructions.md b/exercises/practice/darts/.docs/instructions.md index 7af7428a06..70f0e53da7 100644 --- a/exercises/practice/darts/.docs/instructions.md +++ b/exercises/practice/darts/.docs/instructions.md @@ -12,7 +12,7 @@ In our particular instance of the game, the target rewards 4 different amounts o - If the dart lands in the inner circle of the target, player earns 10 points. The outer circle has a radius of 10 units (this is equivalent to the total radius for the entire target), the middle circle a radius of 5 units, and the inner circle a radius of 1. -Of course, they are all centered at the same point (that is, the circles are [concentric][] defined by the coordinates (0, 0). +Of course, they are all centered at the same point — that is, the circles are [concentric][] defined by the coordinates (0, 0). Write a function that given a point in the target (defined by its [Cartesian coordinates][cartesian-coordinates] `x` and `y`, where `x` and `y` are [real][real-numbers]), returns the correct amount earned by a dart landing at that point. diff --git a/exercises/practice/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md index 74afaa994f..18a3dc2005 100644 --- a/exercises/practice/gigasecond/.docs/introduction.md +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -13,7 +13,7 @@ Then we can use metric system prefixes for writing large numbers of seconds in m - Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). - And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. -```exercism/note +~~~~exercism/note If we ever colonize Mars or some other planet, measuring time is going to get even messier. If someone says "year" do they mean a year on Earth or a year on Mars? @@ -21,4 +21,4 @@ The idea for this exercise came from the science fiction novel ["A Deepness in t In it the author uses the metric system as the basis for time measurements. [vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ -``` +~~~~ diff --git a/exercises/practice/grep/.docs/instructions.md b/exercises/practice/grep/.docs/instructions.md index 7f4080f110..004f28acd5 100644 --- a/exercises/practice/grep/.docs/instructions.md +++ b/exercises/practice/grep/.docs/instructions.md @@ -1,79 +1,27 @@ # Instructions -Search a file for lines matching a regular expression pattern. Return the line -number and contents of each matching line. +Search files for lines matching a search string and return all matching lines. -The Unix [`grep`][grep] command can be used to search for lines in one or more files -that match a user-provided search query (known as the *pattern*). +The Unix [`grep`][grep] command searches files for lines that match a regular expression. +Your task is to implement a simplified `grep` command, which supports searching for fixed strings. The `grep` command takes three arguments: -1. The pattern used to match lines in a file. -2. Zero or more flags to customize the matching behavior. -3. One or more files in which to search for matching lines. +1. The string to search for. +2. Zero or more flags for customizing the command's behavior. +3. One or more files to search in. -Your task is to implement the `grep` function: given a list of files, find all -lines that match the specified pattern. -Return the lines in the order they appear in the files. -You'll also have to handle options (given as flags), which control how matching -is done and how the results are to be reported. - -As an example, suppose there is a file named "input.txt" with the following contents: - -```text -hello -world -hello again -``` - -If we were to call `grep "hello" input.txt`, the result should be: - -```text -hello -hello again -``` - -If given multiple files, `grep` should prefix each found line with the file it was found in. -As an example: - -```text -input.txt:hello -input.txt:hello again -greeting.txt:hello world -``` - -If given just one file, this prefix is not present. +It then reads the contents of the specified files (in the order specified), finds the lines that contain the search string, and finally returns those lines in the order in which they were found. +When searching in multiple files, each matching line is prepended by the file name and a colon (':'). ## Flags -As said earlier, the `grep` command should also support the following flags: - -- `-n` Prefix each matching line with its line number within its file. - When multiple files are present, this prefix goes *after* the filename prefix. -- `-l` Print only the names of files that contain at least one matching line. -- `-i` Match line using a case-insensitive comparison. -- `-v` Invert the program -- collect all lines that fail to match the pattern. -- `-x` Only match entire lines, instead of lines that contain a match. - -If we run `grep -n "hello" input.txt`, the `-n` flag will require the matching -lines to be prefixed with its line number: - -```text -1:hello -3:hello again -``` - -And if we run `grep -i "HELLO" input.txt`, we'll do a case-insensitive match, -and the output will be: - -```text -hello -hello again -``` - -The `grep` command should support multiple flags at once. +The `grep` command supports the following flags: -For example, running `grep -l -v "hello" file1.txt file2.txt` should -print the names of files that do not contain the string "hello". +- `-n` Prepend the line number and a colon (':') to each line in the output, placing the number after the filename (if present). +- `-l` Output only the names of the files that contain at least one matching line. +- `-i` Match using a case-insensitive comparison. +- `-v` Invert the program -- collect all lines that fail to match. +- `-x` Search only for lines where the search string matches the entire line. [grep]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html diff --git a/exercises/practice/linked-list/.docs/instructions.md b/exercises/practice/linked-list/.docs/instructions.md index a47942d73d..edf4055b38 100644 --- a/exercises/practice/linked-list/.docs/instructions.md +++ b/exercises/practice/linked-list/.docs/instructions.md @@ -13,7 +13,7 @@ Sometimes a station gets closed down, and in that case the station needs to be r The size of a route is measured not by how far the train travels, but by how many stations it stops at. -```exercism/note +~~~~exercism/note The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. As the name suggests, it is a list of nodes that are linked together. It is a list of "nodes", where each node links to its neighbor or neighbors. @@ -23,4 +23,4 @@ In a **doubly linked list** each node links to both the node that comes before, If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings. [intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d -``` +~~~~ diff --git a/exercises/practice/matching-brackets/.docs/instructions.md b/exercises/practice/matching-brackets/.docs/instructions.md index ca7c8d838e..544daa968d 100644 --- a/exercises/practice/matching-brackets/.docs/instructions.md +++ b/exercises/practice/matching-brackets/.docs/instructions.md @@ -1,3 +1,4 @@ # Instructions Given a string containing brackets `[]`, braces `{}`, parentheses `()`, or any combination thereof, verify that any and all pairs are matched and nested correctly. +The string may also contain other characters, which for the purposes of this exercise should be ignored. diff --git a/exercises/practice/meetup/.docs/instructions.md b/exercises/practice/meetup/.docs/instructions.md index 788f9f7c63..0694ef583c 100644 --- a/exercises/practice/meetup/.docs/instructions.md +++ b/exercises/practice/meetup/.docs/instructions.md @@ -1,19 +1,51 @@ # Instructions -In this exercise, you will be given a general description of a meetup date and then asked to find the actual meetup date. +Recurring monthly meetups are generally scheduled on the given weekday of a given week each month. +In this exercise you will be given the recurring schedule, along with a month and year, and then asked to find the exact date of the meetup. -Examples of general descriptions are: +For example a meetup might be scheduled on the _first Monday_ of every month. +You might then be asked to find the date that this meetup will happen in January 2018. +In other words, you need to determine the date of the first Monday of January 2018. -- First Monday of January 2022 -- Third Tuesday of August 2021 -- Teenth Wednesday of May 2022 -- Teenth Sunday of July 2021 -- Last Thursday of November 2021 +Similarly, you might be asked to find: + +- the third Tuesday of August 2019 (August 20, 2019) +- the teenth Wednesday of May 2020 (May 13, 2020) +- the fourth Sunday of July 2021 (July 25, 2021) +- the last Thursday of November 2022 (November 24, 2022) The descriptors you are expected to process are: `first`, `second`, `third`, `fourth`, `last`, `teenth`. Note that descriptor `teenth` is a made-up word. -There are exactly seven numbered days in a month that end with "teenth" ("thirteenth" to "nineteenth"). -Therefore, it is guaranteed that each day of the week (Monday, Tuesday, ...) will have exactly one numbered day ending with "teenth" each month. -For example, if given "First Monday of January 2022", the correct meetup date is January 3, 2022. +It refers to the seven numbers that end in '-teen' in English: 13, 14, 15, 16, 17, 18, and 19. +But general descriptions of dates use ordinal numbers, e.g. the _first_ Monday, the _third_ Tuesday. + +For the numbers ending in '-teen', that becomes: + +- 13th (thirteenth) +- 14th (fourteenth) +- 15th (fifteenth) +- 16th (sixteenth) +- 17th (seventeenth) +- 18th (eighteenth) +- 19th (nineteenth) + +So there are seven numbers ending in '-teen'. +And there are also seven weekdays (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday). +Therefore, it is guaranteed that each day of the week (Monday, Tuesday, ...) will have exactly one numbered day ending with "teen" each month. + +If asked to find the teenth Saturday of August, 1953 (or, alternately the "Saturteenth" of August, 1953), we need to look at the calendar for August 1953: + +```plaintext + August 1953 +Su Mo Tu We Th Fr Sa + 1 + 2 3 4 5 6 7 8 + 9 10 11 12 13 14 15 +16 17 18 19 20 21 22 +23 24 25 26 27 28 29 +30 31 +``` + +The Saturday that has a number ending in '-teen' is August 15, 1953. diff --git a/exercises/practice/pangram/.docs/instructions.md b/exercises/practice/pangram/.docs/instructions.md index d5698bc2a2..817c872d90 100644 --- a/exercises/practice/pangram/.docs/instructions.md +++ b/exercises/practice/pangram/.docs/instructions.md @@ -5,4 +5,4 @@ Your task is to figure out if a sentence is a pangram. A pangram is a sentence using every letter of the alphabet at least once. It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). -For this exercise we only use the basic letters used in the English alphabet: `a` to `z`. +For this exercise, a sentence is a pangram if it contains each of the 26 letters in the English alphabet. diff --git a/exercises/practice/pangram/.docs/introduction.md b/exercises/practice/pangram/.docs/introduction.md index d38fa341df..32b6f1fc31 100644 --- a/exercises/practice/pangram/.docs/introduction.md +++ b/exercises/practice/pangram/.docs/introduction.md @@ -7,10 +7,10 @@ To give a comprehensive sense of the font, the random sentences should use **all They're running a competition to get suggestions for sentences that they can use. You're in charge of checking the submissions to see if they are valid. -```exercism/note +~~~~exercism/note Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". The best known English pangram is: > The quick brown fox jumps over the lazy dog. -``` +~~~~ diff --git a/exercises/practice/resistor-color-trio/.docs/instructions.md b/exercises/practice/resistor-color-trio/.docs/instructions.md index fcc76958a5..4ad2aede37 100644 --- a/exercises/practice/resistor-color-trio/.docs/instructions.md +++ b/exercises/practice/resistor-color-trio/.docs/instructions.md @@ -46,9 +46,11 @@ So an input of `"orange", "orange", "black"` should return: > "33 ohms" -When we get more than a thousand ohms, we say "kiloohms". -That's similar to saying "kilometer" for 1000 meters, and "kilograms" for 1000 grams. +When we get to larger resistors, a [metric prefix][metric-prefix] is used to indicate a larger magnitude of ohms, such as "kiloohms". +That is similar to saying "2 kilometers" instead of "2000 meters", or "2 kilograms" for "2000 grams". -So an input of `"orange", "orange", "orange"` should return: +For example, an input of `"orange", "orange", "orange"` should return: > "33 kiloohms" + +[metric-prefix]: https://en.wikipedia.org/wiki/Metric_prefix diff --git a/exercises/practice/saddle-points/.docs/instructions.md b/exercises/practice/saddle-points/.docs/instructions.md index 9b42a84691..749173f91a 100644 --- a/exercises/practice/saddle-points/.docs/instructions.md +++ b/exercises/practice/saddle-points/.docs/instructions.md @@ -12,11 +12,13 @@ Or it might have one, or even several. Here is a grid that has exactly one candidate tree. +```text 1 2 3 4 |----------- 1 | 9 8 7 8 2 | 5 3 2 4 <--- potential tree house at row 2, column 1, for tree with height 5 3 | 6 6 7 1 +``` - Row 2 has values 5, 3, 2, and 4. The largest value is 5. - Column 1 has values 9, 5, and 6. The smallest value is 5. diff --git a/exercises/practice/say/.docs/instructions.md b/exercises/practice/say/.docs/instructions.md index aa2e7687fe..fb4a6dfb98 100644 --- a/exercises/practice/say/.docs/instructions.md +++ b/exercises/practice/say/.docs/instructions.md @@ -48,13 +48,3 @@ Put it all together to get nothing but plain English. `12345` should give `twelve thousand three hundred forty-five`. The program must also report any values that are out of range. - -### Extensions - -Use _and_ (correctly) when spelling out the number in English: - -- 14 becomes "fourteen". -- 100 becomes "one hundred". -- 120 becomes "one hundred and twenty". -- 1002 becomes "one thousand and two". -- 1323 becomes "one thousand three hundred and twenty-three". diff --git a/exercises/practice/secret-handshake/.docs/instructions.md b/exercises/practice/secret-handshake/.docs/instructions.md index 77136cf0f7..d2120b9bf2 100644 --- a/exercises/practice/secret-handshake/.docs/instructions.md +++ b/exercises/practice/secret-handshake/.docs/instructions.md @@ -43,5 +43,6 @@ jump, double blink ~~~~exercism/note If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. + [intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa ~~~~ diff --git a/exercises/practice/sieve/.docs/instructions.md b/exercises/practice/sieve/.docs/instructions.md index c3c0abeb84..3adf1d551b 100644 --- a/exercises/practice/sieve/.docs/instructions.md +++ b/exercises/practice/sieve/.docs/instructions.md @@ -1,28 +1,28 @@ # Instructions -Use the Sieve of Eratosthenes to find all the primes from 2 up to a given -number. +Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find prime numbers. -The Sieve of Eratosthenes is a simple, ancient algorithm for finding all prime numbers up to any given limit. -It does so by iteratively marking as composite (i.e. not prime) the multiples of each prime, starting with the multiples of 2. -It does not use any division or remainder operation. +A prime number is a number that is only divisible by 1 and itself. +For example, 2, 3, 5, 7, 11, and 13 are prime numbers. -Create your range, starting at two and continuing up to and including the given limit. -(i.e. [2, limit]) +The Sieve of Eratosthenes is an ancient algorithm that works by taking a list of numbers and crossing out all the numbers that aren't prime. -The algorithm consists of repeating the following over and over: +A number that is **not** prime is called a "composite number". -- take the next available unmarked number in your list (it is prime) -- mark all the multiples of that number (they are not prime) +To use the Sieve of Eratosthenes, you first create a list of all the numbers between 2 and your given number. +Then you repeat the following steps: -Repeat until you have processed each number in your range. +1. Find the next unmarked number in your list. This is a prime number. +2. Mark all the multiples of that prime number as composite (not prime). -When the algorithm terminates, all the numbers in the list that have not -been marked are prime. +You keep repeating these steps until you've gone through every number in your list. +At the end, all the unmarked numbers are prime. -[This wikipedia article][eratosthenes] has a useful graphic that explains the algorithm. +~~~~exercism/note +[Wikipedia's Sieve of Eratosthenes article][eratosthenes] has a useful graphic that explains the algorithm. -Notice that this is a very specific algorithm, and the tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes. -A good first test is to check that you do not use division or remainder operations (div, /, mod or % depending on the language). +The tests don't check that you've implemented the algorithm, only that you've come up with the correct list of primes. +A good first test is to check that you do not use division or remainder operations. [eratosthenes]: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes +~~~~ diff --git a/exercises/practice/sieve/.docs/introduction.md b/exercises/practice/sieve/.docs/introduction.md new file mode 100644 index 0000000000..f6c1cf79a9 --- /dev/null +++ b/exercises/practice/sieve/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You bought a big box of random computer parts at a garage sale. +You've started putting the parts together to build custom computers. + +You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare. +You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits. diff --git a/exercises/practice/simple-cipher/.docs/instructions.md b/exercises/practice/simple-cipher/.docs/instructions.md index 9167a1d33a..475af61828 100644 --- a/exercises/practice/simple-cipher/.docs/instructions.md +++ b/exercises/practice/simple-cipher/.docs/instructions.md @@ -9,7 +9,7 @@ If anyone wishes to decipher these, and get at their meaning, he must substitute —Suetonius, Life of Julius Caesar Ciphers are very straight-forward algorithms that allow us to render text less readable while still allowing easy deciphering. -They are vulnerable to many forms of cryptanalysis, but we are lucky that generally our little sisters are not cryptanalysts. +They are vulnerable to many forms of cryptanalysis, but Caesar was lucky that his enemies were not cryptanalysts. The Caesar Cipher was used for some messages from Julius Caesar that were sent afield. Now Caesar knew that the cipher wasn't very good, but he had one ally in that respect: almost nobody could read well. @@ -29,9 +29,9 @@ When "ldpdsdqgdehdu" is put into the decode function it would return the origina ## Step 2 -Shift ciphers are no fun though when your kid sister figures it out. +Shift ciphers quickly cease to be useful when the opposition commander figures them out. +So instead, let's try using a substitution cipher. Try amending the code to allow us to specify a key and use that for the shift distance. -This is called a substitution cipher. Here's an example: diff --git a/exercises/practice/space-age/.docs/instructions.md b/exercises/practice/space-age/.docs/instructions.md index 405a6dfb46..fe938cc09e 100644 --- a/exercises/practice/space-age/.docs/instructions.md +++ b/exercises/practice/space-age/.docs/instructions.md @@ -16,4 +16,10 @@ be able to say that they're 31.69 Earth-years old. If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video]. +Note: The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year). +The Gregorian calendar has, on average, 365.2425 days. +While not entirely accurate, 365.25 is the value used in this exercise. +See [Year on Wikipedia][year] for more ways to measure a year. + [pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs +[year]: https://en.wikipedia.org/wiki/Year#Summary diff --git a/exercises/practice/two-fer/.docs/instructions.md b/exercises/practice/two-fer/.docs/instructions.md index a9bb4a3cd3..37aa75297e 100644 --- a/exercises/practice/two-fer/.docs/instructions.md +++ b/exercises/practice/two-fer/.docs/instructions.md @@ -17,9 +17,9 @@ One for you, one for me. Here are some examples: -|Name |Dialogue -|:-------|:------------------ -|Alice |One for Alice, one for me. -|Bohdan |One for Bohdan, one for me. -| |One for you, one for me. -|Zaphod |One for Zaphod, one for me. +| Name | Dialogue | +| :----- | :-------------------------- | +| Alice | One for Alice, one for me. | +| Bohdan | One for Bohdan, one for me. | +| | One for you, one for me. | +| Zaphod | One for Zaphod, one for me. | From 4a4736d319053baba43827882f943a444d0fbf8f Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 10:25:21 +0200 Subject: [PATCH 2/9] Don't catch load error in hello-world Minitest version 5.0.0 was released in May 2013. That's 10 years ago. We don't need to worry about this anymore. --- exercises/practice/hello-world/hello_world_test.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/exercises/practice/hello-world/hello_world_test.rb b/exercises/practice/hello-world/hello_world_test.rb index 247ee7ff80..6fa626cc45 100644 --- a/exercises/practice/hello-world/hello_world_test.rb +++ b/exercises/practice/hello-world/hello_world_test.rb @@ -1,15 +1,5 @@ -begin - gem 'minitest', '>= 5.0.0' - require 'minitest/autorun' - require_relative 'hello_world' -rescue Gem::LoadError => e - puts "\nMissing Dependency:\n#{e.backtrace.first} #{e.message}" - puts 'Minitest 5.0 gem must be installed for the Ruby track.' -rescue LoadError => e - puts "\nError:\n#{e.backtrace.first} #{e.message}" - puts DATA.read - exit 1 -end +require 'minitest/autorun' +require_relative 'hello_world' class HelloWorldTest < Minitest::Test def test_say_hi From b6fbe2ff1ed33579c6512b302501b43e6dab547f Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 10:29:40 +0200 Subject: [PATCH 3/9] Delete hand-holding in hello-world Exercism has evolved a lot. It has become clear that it is about teaching the language to programmers. It is not about teaching TDD. If we want to teach TDD, we will do it as a feature of the platform, not a hand-crafted course for a single track. --- .../practice/hello-world/GETTING_STARTED.md | 112 ------------------ .../practice/hello-world/hello_world_test.rb | 23 ---- 2 files changed, 135 deletions(-) delete mode 100644 exercises/practice/hello-world/GETTING_STARTED.md diff --git a/exercises/practice/hello-world/GETTING_STARTED.md b/exercises/practice/hello-world/GETTING_STARTED.md deleted file mode 100644 index 86d0dad846..0000000000 --- a/exercises/practice/hello-world/GETTING_STARTED.md +++ /dev/null @@ -1,112 +0,0 @@ -# Getting Started - -These exercises lean on Test-Driven Development (TDD), but they're not an exact match. -If you want a gentle introduction to TDD using minitest in Ruby, see the "Intro to TDD" over at JumpstartLab: - -http://tutorials.jumpstartlab.com/topics/testing/intro-to-tdd.html - -The following steps assume that you are in the same directory as the test -suite. - -You must have the `minitest` gem installed: - - $ gem install minitest - -## Step 1 - -Run the test suite. -It's written using the Minitest framework, and can be run with ruby: - - $ ruby hello_world_test.rb - -Run the test, since the file exists, but does not contain the expected code, it will not pass. - -Depending on what platform you are on, the error will look different, but the way to fix it will be the same. - -On Windows, it may complain about: - - syntax error, unexpected end-of-input, expecting '(' - -On OS X and Linux, the error will be something like: - - - # Running: - - E - - Finished in 0.001328s, 753.0121 runs/s, 0.0000 assertions/s. - - 1) Error: - HelloWorldTest#test_say_hi: - NameError: uninitialized constant HelloWorldTest::HelloWorld - Did you mean? HelloWorldTest - hello_world_test.rb:19:in `test_say_hi' - - 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips - - -Within the first test, we are referencing a constant named `HelloWorld` when we say `HelloWorld.hello`. -When Ruby sees a capitalized name like `HelloWorld`, it looks it up in a big huge list of all the constants it knows about, to see what it points to. -It could point to anything, and often in Ruby we have constants that point to definitions of classes or modules. - -When it looks `HelloWorld` up in its list, it doesn't find anything, so we need to make one. - -### Fixing the Error - -To fix it, open up the `hello_world.rb` file and add the following code: - - class HelloWorld - end - -## Step 2 - -Run the test again. - - 1) Error: - HelloWorldTest#test_no_name: - NoMethodError: undefined method `hello' for HelloWorld:Class - hello_world_test.rb:20:in `test_no_name' - -This time we have a `HelloWorld`, but we're trying tell it to `hello`, and `HelloWorld` doesn't understand that message. - -Open up `hello_world.rb` and add a method definition inside the class: - - class HelloWorld - def self.hello - end - end - -## Step 3 - -Run the test again. - - 1) Failure: - HelloWorldTest#test_no_name [hello_world_test.rb:11]: - When given no name, we should greet the world. - Expected: "Hello, World!" - Actual: nil - -Up until now we've been getting errors, this time we get a failure. - -An error means that Ruby cannot even run properly because of things like missing files or syntax errors, or referring to things that don't exist. - -A failure is different. -A failure is when Ruby is running just fine and the test is expecting one outcome, but getting another. - -The test is expecting the `hello` method to return the string `"Hello, World!"`. -The easiest way to make it pass is to simply stick the string `"Hello, World!"` inside the method definition. - -## Step 6 - -Run the test again. - -If it fails you're going to need to read the error message carefully to figure out what went wrong, and then try again. - -If it passes, then you're ready to move to the next step. - -## Submit - -When everything is passing, you can submit your code with the following command: - - $ exercism submit hello_world.rb - diff --git a/exercises/practice/hello-world/hello_world_test.rb b/exercises/practice/hello-world/hello_world_test.rb index 6fa626cc45..a16c3d0101 100644 --- a/exercises/practice/hello-world/hello_world_test.rb +++ b/exercises/practice/hello-world/hello_world_test.rb @@ -7,26 +7,3 @@ def test_say_hi assert_equal "Hello, World!", HelloWorld.hello end end - -__END__ - -***************************************************** -You got an error, which is exactly as it should be. -This is the first step in the Test-Driven Development -(TDD) process. - -The most important part of the error is - - cannot load such file - -It's looking for a file named hello_world.rb that doesn't -exist yet. - -To fix the error, create an empty file named hello_world.rb -in the same directory as the hello_world_test.rb file. - -Then run the test again. - -For more guidance as you work on this exercise, see -GETTING_STARTED.md. -***************************************************** From 0b3d959050562d66d3e1efd85114aefebbec6a5a Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 19 Apr 2023 16:08:51 +0200 Subject: [PATCH 4/9] Delete old generator This generator does not work with V3. We are replacing it with a less clever, language-agnostic generator. --- README.md | 205 ------------------ bin/generate | 27 --- bin/generators-needed | 14 -- .../acronym/.meta/generator/acronym_case.rb | 22 -- .../.meta/generator/affine_cipher_case.rb | 41 ---- .../.meta/generator/all_your_base_case.rb | 48 ---- .../.meta/generator/allergies_case.rb | 34 --- .../.meta/generator/alphametics_case.rb | 60 ----- .../anagram/.meta/generator/anagram_case.rb | 36 --- .../.meta/generator/armstrong_numbers_case.rb | 12 - .../.meta/generator/atbash_cipher_case.rb | 27 --- .../.meta/generator/beer_song_case.rb | 10 - .../.meta/generator/binary_search_case.rb | 25 --- .../binary/.meta/generator/binary_case.rb | 32 --- .../practice/bob/.meta/generator/bob_case.rb | 11 - .../.meta/generator/book_store_case.rb | 10 - .../bowling/.meta/generator/bowling_case.rb | 47 ---- .../change/.meta/generator/change_case.rb | 26 --- .../clock/.meta/generator/clock_case.rb | 51 ----- .../generator/collatz_conjecture_case.rb | 20 -- .../.meta/generator/complex_numbers_case.rb | 47 ---- .../connect/.meta/generator/connect_case.rb | 21 -- .../.meta/generator/crypto_square_case.rb | 10 - .../.meta/generator/custom_set_case.rb | 70 ------ .../darts/.meta/generator/darts_case.rb | 10 - .../generator/difference_of_squares_case.rb | 15 -- .../dominoes/.meta/generator/dominoes_case.rb | 14 -- .../practice/etl/.meta/generator/etl_case.rb | 24 -- .../.meta/generator/flatten_array_case.rb | 14 -- .../.meta/generator/gigasecond_case.rb | 28 --- .../grains/.meta/generator/grains_case.rb | 22 -- .../grep/.meta/generator/grep_case.rb | 14 -- .../grep/.meta/generator/test_template.erb | 51 ----- .../hamming/.meta/generator/hamming_case.rb | 17 -- .../.meta/generator/hello_world_case.rb | 7 - .../.meta/generator/test_template.erb | 43 ---- .../.meta/generator/high_scores_case.rb | 30 --- .../.meta/generator/isbn_verifier_case.rb | 25 --- .../isogram/.meta/generator/isogram_case.rb | 24 -- .../generator/largest_series_product_case.rb | 17 -- .../leap/.meta/generator/leap_case.rb | 11 - .../leap/.meta/generator/test_template.erb | 19 -- .../luhn/.meta/generator/luhn_case.rb | 7 - .../.meta/generator/matching_brackets_case.rb | 30 --- .../meetup/.meta/generator/meetup_case.rb | 10 - .../.meta/generator/nth_prime_case.rb | 17 -- .../.meta/generator/ocr_numbers_case.rb | 32 --- .../pangram/.meta/generator/pangram_case.rb | 25 --- .../.meta/generator/phone_number_case.rb | 17 -- .../.meta/generator/pig_latin_case.rb | 7 - .../.meta/generator/queen_attack_case.rb | 33 --- .../.meta/generator/raindrops_case.rb | 7 - .../generator/resistor_color_duo_case.rb | 7 - .../generator/resistor_color_trio_case.rb | 21 -- .../.meta/generator/resistor_color_case.rb | 22 -- .../.meta/generator/rna_transcription_case.rb | 7 - .../.meta/generator/roman_numerals_case.rb | 18 -- .../.meta/generator/rotational_cipher_case.rb | 7 - .../generator/run_length_encoding_case.rb | 32 --- .../practice/say/.meta/generator/say_case.rb | 24 -- .../sieve/.meta/generator/sieve_case.rb | 29 --- .../.meta/generator/space_age_case.rb | 10 - .../.meta/generator/test_template.erb | 15 -- .../.meta/generator/sum_of_multiples_case.rb | 10 - .../.meta/generator/tournament_case.rb | 11 - .../.meta/generator/transpose_case.rb | 15 -- .../triangle/.meta/generator/triangle_case.rb | 29 --- .../.meta/generator/two_bucket_case.rb | 17 -- .../two-fer/.meta/generator/two_fer_case.rb | 11 - .../.meta/generator/word_count_case.rb | 11 - .../wordy/.meta/generator/wordy_case.rb | 41 ---- .../zipper/.meta/generator/zipper_case.rb | 105 --------- 72 files changed, 1918 deletions(-) delete mode 100755 bin/generate delete mode 100755 bin/generators-needed delete mode 100644 exercises/practice/acronym/.meta/generator/acronym_case.rb delete mode 100644 exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb delete mode 100644 exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb delete mode 100644 exercises/practice/allergies/.meta/generator/allergies_case.rb delete mode 100644 exercises/practice/alphametics/.meta/generator/alphametics_case.rb delete mode 100644 exercises/practice/anagram/.meta/generator/anagram_case.rb delete mode 100644 exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb delete mode 100644 exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb delete mode 100644 exercises/practice/beer-song/.meta/generator/beer_song_case.rb delete mode 100644 exercises/practice/binary-search/.meta/generator/binary_search_case.rb delete mode 100644 exercises/practice/binary/.meta/generator/binary_case.rb delete mode 100644 exercises/practice/bob/.meta/generator/bob_case.rb delete mode 100644 exercises/practice/book-store/.meta/generator/book_store_case.rb delete mode 100644 exercises/practice/bowling/.meta/generator/bowling_case.rb delete mode 100644 exercises/practice/change/.meta/generator/change_case.rb delete mode 100644 exercises/practice/clock/.meta/generator/clock_case.rb delete mode 100644 exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb delete mode 100644 exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb delete mode 100644 exercises/practice/connect/.meta/generator/connect_case.rb delete mode 100644 exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb delete mode 100644 exercises/practice/custom-set/.meta/generator/custom_set_case.rb delete mode 100644 exercises/practice/darts/.meta/generator/darts_case.rb delete mode 100644 exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb delete mode 100644 exercises/practice/dominoes/.meta/generator/dominoes_case.rb delete mode 100644 exercises/practice/etl/.meta/generator/etl_case.rb delete mode 100644 exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb delete mode 100644 exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb delete mode 100644 exercises/practice/grains/.meta/generator/grains_case.rb delete mode 100644 exercises/practice/grep/.meta/generator/grep_case.rb delete mode 100644 exercises/practice/grep/.meta/generator/test_template.erb delete mode 100644 exercises/practice/hamming/.meta/generator/hamming_case.rb delete mode 100644 exercises/practice/hello-world/.meta/generator/hello_world_case.rb delete mode 100644 exercises/practice/hello-world/.meta/generator/test_template.erb delete mode 100644 exercises/practice/high-scores/.meta/generator/high_scores_case.rb delete mode 100644 exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb delete mode 100644 exercises/practice/isogram/.meta/generator/isogram_case.rb delete mode 100644 exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb delete mode 100644 exercises/practice/leap/.meta/generator/leap_case.rb delete mode 100644 exercises/practice/leap/.meta/generator/test_template.erb delete mode 100644 exercises/practice/luhn/.meta/generator/luhn_case.rb delete mode 100644 exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb delete mode 100644 exercises/practice/meetup/.meta/generator/meetup_case.rb delete mode 100644 exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb delete mode 100644 exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb delete mode 100644 exercises/practice/pangram/.meta/generator/pangram_case.rb delete mode 100644 exercises/practice/phone-number/.meta/generator/phone_number_case.rb delete mode 100644 exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb delete mode 100644 exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb delete mode 100644 exercises/practice/raindrops/.meta/generator/raindrops_case.rb delete mode 100644 exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb delete mode 100644 exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb delete mode 100644 exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb delete mode 100644 exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb delete mode 100644 exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb delete mode 100644 exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb delete mode 100644 exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb delete mode 100644 exercises/practice/say/.meta/generator/say_case.rb delete mode 100644 exercises/practice/sieve/.meta/generator/sieve_case.rb delete mode 100644 exercises/practice/space-age/.meta/generator/space_age_case.rb delete mode 100644 exercises/practice/space-age/.meta/generator/test_template.erb delete mode 100644 exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb delete mode 100644 exercises/practice/tournament/.meta/generator/tournament_case.rb delete mode 100644 exercises/practice/transpose/.meta/generator/transpose_case.rb delete mode 100644 exercises/practice/triangle/.meta/generator/triangle_case.rb delete mode 100644 exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb delete mode 100644 exercises/practice/two-fer/.meta/generator/two_fer_case.rb delete mode 100644 exercises/practice/word-count/.meta/generator/word_count_case.rb delete mode 100644 exercises/practice/wordy/.meta/generator/wordy_case.rb delete mode 100644 exercises/practice/zipper/.meta/generator/zipper_case.rb diff --git a/README.md b/README.md index 4e503c094f..3f1eb170c5 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,6 @@ Exercism Exercises in Ruby - [Anatomy of an Exercise][#anatomy-of-an-exercise] - [Canonical Data][#canonical-data] - [Running the Tests][#running-the-tests] - - [Generated Test Suites][#generated-test-suites] - - [Regenerating a Test Suite][#regenerating-a-test-suite] - - [Changing a Generated Exercise][#changing-a-generated-exercise] - - [Implementing a Generator][#implementing-a-generator] - - [Workload Philosophy][#workload-philosophy] - [Pull Requests][#pull-requests] - [Style Guide][#style-guide] - [READMEs][#readmes] @@ -75,205 +70,6 @@ rake test:hamming -- -p -n="/identical/" Note that flags which have an attached value, like above, must take the form `-flag=value` and if `value` has spaces `-flag="value with spaces"`. -### Generated Test Suites - -Generated test suites use the `bin/generator` cli. - -Before using the cli it is recommended you run `bundle install` from within the ruby directory to install/update any required gems. - -While many of the exercises which have canonical data already have generators, some do not. -To find out whether an exercise has a generator, run - - bin/generate -h - -In addition to a usage message, the `-h` flag lists all exercises with a generator. -If a generator is available for your exercise, you can - -* [Regenerate the test suite][#regenerating-an-exercise] based on updated canonical data -* [Make changes to a generated exercise][#changing-a-generated-exercise] - -If not, you will need to [implement a new generator][#implementing-a-generator]. - -Generated exercises depend on the [the shared metadata][problem-specifications], which must be cloned to the same directory that contains your clone of the ruby repository: - -```text -tree -L 1 ~/code/exercism -├── problem-specifications -└── ruby -``` -To explain a bit more, you must follow this commands step-by-step: - -```sh -mkdir exercism -cd exercism -``` - -Now you need to clone both the above repositories - -```sh -git clone https://github.com/YOUR-USERNAME/YOUR-RUBY-REPOSITORY -git clone https://github.com/YOUR-USERNAME/YOUR-PROBLEM-S-REPOSITORY -``` - -Next, you need to [configure the remote](https://help.github.com/articles/configuring-a-remote-for-a-fork/) and [synchronize](https://help.github.com/articles/syncing-a-fork/) it. - -Make sure you have synced up local `main` branch and upstream `main` branch. -Since this will keep local `main` branch up-to-date with the upstream repository. -Thereby, you will able to get the latest commits. - -#### Regenerating a Test Suite - -From time to time, the [canonical data][canonical data] for an exercise's tests changes, and we need to keep the Ruby version's tests synced up. -Regenerating these tests is a quick and easy way to help maintain the track and get involved! - -If it's your first time cloning/contributing to the repository, you'll need to install any dependencies via `bundle`: - -```sh -bundle install -``` - -Be sure that you're working on the most up-to-date version of the repo. -From the root of your copy of the repository: - -```sh -# Add the exercism repo as upstream if you haven't yet: -git remote add upstream https://github.com/exercism/ruby.git - -# Pull down any changes -git fetch upstream - -# Merge any upstream changes with your `main` branch -git checkout main -git merge upstream/main -``` - -Depending on your git workflow preferences and the state of your local repo, you may want to do some rebasing. -See the [rebasing documentation][rebasing documentation] for more information. - -The generator also depends on the presence of Exercism's `problem-specifications` repository (see the file tree in the section above). -Make sure you've got an *up-to-date* version of the specifications in a `problem-specifications` folder that's in a parallel directory to your local copy of the `ruby` repository. - -To check which problems have possibly been updated, run: - -```sh -bin/generate --all -``` - -This will autogenerate all of the test cases for which generators exist. -Use `git diff` (or your preferred method) to find out which test files have changed. -Some exercises will update because someone updated the description or other exercise metadata. -Others will change because the actual test suite has changed. - -Once everything has been regenerated and updated, you're almost ready to submit your changes via pull request. -Please be sure to only update one exercise per pull request. -Also, please follow the guidelines in the [Pull Requests][#pull-requests] section, being sure to follow the pattern of `: Regenerate Tests`, where slug is the slug of the exercise that your pull request is regenerating. - -#### Changing a Generated Exercise - -Do not edit `/_test.rb`. -Any changes you make will be overwritten when the test suite is regenerated. - -There are two reasons why a test suite might change: - -1. the tests need to change (an incorrect expectation, a missing edge case, - etc) -1. there might be issues with the style or boilerplate - -In the first case, the changes need to be made to the `canonical-data.json` file for the exercise, which lives in the problem-specifications repository. - -```text -https://github.com/exercism/v3/blob/main/problem-specifications/exercises// -├── canonical-data.json -├── description.md -└── metadata.yml -``` - -This change will need to be submitted as a pull request to the problem-specifications repository. -This pull request needs to be merged before you can regenerate the exercise. - -Changes that don't have to do directly with the test inputs and outputs should be made to the exercise's test case generator, discussed in [implementing a new generator][#implementing-a-generator], next. -Then you can regenerate the exercise with `bin/generate `. - -#### Implementing a Generator - -An exercise's test case generator class produces the code that goes inside the minitest `test_` methods. -An exercise's generator lives in `exercises//.meta/generator/_case.rb`. - -The test case generator is a derived class of `ExerciseCase` (in `lib/generator/exercise_case.rb`). -`ExerciseCase` does most of the work of extracting the canonical data and provides you with some accessor methods to access the values you are likely to need to use. - -For example: - -If a section of the `canonical-data.json` file looks like this: - -```json - , { "description": "Bar'ing a name with numbers gives an error" - , "property" : "bar" - , "input" : { - "firstName" : "HAL", - "lastName" : "9000" - } - , "expected" : { "error": "You should never bar a number" } - } -``` - -You will be able to access input['firstName'] by the Ruby methods `first_name` (or `input_first_name`). - -And the `expected["error"]` as: `error` or `expected_error`. - -If there is a property name conflict the "input" version will take precedence, or you can use the `input_` and `expected_` prefixes to disambiguate. - -The test template you need to write looks like this: - -```ruby -require 'generator/exercise_case' - -class Case < Generator::ExerciseCase - - def workload - # Example workload: - "#{assert} Problem.call(#{input.inspect})" - end - -end -``` - -where `` is the CamelCased version of the exercise's slug. -This is important, since the generator script will infer the name of the class from ``. - -This class must provide the methods used by the test template. -A [default template][default template] that most exercises can (and do) use lives in `lib/generator/test_template.erb`. -The base class provides methods for the default template for everything except `#workload`. - -`#workload` generates the code for the body of a test, including the assertion and any setup required. -The base class provides a variety of [assertion][assertion] and [helper][helper] methods. - -Beyond that, you can implement any helper methods that you need as private methods in your derived class. -See below for more information about [the intention of #workload][#workload-philosophy] - -You don't have to do anything other than implement `#workload` to use the default template. - -If you really must add additional logic to the view template, you can use a custom template. -Copy `lib/generator/test_template.erb` to `.meta/generator/test_template.erb` under your exercise directory and customize. -You may need to create `.meta` and/or `.meta/generator`. - -#### Workload philosophy. - -Prioritize educational value over expert comprehension and make sure that -things are clear to people who may not be familiar with Minitest and even Ruby. - -Provide the information the student needs to derive the code to pass the test in a clear and consistent manner. -Illustrate the purpose of the individual elements of the assertion by using meaningful variable names. - -Example output from the `workload` method: - -```ruby -detector = Anagram.new('allergy') -anagrams = detector.match(["gallery", "ballerina", "regally", "clergy", "largely", "leading"]) -expected = ["gallery", "largely", "regally"] -assert_equal expected, anagrams.sort -``` - ## Pull Requests We welcome pull requests that provide fixes to existing test suites (missing tests, interesting edge cases, improved APIs), as well as new problems. @@ -368,4 +164,3 @@ Dress :) [synchronize]: https://help.github.com/articles/syncing-a-fork/ [tests-workflow-badge]: https://github.com/exercism/ruby/actions/workflows/exercise-tests.yml/badge.svg [tests-workflow]: https://github.com/exercism/ruby/actions/workflows/exercise-tests.yml -[#workload-philosophy]: #workload-philosophy diff --git a/bin/generate b/bin/generate deleted file mode 100755 index 82c0044fe2..0000000000 --- a/bin/generate +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env ruby - -require_relative '../lib/helper' -require 'generator' -require 'generator/command_line' - -paths = Generator::Paths.new(track: EXERCISM_RUBY_ROOT, metadata: METADATA_REPOSITORY_PATH) - -generators = Generator::CommandLine.new(paths).parse(ARGV) -exit 1 unless generators - -broken_generator_slugs = [] - -generators.each do |generator| - begin - File.write('.last_generator_run', generator.slug) - generator.call - rescue - raise if generators.size == 1 - broken_generator_slugs << generator.slug - end -end - -unless broken_generator_slugs.empty? - puts "\n\nBroken generators: (Run these individually to see the error raised.)\n\n" - puts broken_generator_slugs -end diff --git a/bin/generators-needed b/bin/generators-needed deleted file mode 100755 index 71a720fc9a..0000000000 --- a/bin/generators-needed +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby - -EXERCISES = File.expand_path('../exercises', __dir__) - -genny_path = ->(slug) { - File.join(EXERCISES, slug, '.meta', 'generator') -} - -genny_path_exists = ->(slug) { Dir.exist?(genny_path[slug]) } - -need_gennies = Dir.children(EXERCISES) - .reject(&genny_path_exists).sort - -puts need_gennies diff --git a/exercises/practice/acronym/.meta/generator/acronym_case.rb b/exercises/practice/acronym/.meta/generator/acronym_case.rb deleted file mode 100644 index e746aeb892..0000000000 --- a/exercises/practice/acronym/.meta/generator/acronym_case.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'generator/exercise_case' - -class AcronymCase < Generator::ExerciseCase - def workload - assert_equal(expected, "Acronym.abbreviate('#{phrase}')") - end - - def to_s(*args) - super unless excluded_tests.include?(test_name) - end - - private - - # We exclude these tests because they currently don't fit the purpose - # we have for Acronym on the Ruby track. - def excluded_tests - %w( - test_apostrophes - test_underscore_emphasis - ) - end -end diff --git a/exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb b/exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb deleted file mode 100644 index a71bbb6c2e..0000000000 --- a/exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'generator/exercise_case' - -class AffineCipherCase < Generator::ExerciseCase - - def workload - return error_workload if error_expected? - case property - when 'encode' then encode_workload - when 'decode' then decode_workload - else raise 'unexpected property encountered' - end - end - - private - - def encode_workload - [ - "cipher = #{new_cipher}\n", - "plaintext = '#{phrase}'\n", - "ciphertext = '#{expected}'\n", - "assert_equal ciphertext, cipher.encode(plaintext)\n" - ].join - end - - def decode_workload - [ - "cipher = #{new_cipher}\n", - "ciphertext = '#{phrase}'\n", - "plaintext = '#{expected}'\n", - "assert_equal plaintext, cipher.decode(ciphertext)\n" - ].join - end - - def error_workload - "assert_raises(ArgumentError) { #{new_cipher} }\n" - end - - def new_cipher - "Affine.new(#{key['a']}, #{key['b']})" - end -end diff --git a/exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb b/exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb deleted file mode 100644 index fcd3c3aba8..0000000000 --- a/exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'generator/exercise_case' - -class AllYourBaseCase < Generator::ExerciseCase - def workload - assignments + assertion - end - - private - - def assignments - [ - "digits = #{input_digits}", - "input_base = #{input_base}", - "output_base = #{output_base}" - ] - end - - def assertion - if error_expected? - [error_assertion] - else - standard_assertion - end - end - - def standard_assertion - [ - "expected = #{expected}", - '', - 'converted = BaseConverter.convert(input_base, digits, output_base)', - '', - "hint = #{hint}", - '', - 'assert_equal expected, converted, hint', - ] - end - - def hint - [ - "\"Input base: #{input_base}, output base #{output_base}. \" +\n", - indent_by(7, %q("Expected #{expected} but got #{converted}.") + "\n") - ].join - end - - def error_assertion - assert_raises(ArgumentError, 'BaseConverter.convert(input_base, digits, output_base)') - end -end diff --git a/exercises/practice/allergies/.meta/generator/allergies_case.rb b/exercises/practice/allergies/.meta/generator/allergies_case.rb deleted file mode 100644 index d8b35f9b8c..0000000000 --- a/exercises/practice/allergies/.meta/generator/allergies_case.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'generator/exercise_case' - -class AllergiesCase < Generator::ExerciseCase - def workload - [ - "allergies = Allergies.new(#{score})\n", - assertions - ].join - end - - def assertions - case property - when 'list' then list_assertion - when 'allergicTo' then substance_assertions - end - end - - def list_assertion - [ - "expected_items = #{expected.sort.inspect}\n", - "assert_equal expected_items, allergies.list.sort\n" - ] - end - - def substance_assertions - expected.map do |test| - "#{assert_or_refute(test['result'])} allergies.allergic_to?('#{test['substance']}')\n" - end - end - - def assert_or_refute(status) - status ? 'assert' : 'refute' - end -end diff --git a/exercises/practice/alphametics/.meta/generator/alphametics_case.rb b/exercises/practice/alphametics/.meta/generator/alphametics_case.rb deleted file mode 100644 index 0d2b94c719..0000000000 --- a/exercises/practice/alphametics/.meta/generator/alphametics_case.rb +++ /dev/null @@ -1,60 +0,0 @@ -require 'generator/exercise_case' - -class AlphameticsCase < Generator::ExerciseCase - def to_s(index) - indent_by(2, runtime_comment) + super(index) - end - - def test_name - super.sub(/(test_puzzle_with_ten_letters_and_199_addends)/, 'do_not_\1') - ## Remove 'do_not_' from the test name to run this test. - end - - def workload - [ - "puzzle = #{format_puzzle}\n", - "expected = #{format_expected}\n", - "assert_equal expected, Alphametics.solve(puzzle)\n" - ].join - end - - private - - def runtime_comment - comment = '' - if slow? - comment += [ - "# The obvious algorithm can take a long time to solve this puzzle,\n", - "# but an optimised solution can solve it fairly quickly.\n", - "# (It's OK to submit your solution without getting this test to pass.)\n", - ].join - end - - if test_name == "do_not_test_puzzle_with_ten_letters_and_199_addends" - comment += "#\n# Remove 'do_not_' from the test name to run this test.\n" - end - - comment - end - - def slow? - expected && expected.size > 7 - end - - def format_puzzle - "'#{puzzle}'" - end - - def format_expected - return "{}" if expected.nil? - - pairs = expected.sort.map { |(key, value)| "'#{key}' => #{value}" } - groups = pairs.each_slice(4).map { |pair| pair.join(', ') } - - indented_groups = indent_by(13, groups.join(",\n")) - # Strip the first indenting spaces. - indented_groups.sub!(/^ {13}/,'') - - "{ #{indented_groups} }" - end -end diff --git a/exercises/practice/anagram/.meta/generator/anagram_case.rb b/exercises/practice/anagram/.meta/generator/anagram_case.rb deleted file mode 100644 index 51d70ba7de..0000000000 --- a/exercises/practice/anagram/.meta/generator/anagram_case.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'generator/exercise_case' - -class AnagramCase < Generator::ExerciseCase - - def workload - [show_comment, detector, anagram, wanted, assert].join - end - - private - - def indent_lines(code, indent = 2) - code.join("\n" + ' '*2*indent) - end - - def show_comment - "# #{comment}\n" if respond_to?(:comment) - end - - def detector - "detector = Anagram.new('#{subject}')\n" - end - - def anagram - "anagrams = detector.match(#{candidates})\n" - end - - def wanted - "expected = #{expected.sort}\n" - end - - def assert - actual = expected.size > 1 ? 'anagrams.sort' : 'anagrams' - "assert_equal expected, #{actual}\n" - end - -end diff --git a/exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb b/exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb deleted file mode 100644 index fbe42de7c9..0000000000 --- a/exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'generator/exercise_case' - -class ArmstrongNumbersCase < Generator::ExerciseCase - - def workload - assert_or_refute(expected, call_armstrong) - end - - def call_armstrong - "ArmstrongNumbers.include?(#{underscore(input['number'])})" - end -end diff --git a/exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb b/exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb deleted file mode 100644 index f40f1c62d7..0000000000 --- a/exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'generator/exercise_case' - -class AtbashCipherCase < Generator::ExerciseCase - def workload - case property - when 'encode' then encode_workload - when 'decode' then decode_workload - else raise 'unexpected property encountered' - end - end - - def encode_workload - [ - "plaintext = '#{phrase}'", - "ciphertext = '#{expected}'", - "assert_equal ciphertext, Atbash.encode(plaintext)" - ] - end - - def decode_workload - [ - "ciphertext = '#{phrase}'", - "plaintext = '#{expected}'", - "assert_equal plaintext, Atbash.decode(ciphertext)" - ] - end -end diff --git a/exercises/practice/beer-song/.meta/generator/beer_song_case.rb b/exercises/practice/beer-song/.meta/generator/beer_song_case.rb deleted file mode 100644 index 75a8383b80..0000000000 --- a/exercises/practice/beer-song/.meta/generator/beer_song_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class BeerSongCase < Generator::ExerciseCase - def workload - [ - "expected = #{indent_heredoc(expected, 'TEXT' )}\n", - "assert_equal expected, BeerSong.recite(#{start_bottles}, #{take_down})\n" - ].join - end -end diff --git a/exercises/practice/binary-search/.meta/generator/binary_search_case.rb b/exercises/practice/binary-search/.meta/generator/binary_search_case.rb deleted file mode 100644 index 2f4aaa3305..0000000000 --- a/exercises/practice/binary-search/.meta/generator/binary_search_case.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'generator/exercise_case' - -class BinarySearchCase < Generator::ExerciseCase - def workload - [binary_search, assertion].join - end - - private - - def binary_search - "binary = BinarySearch.new(#{array})\n" - end - - def assertion - expected.is_a?(Numeric) ? standard_assertion : error_assertion - end - - def standard_assertion - "assert_equal #{expected}, binary.search_for(#{value})" - end - - def error_assertion - assert_equal(nil, "binary.search_for(#{value})") - end -end diff --git a/exercises/practice/binary/.meta/generator/binary_case.rb b/exercises/practice/binary/.meta/generator/binary_case.rb deleted file mode 100644 index 08d8ce506f..0000000000 --- a/exercises/practice/binary/.meta/generator/binary_case.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'generator/exercise_case' - -class BinaryCase < Generator::ExerciseCase - - def workload - error_expected? ? error_assertion : equality_assertion - end - - private - - # "binary" is using a non-standard canonical data format so we need - # to override this method. - def error_expected? - expected.nil? - end - - def error_assertion - [ - "assert_raises(ArgumentError) do\n", - " #{subject_of_test}\n", - "end\n" - ].join - end - - def equality_assertion - "assert_equal #{expected}, #{subject_of_test}\n" - end - - def subject_of_test - "Binary.to_decimal('#{binary}')" - end -end diff --git a/exercises/practice/bob/.meta/generator/bob_case.rb b/exercises/practice/bob/.meta/generator/bob_case.rb deleted file mode 100644 index 09d7cf5421..0000000000 --- a/exercises/practice/bob/.meta/generator/bob_case.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'generator/exercise_case' - -class BobCase < Generator::ExerciseCase - def workload - [ - "remark = #{input["heyBob"].inspect}\n", - "assert_equal #{expected.inspect}, Bob.hey(remark), %q{Bob hears #{input["heyBob"].inspect}, and..}\n" - ].join - end -end - diff --git a/exercises/practice/book-store/.meta/generator/book_store_case.rb b/exercises/practice/book-store/.meta/generator/book_store_case.rb deleted file mode 100644 index 321850eec5..0000000000 --- a/exercises/practice/book-store/.meta/generator/book_store_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class BookStoreCase < Generator::ExerciseCase - def workload - [ - "basket = #{basket}\n", - "assert_equal #{"%.2f" % (expected/100.0)}, BookStore.calculate_price(basket)\n" - ].join - end -end diff --git a/exercises/practice/bowling/.meta/generator/bowling_case.rb b/exercises/practice/bowling/.meta/generator/bowling_case.rb deleted file mode 100644 index a51b40e7be..0000000000 --- a/exercises/practice/bowling/.meta/generator/bowling_case.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'generator/exercise_case' - -class BowlingCase < Generator::ExerciseCase - - def workload - [ - roll_previous, - assert - ].join - end - - private - - def roll_previous - [ - "game = Game.new\n", - "rolls = #{previous_rolls}\n", - "rolls.each { |pins| game.roll(pins) }\n" - ] - end - - def assert - return error_assertion if error_expected? - standard_assertion - end - - def standard_assertion - ["assert_equal #{expected}, game.score\n"] - end - - def error_assertion - body = case property - when 'score' then "game.score\n" - when 'roll' then "game.roll(#{roll})\n" - end - - assert_raises("Game::BowlingError", body) - end - - def assert_raises(error, body) - [ - "assert_raises #{error} do\n", - indent_by(2, body), - "end\n" - ] - end -end diff --git a/exercises/practice/change/.meta/generator/change_case.rb b/exercises/practice/change/.meta/generator/change_case.rb deleted file mode 100644 index 99369d768c..0000000000 --- a/exercises/practice/change/.meta/generator/change_case.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'generator/exercise_case' - -class ChangeCase < Generator::ExerciseCase - def workload - if error_expected? - handle_errors - else - assert_equal(expected, subject_of_test) - end - end - - private - - def handle_errors - case test_name - when 'test_cannot_find_negative_change_values' - assert_raises('Change::NegativeTargetError', subject_of_test) - else - assert_raises('Change::ImpossibleCombinationError', subject_of_test) - end - end - - def subject_of_test - "Change.generate(#{coins}, #{target})" - end -end diff --git a/exercises/practice/clock/.meta/generator/clock_case.rb b/exercises/practice/clock/.meta/generator/clock_case.rb deleted file mode 100644 index fdc6d45543..0000000000 --- a/exercises/practice/clock/.meta/generator/clock_case.rb +++ /dev/null @@ -1,51 +0,0 @@ -require 'generator/exercise_case' - -class ClockCase < Generator::ExerciseCase - - def workload - case property - when 'create' then simple_test - when 'add' then add_to_clock - when 'subtract' then subtract_from_clock - when 'equal' then compare_clocks - else - fail "Encountered unknown property in canonical-data.json" - end - end - - def description - super.gsub('=', 'is_equal_to').gsub(/\(.*\)/,'') - end - - private - - def compare_clocks - [ - "clock1 = Clock.new(hour: #{clock1['hour']}, minute: #{clock1['minute']})\n", - "clock2 = Clock.new(hour: #{clock2['hour']}, minute: #{clock2['minute']})\n", - assert_or_refute(expected, "clock1 == clock2") - ].join - end - - def simple_test - keyword_arguments = %w(hour minute).map { |key| [key, input[key]] } - keyword_arguments.reject! { |_, value| value.zero? } - keyword_arguments.map! { |key, value| "#{key}: #{value}" } - - assert_equal(expected, "Clock.new(#{keyword_arguments.join(', ')}).to_s") - end - - def add_to_clock - [ - "clock1 = Clock.new(hour: #{input['hour']}, minute: #{input['minute']})\n", - assert_equal(expected, "(clock1 + Clock.new(minute: #{input['value']})).to_s") - ].join - end - - def subtract_from_clock - [ - "clock1 = Clock.new(hour: #{input['hour']}, minute: #{input['minute']})\n", - assert_equal(expected, "(clock1 - Clock.new(minute: #{input['value']})).to_s") - ].join - end -end diff --git a/exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb b/exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb deleted file mode 100644 index b641fb0008..0000000000 --- a/exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'generator/exercise_case' - -class CollatzConjectureCase < Generator::ExerciseCase - def workload - error_expected? ? error_assertion : standard_assertion - end - - def error_assertion - assert_raises(ArgumentError, subject_of_test) - end - - def standard_assertion - assert_equal(expected, subject_of_test) - end - - def subject_of_test - "CollatzConjecture.steps(#{underscore(input_number)})" - end -end - diff --git a/exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb b/exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb deleted file mode 100644 index 736ab80be4..0000000000 --- a/exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'generator/exercise_case' - -class ComplexNumbersCase < Generator::ExerciseCase - MATH_SYMBOLS = { - 'e' => 'Math::E', - 'pi' => 'Math::PI', - 'ln(2)' => 'Math.log(2)' - }.freeze - - def description - super.gsub(/'/,'') - end - - def workload - [ - "expected = #{expected_value}\n", - "assert_equal expected, #{subject}#{operation}\n" - ].join - end - - def expected_value - if expected.is_a? Array - complex_number(*expected) - else - expected - end - end - - def subject - complex_number(*(input['z'] || z1)) - end - - def complex_number(real, imaginary) - real, imaginary = [real, imaginary].map { |el| MATH_SYMBOLS[el] || el } - "ComplexNumber.new(#{real}, #{imaginary})" - end - - def operation - case property - when 'add' then " + #{complex_number(*z2)}" - when 'sub' then " - #{complex_number(*z2)}" - when 'mul' then " * #{complex_number(*z2)}" - when 'div' then " / #{complex_number(*z2)}" - else ".#{property}" - end - end -end diff --git a/exercises/practice/connect/.meta/generator/connect_case.rb b/exercises/practice/connect/.meta/generator/connect_case.rb deleted file mode 100644 index 080bdf4a54..0000000000 --- a/exercises/practice/connect/.meta/generator/connect_case.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'generator/exercise_case' - -class ConnectCase < Generator::ExerciseCase - - def workload - [ - 'board = [', - indent_by(2,board.map(&method(:single_quote)).join(",\n")), - "].map {|row| row.gsub(/^ */, '')}", - 'game = Board.new(board)', - "assert_equal #{single_quote(expected)}, game.winner, #{single_quote(description)}" - ].map {|line| line + "\n" }.join - end - - private - - def single_quote(string) - string.inspect.tr('"', "'") - end - -end diff --git a/exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb b/exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb deleted file mode 100644 index e4bbb71a33..0000000000 --- a/exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class CryptoSquareCase < Generator::ExerciseCase - def workload - [ - "plaintext = '#{plaintext}'\n", - assert_equal(expected, "Crypto.new(plaintext).ciphertext") - ].join - end -end diff --git a/exercises/practice/custom-set/.meta/generator/custom_set_case.rb b/exercises/practice/custom-set/.meta/generator/custom_set_case.rb deleted file mode 100644 index c58bf90fc8..0000000000 --- a/exercises/practice/custom-set/.meta/generator/custom_set_case.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'generator/exercise_case' - -class CustomSetCase < Generator::ExerciseCase - - def workload - send(property).gsub(/^ */, '') + "\n" - end - - private - - def assert_or_refute - expected ? "assert" : "refute" - end - - def union - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - expected = CustomSet.new #{expected} - #{assert_or_refute}_equal expected, set1.union(set2)" - end - - def difference - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - expected = CustomSet.new #{expected} - #{assert_or_refute}_equal expected, set1.difference(set2)" - end - - def intersection - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - expected = CustomSet.new #{expected} - #{assert_or_refute}_equal expected, set2.intersection(set1)" - end - - def add - "set = CustomSet.new #{set} - expected = CustomSet.new #{expected} - #{assert_or_refute}_equal expected, set.add(#{element})" - end - - def equal - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - #{assert_or_refute}_equal set1, set2" - end - - def disjoint - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - #{assert_or_refute} set1.disjoint? set2" - end - - def subset - "set1 = CustomSet.new #{set1} - set2 = CustomSet.new #{set2} - #{assert_or_refute} set1.subset? set2" - end - - def empty - "set = CustomSet.new #{set} - #{assert_or_refute}_empty set" - end - - def contains - "set = CustomSet.new #{set} - element = #{element} - #{assert_or_refute} set.member? element" - end -end diff --git a/exercises/practice/darts/.meta/generator/darts_case.rb b/exercises/practice/darts/.meta/generator/darts_case.rb deleted file mode 100644 index f7cec1aaa4..0000000000 --- a/exercises/practice/darts/.meta/generator/darts_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class DartsCase < Generator::ExerciseCase - def workload - [ - "darts = Darts.new(#{input["x"]}, #{input["y"]})\n", - "assert_equal(#{expected.inspect}, darts.score)\n" - ].join - end -end diff --git a/exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb b/exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb deleted file mode 100644 index 8df484d745..0000000000 --- a/exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'generator/exercise_case' - -class DifferenceOfSquaresCase < Generator::ExerciseCase - - def workload - "assert_equal #{underscore(expected)}, Squares.new(#{number}).#{action}\n" - end - - def action - case property - when 'differenceOfSquares' then 'difference' - else snake_case(property) - end - end -end diff --git a/exercises/practice/dominoes/.meta/generator/dominoes_case.rb b/exercises/practice/dominoes/.meta/generator/dominoes_case.rb deleted file mode 100644 index 48d075fa20..0000000000 --- a/exercises/practice/dominoes/.meta/generator/dominoes_case.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'generator/exercise_case' - -class DominoesCase < Generator::ExerciseCase - def description - super.gsub("can't", 'can not') - end - - def workload - [ - "dominoes = #{dominoes}\n", - assert_or_refute(expected, "Dominoes.chain?(dominoes)") - ].join - end -end diff --git a/exercises/practice/etl/.meta/generator/etl_case.rb b/exercises/practice/etl/.meta/generator/etl_case.rb deleted file mode 100644 index 9b00dc26af..0000000000 --- a/exercises/practice/etl/.meta/generator/etl_case.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'generator/exercise_case' - -class EtlCase < Generator::ExerciseCase - def workload - [ - "old = {\n#{indent_by(2, format(input))}\n}\n", - "expected = {\n#{indent_by(2,format(expected))}\n}\n", - "assert_equal expected, ETL.transform(old)\n" - ].join - end - - private - - def format(obj) - case obj - when Hash - obj.reduce([]) {|lines, (k, v)| lines << "#{format(k)} => #{format(v)}" }.join(",\n") - when String - obj =~ /\d+/ ? obj.to_i : "'#{obj}'" - else - obj - end - end -end diff --git a/exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb b/exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb deleted file mode 100644 index dc8e4b8a12..0000000000 --- a/exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'generator/exercise_case' - -class FlattenArrayCase < Generator::ExerciseCase - def description - super.gsub(/null/,'nil') - end - - def workload - [ - "flat_array = FlattenArray.flatten(#{input_array})", - "assert_equal #{expected}, flat_array" - ] - end -end diff --git a/exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb b/exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb deleted file mode 100644 index 9e4a4dbc27..0000000000 --- a/exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'generator/exercise_case' -require 'time' - -class GigasecondCase < Generator::ExerciseCase - def workload - %Q(assert_equal #{want}, Gigasecond.from(#{got})) - end - - private - - def got - "Time.utc(#{start_values.join(', ')})" - end - - def want - "Time.utc(#{stop_values.join(', ')})" - end - - def start_values - ts = Time.parse(birthdate) - [ts.year, ts.month, ts.day, ts.hour, ts.min, ts.sec] - end - - def stop_values - ts = Time.parse(expected) - [ts.year, ts.month, ts.day, ts.hour, ts.min, ts.sec] - end -end diff --git a/exercises/practice/grains/.meta/generator/grains_case.rb b/exercises/practice/grains/.meta/generator/grains_case.rb deleted file mode 100644 index 1639f12f98..0000000000 --- a/exercises/practice/grains/.meta/generator/grains_case.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'generator/exercise_case' - -class GrainsCase < Generator::ExerciseCase - def workload - send("#{property}_workload") - end - - private - - def square_workload - subject_of_test = "Grains.square(#{square})" - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - "assert_equal #{underscore(expected)}, #{subject_of_test}" - end - end - - def total_workload - "assert_equal #{underscore(expected)}, Grains.total" - end -end diff --git a/exercises/practice/grep/.meta/generator/grep_case.rb b/exercises/practice/grep/.meta/generator/grep_case.rb deleted file mode 100644 index d37b9a4c34..0000000000 --- a/exercises/practice/grep/.meta/generator/grep_case.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'generator/exercise_case' - -class GrepCase < Generator::ExerciseCase - def workload - [ - "pattern = #{pattern.inspect}", - "flags = #{flags}", - "files = #{files}", - "expected = #{indent_heredoc(expected, 'EXPECTED', 2, '.rstrip')}", - "", - "assert_equal expected, Grep.grep(pattern, flags, files)" - ] - end -end diff --git a/exercises/practice/grep/.meta/generator/test_template.erb b/exercises/practice/grep/.meta/generator/test_template.erb deleted file mode 100644 index bda78ca82f..0000000000 --- a/exercises/practice/grep/.meta/generator/test_template.erb +++ /dev/null @@ -1,51 +0,0 @@ -require 'minitest/autorun' -require_relative '<%= exercise_name %>' - -# Common test data version: <%= canonical_data_version %> <%= abbreviated_commit_hash %> -class <%= exercise_test_classname %> < Minitest::Test - def setup - IO.write 'iliad.txt', <<~END - Achilles sing, O Goddess! Peleus' son; - His wrath pernicious, who ten thousand woes - Caused to Achaia's host, sent many a soul - Illustrious into Ades premature, - And Heroes gave (so stood the will of Jove) - To dogs and to all ravening fowls a prey, - When fierce dispute had separated once - The noble Chief Achilles from the son - Of Atreus, Agamemnon, King of men. - END - - IO.write 'midsummer-night.txt', <<~END - I do entreat your grace to pardon me. - I know not by what power I am made bold, - Nor how it may concern my modesty, - In such a presence here to plead my thoughts; - But I beseech your grace that I may know - The worst that may befall me in this case, - If I refuse to wed Demetrius. - END - - IO.write 'paradise-lost.txt', <<~END - Of Mans First Disobedience, and the Fruit - Of that Forbidden Tree, whose mortal tast - Brought Death into the World, and all our woe, - With loss of Eden, till one greater Man - Restore us, and regain the blissful Seat, - Sing Heav'nly Muse, that on the secret top - Of Oreb, or of Sinai, didst inspire - That Shepherd, who first taught the chosen Seed - END - end - - def teardown - File.delete('iliad.txt') - File.delete('midsummer-night.txt') - File.delete('paradise-lost.txt') - end - -<%= - test_cases.map.with_index do |test_case, index| - test_case.to_s(index.zero?) - end.join("\n") -%>end diff --git a/exercises/practice/hamming/.meta/generator/hamming_case.rb b/exercises/practice/hamming/.meta/generator/hamming_case.rb deleted file mode 100644 index 2e459d12c5..0000000000 --- a/exercises/practice/hamming/.meta/generator/hamming_case.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'generator/exercise_case' - -class HammingCase < Generator::ExerciseCase - def workload - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - private - - def subject_of_test - "Hamming.compute('#{strand1}', '#{strand2}')" - end -end diff --git a/exercises/practice/hello-world/.meta/generator/hello_world_case.rb b/exercises/practice/hello-world/.meta/generator/hello_world_case.rb deleted file mode 100644 index 4bbf7934a6..0000000000 --- a/exercises/practice/hello-world/.meta/generator/hello_world_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class HelloWorldCase < Generator::ExerciseCase - def workload - assert_equal(expected, "HelloWorld.hello") - end -end diff --git a/exercises/practice/hello-world/.meta/generator/test_template.erb b/exercises/practice/hello-world/.meta/generator/test_template.erb deleted file mode 100644 index 6e32919c88..0000000000 --- a/exercises/practice/hello-world/.meta/generator/test_template.erb +++ /dev/null @@ -1,43 +0,0 @@ -begin - gem 'minitest', '>= 5.0.0' - require 'minitest/autorun' - require_relative 'hello_world' -rescue Gem::LoadError => e - puts "\nMissing Dependency:\n#{e.backtrace.first} #{e.message}" - puts 'Minitest 5.0 gem must be installed for the Ruby track.' -rescue LoadError => e - puts "\nError:\n#{e.backtrace.first} #{e.message}" - puts DATA.read - exit 1 -end - -# Common test data version: <%= canonical_data_version %> <%= abbreviated_commit_hash %> -class HelloWorldTest < Minitest::Test -<%= - test_cases.map.with_index do |test_case, index| - test_case.to_s(index.zero?) - end.join("\n") -%>end - -__END__ - -***************************************************** -You got an error, which is exactly as it should be. -This is the first step in the Test-Driven Development -(TDD) process. - -The most important part of the error is - - cannot load such file - -It's looking for a file named hello_world.rb that doesn't -exist yet. - -To fix the error, create an empty file named hello_world.rb -in the same directory as the hello_world_test.rb file. - -Then run the test again. - -For more guidance as you work on this exercise, see -GETTING_STARTED.md. -***************************************************** diff --git a/exercises/practice/high-scores/.meta/generator/high_scores_case.rb b/exercises/practice/high-scores/.meta/generator/high_scores_case.rb deleted file mode 100644 index 4e03367522..0000000000 --- a/exercises/practice/high-scores/.meta/generator/high_scores_case.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'generator/exercise_case' - -class HighScoresCase < Generator::ExerciseCase - def workload - [ - "scores = #{scores}", - assertions - ].flatten - end - - private - - def assertions - case property - when 'latestIsPersonalBest' then boolean_assertion - else regular_assertion - end - end - - def regular_assertion - [ - "expected = #{expected.inspect}", - "assert_equal expected, HighScores.new(scores).#{snake_case(property)}" - ] - end - - def boolean_assertion - assert_or_refute(expected, "HighScores.new(scores).#{snake_case(property)}?") - end -end diff --git a/exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb b/exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb deleted file mode 100644 index 63a8ec2813..0000000000 --- a/exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'generator/exercise_case' - -class IsbnVerifierCase < Generator::ExerciseCase - - def workload - [ - "string = #{isbn.inspect}", - assert_or_refute(expected, "IsbnVerifier.valid?(string), #{failure_message}") - ] - end - - private - - def failure_message - %Q("Expected #{expected}, #{reason}") - end - - def reason - "'\#{string}' #{is_or_not} a valid isbn" - end - - def is_or_not - expected ? 'is' : 'is not' - end -end diff --git a/exercises/practice/isogram/.meta/generator/isogram_case.rb b/exercises/practice/isogram/.meta/generator/isogram_case.rb deleted file mode 100644 index 4bd4d4ffe9..0000000000 --- a/exercises/practice/isogram/.meta/generator/isogram_case.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'generator/exercise_case' - -class IsogramCase < Generator::ExerciseCase - def workload - [ - "input = #{phrase.inspect}", - assert_or_refute(expected, "Isogram.isogram?(input), #{failure_message}") - ] - end - - private - - def failure_message - %Q("Expected #{expected}, #{reason}") - end - - def reason - "'\#{input}' #{is_or_not} an isogram" - end - - def is_or_not - expected ? 'is' : 'is not' - end -end diff --git a/exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb b/exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb deleted file mode 100644 index 8cf3bf7ec7..0000000000 --- a/exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'generator/exercise_case' - -class LargestSeriesProductCase < Generator::ExerciseCase - def workload - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - private - - def subject_of_test - "Series.new('#{digits}').largest_product(#{span})" - end -end diff --git a/exercises/practice/leap/.meta/generator/leap_case.rb b/exercises/practice/leap/.meta/generator/leap_case.rb deleted file mode 100644 index 8b7770f696..0000000000 --- a/exercises/practice/leap/.meta/generator/leap_case.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'generator/exercise_case' - -class LeapCase < Generator::ExerciseCase - def workload - assert_or_refute(expected, "Year.leap?(#{input_year.inspect}), #{failure_message.inspect}") - end - - def failure_message - "Expected '#{expected}', #{input_year} is #{expected ? '' : 'not '}a leap year." - end -end diff --git a/exercises/practice/leap/.meta/generator/test_template.erb b/exercises/practice/leap/.meta/generator/test_template.erb deleted file mode 100644 index 1fc27ee895..0000000000 --- a/exercises/practice/leap/.meta/generator/test_template.erb +++ /dev/null @@ -1,19 +0,0 @@ -require 'minitest/autorun' -require_relative 'leap' - -# Common test data version: <%= canonical_data_version %> <%= abbreviated_commit_hash %> -class Date - def leap? - raise RuntimeError, "Implement this yourself instead of using Ruby's implementation." - end - - alias gregorian_leap? leap? - alias julian_leap? leap? -end - -class YearTest < Minitest::Test -<%= - test_cases.map.with_index do |test_case, index| - test_case.to_s(index.zero?) - end.join("\n") -%>end diff --git a/exercises/practice/luhn/.meta/generator/luhn_case.rb b/exercises/practice/luhn/.meta/generator/luhn_case.rb deleted file mode 100644 index 977fb5def3..0000000000 --- a/exercises/practice/luhn/.meta/generator/luhn_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class LuhnCase < Generator::ExerciseCase - def workload - assert_or_refute(expected, "Luhn.valid?(#{input_value.inspect})") - end -end diff --git a/exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb b/exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb deleted file mode 100644 index 4e27b250db..0000000000 --- a/exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'generator/exercise_case' - -class MatchingBracketsCase < Generator::ExerciseCase - - def workload - long_input? ? split_test : simple_test - end - - private - - def long_input? - value.length > 80 - end - - def simple_test - assert_or_refute(expected, "Brackets.paired?('#{value}')") - end - - def split_test - [ - "string = '#{split_input[0]}' +\n", - " '#{split_input[1]}'\n", - assert_or_refute(expected, "Brackets.paired?(string)") - ].join - end - - def split_input - value.scan(/.{1,#{value.length / 2}}/) - end -end diff --git a/exercises/practice/meetup/.meta/generator/meetup_case.rb b/exercises/practice/meetup/.meta/generator/meetup_case.rb deleted file mode 100644 index be7f8687be..0000000000 --- a/exercises/practice/meetup/.meta/generator/meetup_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class MeetupCase < Generator::ExerciseCase - def workload - [ - "meetup = Meetup.new(#{month}, #{year}).day(:#{dayofweek.downcase}, :#{week})", - "assert_equal Date.parse(#{expected.inspect}), meetup" - ] - end -end diff --git a/exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb b/exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb deleted file mode 100644 index 557f9f4342..0000000000 --- a/exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'generator/exercise_case' - -class NthPrimeCase < Generator::ExerciseCase - def workload - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - private - - def subject_of_test - "Prime.nth(#{number})" - end -end diff --git a/exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb b/exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb deleted file mode 100644 index efc8cb0d97..0000000000 --- a/exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'generator/exercise_case' - -class OcrNumbersCase < Generator::ExerciseCase - def workload - [ - formatted_rows, - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - ] - end - - def description - super.gsub(/\?/,'question_mark') - end - - private - - def formatted_rows - [ - "input = [", - indent_by(9, rows.map(&:inspect).join(",\n")).sub(/^ */,''), - %Q{].join("\\n")\n} - ].join - end - - def subject_of_test - "OcrNumbers.convert(input)" - end -end diff --git a/exercises/practice/pangram/.meta/generator/pangram_case.rb b/exercises/practice/pangram/.meta/generator/pangram_case.rb deleted file mode 100644 index 97131e9a26..0000000000 --- a/exercises/practice/pangram/.meta/generator/pangram_case.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'generator/exercise_case' - -class PangramCase < Generator::ExerciseCase - def workload - [ - "sentence = '#{sentence}'", - "result = Pangram.pangram?(sentence)", - assert_or_refute(expected, "result, \"#{message}\"") - ] - end - - def message - "Expected #{expected}, got: \#{result.inspect}. \#{sentence.inspect} #{is_or_isnt} a pangram" - end - - def is_or_isnt - expected ? 'IS' : 'is NOT' - end - - def description - # Reword confusing test case name - # "e.g. 'h'" converts to "eg_h" - super.gsub("another missing character, e.g. 'h'","missing character h") - end -end diff --git a/exercises/practice/phone-number/.meta/generator/phone_number_case.rb b/exercises/practice/phone-number/.meta/generator/phone_number_case.rb deleted file mode 100644 index 5edbe99a2d..0000000000 --- a/exercises/practice/phone-number/.meta/generator/phone_number_case.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'generator/exercise_case' - -class PhoneNumberCase < Generator::ExerciseCase - def workload - if error_expected? - assert_equal(nil, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - private - - def subject_of_test - "PhoneNumber.clean(#{phrase.inspect})" - end -end diff --git a/exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb b/exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb deleted file mode 100644 index 7485891e76..0000000000 --- a/exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class PigLatinCase < Generator::ExerciseCase - def workload - assert_equal(expected, "PigLatin.translate(#{phrase.inspect})") - end -end diff --git a/exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb b/exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb deleted file mode 100644 index 30d1e9db22..0000000000 --- a/exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'generator/exercise_case' - -class QueenAttackCase < Generator::ExerciseCase - - def workload - send("#{snake_case(property)}_assertion") - end - - private - - def can_attack_assertion - [ - "queens = Queens.new(white: #{parse_position white_queen}, black: #{parse_position black_queen})", - assert_or_refute(expected, "queens.attack?") - ] - end - - def create_assertion - if error_expected? - assert_raises(ArgumentError, new_queen) - else - assert_or_refute(expected, new_queen) - end - end - - def parse_position(queen) - [queen['position']['row'], queen['position']['column']] - end - - def new_queen - "Queens.new(white: #{parse_position queen})" - end -end diff --git a/exercises/practice/raindrops/.meta/generator/raindrops_case.rb b/exercises/practice/raindrops/.meta/generator/raindrops_case.rb deleted file mode 100644 index 6fe17e7ad9..0000000000 --- a/exercises/practice/raindrops/.meta/generator/raindrops_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class RaindropsCase < Generator::ExerciseCase - def workload - assert_equal(expected, "Raindrops.convert(#{number})") - end -end diff --git a/exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb b/exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb deleted file mode 100644 index dc471716f8..0000000000 --- a/exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class ResistorColorDuoCase < Generator::ExerciseCase - def workload - assert_equal(expected, "ResistorColorDuo.value(#{colors})") - end -end diff --git a/exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb b/exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb deleted file mode 100644 index f2a8b12152..0000000000 --- a/exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'generator/exercise_case' - -class ResistorColorTrioCase < Generator::ExerciseCase - def workload - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - private - - def subject_of_test - "ResistorColorTrio.new(#{colors}).label" - end - - def expected - "Resistor value: #{super['value']} #{super['unit']}" - end -end diff --git a/exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb b/exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb deleted file mode 100644 index b82ed82775..0000000000 --- a/exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'generator/exercise_case' - -class ResistorColorCase < Generator::ExerciseCase - def workload - send("#{snake_case(property)}_workload") - end - - private - - def color_code_workload - assert_equal(expected, "ResistorColor.color_code(#{color.inspect})") - end - - # Instead of specifying a `colors` method like the canonical data suggests - # we expect the student to define a COLORS constant. - def colors_workload - [ - "expected = #{expected}", - "assert_equal expected, ResistorColor::COLORS" - ] - end -end diff --git a/exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb b/exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb deleted file mode 100644 index 83d973e54f..0000000000 --- a/exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class RnaTranscriptionCase < Generator::ExerciseCase - def workload - "assert_equal '#{expected}', Complement.of_dna('#{dna}')" - end -end diff --git a/exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb b/exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb deleted file mode 100644 index 5ed7fdf6b0..0000000000 --- a/exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'generator/exercise_case' - -class RomanNumeralsCase < Generator::ExerciseCase - def name - 'test_%s' % number.to_s - end - - def workload - "assert_equal '#{expected}', #{actual}" - end - - private - - def actual - '%s.to_roman' % number.to_s - end - -end diff --git a/exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb b/exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb deleted file mode 100644 index c51fe9a942..0000000000 --- a/exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'generator/exercise_case' - -class RotationalCipherCase < Generator::ExerciseCase - def workload - assert_equal expected, "RotationalCipher.rotate(#{text.inspect}, #{shift_key})" - end -end diff --git a/exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb b/exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb deleted file mode 100644 index dfb0cc814c..0000000000 --- a/exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'generator/exercise_case' - -class RunLengthEncodingCase < Generator::ExerciseCase - def workload - send("#{property}_assertion") - end - - def test_name - super.sub('test_',"test_#{property}_") - end - - private - - def standard_assertion - [ - "input = '#{string}'", - "output = '#{expected}'", - "assert_equal output, RunLengthEncoding.#{property}(input)" - ] - end - - alias_method :encode_assertion, :standard_assertion - alias_method :decode_assertion, :standard_assertion - - def consistency_assertion - [ - "input = '#{string}'", - "encoded = RunLengthEncoding.encode(input)", - "assert_equal input, RunLengthEncoding.decode(encoded)" - ] - end -end diff --git a/exercises/practice/say/.meta/generator/say_case.rb b/exercises/practice/say/.meta/generator/say_case.rb deleted file mode 100644 index 27737e5003..0000000000 --- a/exercises/practice/say/.meta/generator/say_case.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'generator/exercise_case' - -class SayCase < Generator::ExerciseCase - def workload - [ - "number = #{underscore(number)}", - assertion, - ] - end - - private - - def assertion - if error_expected? - assert_raises(ArgumentError, subject_of_test) - else - assert_equal(expected, subject_of_test) - end - end - - def subject_of_test - 'Say.new(number).in_english' - end -end diff --git a/exercises/practice/sieve/.meta/generator/sieve_case.rb b/exercises/practice/sieve/.meta/generator/sieve_case.rb deleted file mode 100644 index 97299c66d2..0000000000 --- a/exercises/practice/sieve/.meta/generator/sieve_case.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'generator/exercise_case' - -class SieveCase < Generator::ExerciseCase - ARRAY_ELEMENTS_PER_ROW = 17.freeze - - def workload - [ - formatted_expected, - "assert_equal expected, Sieve.new(#{limit}).primes" - ] - end - - private - - def formatted_expected - return "expected = #{expected}" unless needs_indentation? - - array_rows = expected.each_slice(ARRAY_ELEMENTS_PER_ROW).map { |elements| elements.join(', ') } - [ - "expected = [\n", - indent_by(2,array_rows.join(",\n")) + "\n", - "]\n" - ].join - end - - def needs_indentation? - expected.size > ARRAY_ELEMENTS_PER_ROW - end -end diff --git a/exercises/practice/space-age/.meta/generator/space_age_case.rb b/exercises/practice/space-age/.meta/generator/space_age_case.rb deleted file mode 100644 index a88bc1e9bf..0000000000 --- a/exercises/practice/space-age/.meta/generator/space_age_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class SpaceAgeCase < Generator::ExerciseCase - def workload - [ - "age = SpaceAge.new(#{underscore(seconds)})\n", - "assert_in_delta #{expected}, age.on_#{planet.downcase}, DELTA\n" - ].join - end -end diff --git a/exercises/practice/space-age/.meta/generator/test_template.erb b/exercises/practice/space-age/.meta/generator/test_template.erb deleted file mode 100644 index e476f80b7c..0000000000 --- a/exercises/practice/space-age/.meta/generator/test_template.erb +++ /dev/null @@ -1,15 +0,0 @@ -require 'minitest/autorun' -require_relative '<%= exercise_name %>' - -# Common test data version: <%= canonical_data_version %> <%= abbreviated_commit_hash %> -class <%= exercise_test_classname %> < Minitest::Test - # assert_in_delta will pass if the difference - # between the values being compared is less - # than the allowed delta - DELTA = 0.01 - -<%= - test_cases.map.with_index do |test_case, index| - test_case.to_s(index.zero?) - end.join("\n") -%>end diff --git a/exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb b/exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb deleted file mode 100644 index 5421b0979e..0000000000 --- a/exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'generator/exercise_case' - -class SumOfMultiplesCase < Generator::ExerciseCase - def workload - [ - "sum_of_multiples = SumOfMultiples.new(#{factors.join(', ')})\n", - "assert_equal #{underscore(expected)}, sum_of_multiples.to(#{underscore(limit)})\n" - ].join - end -end diff --git a/exercises/practice/tournament/.meta/generator/tournament_case.rb b/exercises/practice/tournament/.meta/generator/tournament_case.rb deleted file mode 100644 index df2d74e8b8..0000000000 --- a/exercises/practice/tournament/.meta/generator/tournament_case.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'generator/exercise_case' - -class TournamentCase < Generator::ExerciseCase - def workload - [ - "input = #{indent_heredoc(rows, 'INPUT')}\n\n", - "expected = #{indent_heredoc(expected, 'TALLY')}\n\n", - "assert_equal expected, Tournament.tally(input)" - ] - end -end diff --git a/exercises/practice/transpose/.meta/generator/transpose_case.rb b/exercises/practice/transpose/.meta/generator/transpose_case.rb deleted file mode 100644 index 1efa6d1eab..0000000000 --- a/exercises/practice/transpose/.meta/generator/transpose_case.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'generator/exercise_case' - -class TransposeCase < Generator::ExerciseCase - - def workload - [ - "input = #{to_string(lines)}", - "", - "expected = #{to_string(expected)}", - "", - "assert_equal expected, Transpose.transpose(input)" - ] - end - -end diff --git a/exercises/practice/triangle/.meta/generator/triangle_case.rb b/exercises/practice/triangle/.meta/generator/triangle_case.rb deleted file mode 100644 index d19a085ebd..0000000000 --- a/exercises/practice/triangle/.meta/generator/triangle_case.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'generator/exercise_case' - -class TriangleCase < Generator::ExerciseCase - def description - initial = super.downcase - replaced = initial.gsub(/(true|false)/, "triangle is #{type}") - - return replaced unless initial == replaced # no change - return replaced if replaced.include?(property) - return "#{property} triangle " + replaced - end - - def workload - [ - "triangle = Triangle.new(#{sides})", - assert_or_refute(expected, "triangle.#{property}?, #{failure_message}") - ] - end - - private - - def failure_message - %Q("Expected '#{expected}', triangle #{sides} is #{type}.") - end - - def type - (expected ? '' : 'not ') + property - end -end diff --git a/exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb b/exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb deleted file mode 100644 index b80fb85131..0000000000 --- a/exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'generator/exercise_case' - -class TwoBucketCase < Generator::ExerciseCase - def description - "bucket one size #{bucket_one} bucket two size #{bucket_two} "+ - "goal #{goal} start with bucket #{start_bucket}" - end - - def workload - [ - "subject = TwoBucket.new(#{bucket_one}, #{bucket_two}, #{goal}, '#{start_bucket}')", - "assert_equal #{moves}, subject.moves", - "assert_equal '#{goal_bucket}', subject.goal_bucket", - "assert_equal #{other_bucket}, subject.other_bucket", - ] - end -end diff --git a/exercises/practice/two-fer/.meta/generator/two_fer_case.rb b/exercises/practice/two-fer/.meta/generator/two_fer_case.rb deleted file mode 100644 index cf7d422e6e..0000000000 --- a/exercises/practice/two-fer/.meta/generator/two_fer_case.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'generator/exercise_case' - -class TwoFerCase < Generator::ExerciseCase - def workload - if name.nil? - assert_equal(expected, "TwoFer.two_fer") - else - assert_equal(expected, "TwoFer.two_fer(#{name.inspect})") - end - end -end diff --git a/exercises/practice/word-count/.meta/generator/word_count_case.rb b/exercises/practice/word-count/.meta/generator/word_count_case.rb deleted file mode 100644 index 1d65ef0508..0000000000 --- a/exercises/practice/word-count/.meta/generator/word_count_case.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'generator/exercise_case' - -class WordCountCase < Generator::ExerciseCase - def workload - [ - "phrase = Phrase.new(#{sentence.inspect})", - "counts = #{expected}", - "assert_equal counts, phrase.word_count" - ] - end -end diff --git a/exercises/practice/wordy/.meta/generator/wordy_case.rb b/exercises/practice/wordy/.meta/generator/wordy_case.rb deleted file mode 100644 index 17d8c8833b..0000000000 --- a/exercises/practice/wordy/.meta/generator/wordy_case.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'generator/exercise_case' - -class WordyCase < Generator::ExerciseCase - - def workload - assertion - end - - private - - def assertion - return error_assertion if error_expected? - return message_assertion if message - - [ - "problem = WordProblem.new(#{question.inspect})", - "assert_equal(#{expected}, problem.answer)" - ] - end - - def error_assertion - [ - "problem = WordProblem.new(#{question.inspect})", - assert_raises(ArgumentError, 'problem.answer') - ] - end - - def message_assertion - [ - "problem = WordProblem.new(#{question.inspect})", - "message = \"#{message % '#{problem.answer}'}\"", - "assert_equal(#{expected}, problem.answer, message)", - ].join("\n") - end - - def message - if question == 'What is -3 plus 7 multiplied by -2?' - 'You should ignore order of precedence. -3 + 7 * -2 = -8, not %s' - end - end -end diff --git a/exercises/practice/zipper/.meta/generator/zipper_case.rb b/exercises/practice/zipper/.meta/generator/zipper_case.rb deleted file mode 100644 index 84d556a0fc..0000000000 --- a/exercises/practice/zipper/.meta/generator/zipper_case.rb +++ /dev/null @@ -1,105 +0,0 @@ -require 'generator/exercise_case' - -class ZipperCase < Generator::ExerciseCase - def workload - [ - "#{initial_tree}", - "zipper = Zipper.from_tree(tree)", - "value = #{operations(input)}", - "#{expected_by_type}", - assertion - ] - end - - private - - def initial_tree - indent([ - "tree =\n", - build_tree(input['initialTree'], 2) - ], 2) - end - - def operations(input, zipper_name='zipper') - operation_chain = input['operations'].map do |op| - operation = op['operation'] - item = op['item'] - - set_tree = lambda do - if item.nil? - "#{operation}(nil)" - else - depth = ' ' * 2 - left = nil_if build_tree(item['left'], 3) - right = nil_if build_tree(item['right'], 3) - # I know. This line is crazy. - "#{operation}(\n#{depth}Node.new(#{item['value']},\n #{depth}#{left},\n #{depth}#{right}))" - end - end - - case operation - when 'set_value' - "#{operation}(#{op['item']})" - when 'set_left' - set_tree.call - when 'set_right' - set_tree.call - else - operation - end - end.join('.') - "#{zipper_name}.%s" % operation_chain - end - - def assertion - if expected['value'].nil? && expected['initialTree'].nil? - 'assert_nil value' - else - 'assert_equal expected, value' - end - end - - def expected_by_type - case expected['type'] - when 'tree' - indent([ - "expected =\n", - build_tree(expected['value'], 2) - ], 2) - when 'int' - "expected = #{expected['value']}" - when 'zipper' - if expected['initialTree'] - indent([ - "expected_tree =\n ", - "#{build_tree(expected['initialTree'], 2)}\n", - "expected_zipper = Zipper.from_tree(expected_tree)\n", - "expected = #{operations(expected, 'expected_zipper')}" - ], 0) - elsif expected['value'].nil? - "expected = nil" - end - end - end - - def build_tree(input, depth) - return 'nil' if input.nil? - next_depth = depth + 1 - tree = "Node.new(#{input['value']},\n", - "#{build_tree(input['left'], next_depth)},\n", - "#{build_tree(input['right'], next_depth)})" - indent(tree, depth * 2) - end - - def indent(lines, spaces) - lines.join(' ' * spaces) - end - - def nil_if(value) - if value.nil? - 'nil' - else - value - end - end -end From 0fdf1532b88794f1f7e18d105d925335f723657f Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 10:40:58 +0200 Subject: [PATCH 5/9] Upgrade rubocop to latest version --- Gemfile | 2 +- Gemfile.lock | 32 +++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Gemfile b/Gemfile index 95fa3b6b8b..fa2d4a9f88 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source 'https://rubygems.org' gem 'minitest' gem 'rake' gem 'mocha', require: false -gem 'rubocop', '~> 1.21', require: false +gem 'rubocop', '~> 1.50.0', require: false gem 'rubocop-minitest', require: false gem 'rubocop-rake', require: false gem 'simplecov', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 786493523e..5f073c4c77 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,38 +3,40 @@ GEM specs: ast (2.4.2) docile (1.4.0) + json (2.6.3) minitest (5.14.4) mocha (1.13.0) - parallel (1.21.0) - parser (3.0.2.0) + parallel (1.23.0) + parser (3.2.2.1) ast (~> 2.4.1) - rainbow (3.0.0) + rainbow (3.1.1) rake (13.0.6) - regexp_parser (2.1.1) + regexp_parser (2.8.0) rexml (3.2.5) - rubocop (1.21.0) + rubocop (1.50.2) + json (~> 2.3) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.2.0.0) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.9.1, < 2.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.28.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.11.0) - parser (>= 3.0.1.1) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.28.0) + parser (>= 3.2.1.0) rubocop-minitest (0.15.0) rubocop (>= 0.90, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - ruby-progressbar (1.11.0) + ruby-progressbar (1.13.0) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.3) - unicode-display_width (2.1.0) + unicode-display_width (2.4.2) PLATFORMS ruby @@ -43,10 +45,10 @@ DEPENDENCIES minitest mocha rake - rubocop (~> 1.21) + rubocop (~> 1.50.0) rubocop-minitest rubocop-rake simplecov BUNDLED WITH - 2.1.4 + 2.2.22 From 69da91a8c5595d39619704e1335664672893620b Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 11:05:58 +0200 Subject: [PATCH 6/9] Fix acronym tests.toml The tests.toml file had two tests that were not included in the test suite. --- exercises/practice/acronym/.meta/tests.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/exercises/practice/acronym/.meta/tests.toml b/exercises/practice/acronym/.meta/tests.toml index 6e3277c68d..5c5b9fd84e 100644 --- a/exercises/practice/acronym/.meta/tests.toml +++ b/exercises/practice/acronym/.meta/tests.toml @@ -29,9 +29,3 @@ description = "very long abbreviation" [6a078f49-c68d-4b7b-89af-33a1a98c28cc] description = "consecutive delimiters" - -[5118b4b1-4572-434c-8d57-5b762e57973e] -description = "apostrophes" - -[adc12eab-ec2d-414f-b48c-66a4fc06cdef] -description = "underscore emphasis" From 042b14f1e9f672776b84c3b9c08c064a8abd3fa7 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 26 Apr 2023 19:57:34 +0200 Subject: [PATCH 7/9] Temporarily override ruby version --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 4efbd8f759..be94e6f53d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-3.0.2 +3.2.2 From c35e38f28ffc8b3979151f401916d1dafed4912e Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 19 Apr 2023 16:37:28 +0200 Subject: [PATCH 8/9] Set up generator --- generator/config.json | 10 ++++++++++ generator/templates/imports.tmpl | 2 ++ generator/templates/initialization.tmpl | 0 generator/templates/suite.tmpl | 6 ++++++ generator/templates/test.error.tmpl | 6 ++++++ generator/templates/test.false.tmpl | 4 ++++ generator/templates/test.tmpl | 4 ++++ generator/templates/test.true.tmpl | 4 ++++ 8 files changed, 36 insertions(+) create mode 100644 generator/config.json create mode 100644 generator/templates/imports.tmpl create mode 100644 generator/templates/initialization.tmpl create mode 100644 generator/templates/suite.tmpl create mode 100644 generator/templates/test.error.tmpl create mode 100644 generator/templates/test.false.tmpl create mode 100644 generator/templates/test.tmpl create mode 100644 generator/templates/test.true.tmpl diff --git a/generator/config.json b/generator/config.json new file mode 100644 index 0000000000..3c2e310027 --- /dev/null +++ b/generator/config.json @@ -0,0 +1,10 @@ +{ + "skipping": { + "yes": "skip", + "no": "# skip" + }, + "postprocess": [ + "rubocop -A exercises/practice/{{exercise-name}}", + "rake test:{{exercise-name}}" + ] +} diff --git a/generator/templates/imports.tmpl b/generator/templates/imports.tmpl new file mode 100644 index 0000000000..f97860b140 --- /dev/null +++ b/generator/templates/imports.tmpl @@ -0,0 +1,2 @@ +require 'minitest/autorun' +require_relative '{{exercise_name}}' diff --git a/generator/templates/initialization.tmpl b/generator/templates/initialization.tmpl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/generator/templates/suite.tmpl b/generator/templates/suite.tmpl new file mode 100644 index 0000000000..cdd10f4dab --- /dev/null +++ b/generator/templates/suite.tmpl @@ -0,0 +1,6 @@ +{{imports}} + +class {{ExerciseName}}Test < Minitest::Test +{{initialization}} +{{tests}} +end diff --git a/generator/templates/test.error.tmpl b/generator/templates/test.error.tmpl new file mode 100644 index 0000000000..8c1c356bf6 --- /dev/null +++ b/generator/templates/test.error.tmpl @@ -0,0 +1,6 @@ + def test_{{test_description}} + {{skipping}} + assert_raises({{expected-error}}) do + {{ExerciseNamespace}}.{{property_name}}({{input}}) + end + end diff --git a/generator/templates/test.false.tmpl b/generator/templates/test.false.tmpl new file mode 100644 index 0000000000..653eb788a8 --- /dev/null +++ b/generator/templates/test.false.tmpl @@ -0,0 +1,4 @@ + def test_{{test_description}} + {{skipping}} + refute {{ExerciseNamespace}}.{{property_name}}({{input}}) + end diff --git a/generator/templates/test.tmpl b/generator/templates/test.tmpl new file mode 100644 index 0000000000..4769913ce4 --- /dev/null +++ b/generator/templates/test.tmpl @@ -0,0 +1,4 @@ + def test_{{test_description}} + {{skipping}} + assert_equal {{expected}}, {{ExerciseNamespace}}.{{property_name}}({{input}}) + end diff --git a/generator/templates/test.true.tmpl b/generator/templates/test.true.tmpl new file mode 100644 index 0000000000..adbd5b3791 --- /dev/null +++ b/generator/templates/test.true.tmpl @@ -0,0 +1,4 @@ + def test_{{test_description}} + {{skipping}} + assert {{ExerciseNamespace}}.{{property_name}}({{input}}) + end From ab368cf2e91413eeb9a8ea985471130a7c0d3fa7 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 19 Apr 2023 17:02:28 +0200 Subject: [PATCH 9/9] Add simple syntax file --- generator/syntax | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 generator/syntax diff --git a/generator/syntax b/generator/syntax new file mode 100755 index 0000000000..06496d919b --- /dev/null +++ b/generator/syntax @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +require 'json' + +value = JSON.parse(ARGV.first)["value"] +if value.is_a?(String) || value.nil? + puts value.inspect +else + puts value.to_s +end