diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..ed8f4a432b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 + +updates: + + # Keep dependencies for GitHub Actions up-to-date + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'daily' diff --git a/.github/workflows/configlet.yml b/.github/workflows/configlet.yml index 06c076e089..9e6ce9f778 100644 --- a/.github/workflows/configlet.yml +++ b/.github/workflows/configlet.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v2 - name: Fetch configlet - uses: exercism/github-actions/configlet-ci@master + uses: exercism/github-actions/configlet-ci@main - name: Configlet Linter - run: configlet lint . + run: configlet lint diff --git a/README.md b/README.md index f685bd0e56..92d1a3a860 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ 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. ``` -../problem-specifications/exercises// +https://github.com/exercism/v3/blob/main/problem-specifications/exercises// ├── canonical-data.json ├── description.md └── metadata.yml diff --git a/bin/fetch-configlet b/bin/fetch-configlet index 915ee034d4..43f1c83cee 100755 --- a/bin/fetch-configlet +++ b/bin/fetch-configlet @@ -1,52 +1,58 @@ -#!/bin/bash +#!/usr/bin/env bash set -eo pipefail readonly LATEST='https://api.github.com/repos/exercism/configlet/releases/latest' case "$(uname)" in - (Darwin*) OS='mac' ;; - (Linux*) OS='linux' ;; - (Windows*) OS='windows' ;; - (MINGW*) OS='windows' ;; - (MSYS_NT-*) OS='windows' ;; - (*) OS='linux' ;; + Darwin*) os='mac' ;; + Linux*) os='linux' ;; + Windows*) os='windows' ;; + MINGW*) os='windows' ;; + MSYS_NT-*) os='windows' ;; + *) os='linux' ;; esac -case "$OS" in - (windows*) EXT='zip' ;; - (*) EXT='tgz' ;; +case "${os}" in + windows*) ext='zip' ;; + *) ext='tgz' ;; esac case "$(uname -m)" in - (*64*) ARCH='64bit' ;; - (*686*) ARCH='32bit' ;; - (*386*) ARCH='32bit' ;; - (*) ARCH='64bit' ;; + *64*) arch='64bit' ;; + *686*) arch='32bit' ;; + *386*) arch='32bit' ;; + *) arch='64bit' ;; esac -if [ -z "${GITHUB_TOKEN}" ] -then - HEADER='' -else - HEADER="authorization: Bearer ${GITHUB_TOKEN}" +curlopts=( + --silent + --show-error + --fail + --location + --retry 3 +) + +if [[ -n "${GITHUB_TOKEN}" ]]; then + curlopts+=(--header "authorization: Bearer ${GITHUB_TOKEN}") fi -FILENAME="configlet-${OS}-${ARCH}.${EXT}" +suffix="${os}-${arch}.${ext}" -get_url () { - curl --header "$HEADER" -s "$LATEST" | - awk -v filename=$FILENAME '$1 ~ /browser_download_url/ && $2 ~ filename { print $2 }' | - tr -d '"' +get_download_url() { + curl "${curlopts[@]}" --header 'Accept: application/vnd.github.v3+json' "${LATEST}" | + grep "\"browser_download_url\": \".*/download/.*/configlet.*${suffix}\"$" | + cut -d'"' -f4 } -URL=$(get_url) +download_url="$(get_download_url)" +output_dir="bin" +output_path="${output_dir}/latest-configlet.${ext}" +curl "${curlopts[@]}" --output "${output_path}" "${download_url}" -case "$EXT" in - (*zip) - curl --header "$HEADER" -s --location "$URL" -o bin/latest-configlet.zip - unzip bin/latest-configlet.zip -d bin/ - rm bin/latest-configlet.zip - ;; - (*) curl --header "$HEADER" -s --location "$URL" | tar xz -C bin/ ;; +case "${ext}" in + *zip) unzip "${output_path}" -d "${output_dir}" ;; + *) tar xzf "${output_path}" -C "${output_dir}" ;; esac + +rm -f "${output_path}" diff --git a/concepts/arrays/about.md b/concepts/arrays/about.md new file mode 100644 index 0000000000..3d78c7a5c5 --- /dev/null +++ b/concepts/arrays/about.md @@ -0,0 +1,54 @@ +Data structures that can hold zero or more elements are known as _collections_. An **array** in Ruby is a collection that maintains the ordering in which its objects are added. Arrays can hold any object. Objects can be added to an array or retrieved from it using an index. Ruby array indexing is zero-based, meaning that the first element's index is always zero: + +```ruby +# Declare an array containing two values +two_ints = [1,2]; + +# Assign first and second element by index +two_ints[0] = 7; +two_ints[1] = 8; + +# Retrieve the second element by index +two_ints[1] # => 8 + +# Check the length of the array +two_ints.size # => 2 +``` + +In Ruby there are multiple ways of creating an Array: + +- Using the literal constructor `[]` _(most common)_ +- Explicitly calling `Array.new` +- Calling the Kernel `Array()` method + +The `Array.new` method supports two optional arguments: the initial size of the array and a default object. + +When a size and default are provided, the array is populated with `size` copies of default object. + +```ruby +a = Array.new(2, Hash.new) +# => [{}, {}] +``` + +Since all the Array elements store the same hash, changes to one of them will affect them all. + +```ruby +a[0]['cat'] = 'feline' +a # => [{"cat"=>"feline"}, {"cat"=>"feline"}] + +a[1]['cat'] = 'Felix' +a # => [{"cat"=>"Felix"}, {"cat"=>"Felix"}] +``` + +If multiple copies are what you want, you should use the block version which uses the result of that block each time an element of the array needs to be initialized: + +```ruby +a = Array.new(2) {Hash.new} +a[0]['cat'] = 'feline' +a # => [{"cat"=>"feline"}, {}] +``` + +Another characteristic of Ruby arrays is that they mix in the [Enumerable][enumerable-module] module, which adds a lot of handy methods to iterate, search, sort, filter, etc. elements of an array. + +[enumerable-module]: https://ruby-doc.org/core-2.7.1/Enumerable.html +[for-loop]: https://launchschool.com/books/ruby/read/loops_iterators#forloops diff --git a/concepts/arrays/introduction.md b/concepts/arrays/introduction.md new file mode 100644 index 0000000000..ac17cb6f6b --- /dev/null +++ b/concepts/arrays/introduction.md @@ -0,0 +1,84 @@ +In Ruby, **arrays** are ordered, integer-indexed collections of any object. Array indexing starts at `0`. A negative index is assumed to be relative to the end of the array — i.e. an index of `-1` indicates the last element of the array, `-2` is the next to last element in the array, and so on. +Ruby arrays mix in the [Enumerable module][enumerable-module], which adds several traversal and searching methods, and with the ability to sort. + +### Create array. + +- An array in Ruby can contain different types of objects. + +```ruby +array = [1, "two", 3.0] #=> [1, "two", 3.0] +``` + +### Element Assignment + +Elements can accessed or changed using indexes. Subarrays can be accessed by specifying a start index and a size. + +```ruby +a = ["", "", "", "", ""] + +a[4] = "hello" #=> [nil, nil, nil, nil, "hello"] +a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "hello"] +``` + +- Negative indices will count backward from the end of the array. + +```ruby +a = ['a', 'b'] + +a[-1] = "Z" +a #=> ["a", "Z"] +``` + +### Element Reference + +- Elements in an array can be retrieved using the #[] method. It returns the element at index, or returns a subarray starting at the start index and continuing for length elements. + +```ruby +a = [ "a", "b", "c", "d", "e" ] + +a[2] #=> "c" +a[6] #=> nil +a[1, 2] #=> [ "b", "c" ] +``` + +- Negative indices count backward from the end of the array (-1 is the last element) + +```ruby +a = [ "a", "b", "c", "d", "e" ] + +a[-2] #=> "d" +a[-3, 3] #=> [ "c", "d", "e" ] +``` + +### Obtaining Information about an Array + +Arrays keep track of their own length at all times. To query an array about the number of elements it contains, use length, count or size. + +```ruby +browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] +browsers.length #=> 5 +browsers.count #=> 5 +browsers.size #=> 5 +``` + +### Adding Items to Arrays + +Items can be added to the end of an array by using either push or << + +```ruby +arr = [1, 2, 3, 4] +arr.push(5) #=> [1, 2, 3, 4, 5] +arr << 6 #=> [1, 2, 3, 4, 5, 6] +``` + +### Removing Items from an Array + +The method pop removes the last element in an array and returns it + +```ruby +arr = [1, 2, 3, 4, 5, 6] +arr.pop #=> 6 +arr #=> [1, 2, 3, 4, 5] +``` + +[enumerable-module]: https://ruby-doc.org/core-2.7.1/Enumerable.html diff --git a/concepts/arrays/links.json b/concepts/arrays/links.json new file mode 100644 index 0000000000..4dc034f96c --- /dev/null +++ b/concepts/arrays/links.json @@ -0,0 +1,6 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.1/Enumerable.html", + "description": "enumerable-module" + } +] diff --git a/concepts/basics/about.md b/concepts/basics/about.md new file mode 100644 index 0000000000..9b14ae5c43 --- /dev/null +++ b/concepts/basics/about.md @@ -0,0 +1,45 @@ +Ruby is a dynamic and strongly typed language. In dynamic languages the type of a variable or object is resolved at runtime, which means that its value or type can be changed up to the very last moment (when it gets parsed by the interpreter). +And what do we mean with strongly typed? Once we know the type of a variable or object, Ruby is strict about what you can do with it, for example: + +```ruby +x = '2' +y = x + 'n' +=> '2n' +``` + +**But** + +````ruby +x = '2' +y = x + 2 +=> TypeError (no implicit conversion of Integer into String) + +Remember, in Ruby everything is an object. Even classes are instances of the class `Class`. For example: + +```ruby +1.class +=> Integer + +Integer.is_a?(Object) +# => true + +Class.is_a?(Object) +# => true +```` + +This means that we can also define classes like this: + +```ruby +Car = Class.new do + def run + 'running' + end +end + +Car.new.run +=> 'running' +``` + +Finally, bear in mind that the `Integer` object holds values that may be defined as one or more (consecutive) digits and its methods support many of the [mathematical operators][integers-docs]. + +[integers-docs]: https://ruby-doc.org/core-2.7.0/Integer.html diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md new file mode 100644 index 0000000000..537bc457d9 --- /dev/null +++ b/concepts/basics/introduction.md @@ -0,0 +1,55 @@ +Ruby is a dynamic [object-oriented language][object-oriented-programming]. Everything in Ruby is an [object][object]. + +There are two primary ways to assign objects to names in Ruby - using variables or constants. Variables are always written in [snake case][snake-case]. A variable can reference different objects over its lifetime. For example, `my_first_variable` can be defined and redefined many times using the `=` operator: + +```ruby +my_first_variable = 1 +my_first_variable = "Some string" +my_first_variable = SomeComplexObject.new +``` + +Constants, however, are meant to be assigned once. They must start with capital letters and are normally written in block capitals with words separated by underscores. For example: + +```ruby +MY_FIRST_CONSTANT = 10 + +# Redefining not allowed +# MY_FIRST_CONSTANT = "Some String" +``` + +Ruby is organised into classes. Classes are defined using the `class` keyword followed by the name of the class. Objects are generally created by instantiating classes using the `.new` method. For example: + +```ruby +# Define the class +class Calculator + #... +end + +# Create an instance of it and assign it to a variable +my_first_calc = Calculator.new +``` + +Units of functionality are encapsulated in methods - similar to _functions_ in other languages. A method can optionally be defined with positional arguments, and/or keyword arguments that are defined and called using the `:` syntax. Methods either implicitly return the result of the last evaluated statement, or can explicitly return an object via the `return` keyword. Methods are invoked using `.` syntax. + +```ruby +class Calculator + + # Unnamed params + def add(num1, num2) + return num1 + num2 # Explicit return + end + + # Named params + def multiply(num1:, num2:) + num1 * num2 # Implicit return + end +end + +calc = Calculator.new +calc.add(1, 3) +calc.multiply(num1: 2, num_2: 5) +``` + +[object-oriented-programming]: https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/oothinking.html +[object]: https://github.com/exercism/v3/blob/main/reference/concepts/objects.md +[snake-case]: https://en.wikipedia.org/wiki/Snake_case diff --git a/concepts/basics/links.json b/concepts/basics/links.json new file mode 100644 index 0000000000..3672d2c252 --- /dev/null +++ b/concepts/basics/links.json @@ -0,0 +1,6 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.0/Integer.html", + "description": "integers-docs" + } +] diff --git a/concepts/blocks/about.md b/concepts/blocks/about.md new file mode 100644 index 0000000000..3171aac4f5 --- /dev/null +++ b/concepts/blocks/about.md @@ -0,0 +1 @@ +TODO: add information on blocks concept diff --git a/concepts/blocks/introduction.md b/concepts/blocks/introduction.md new file mode 100644 index 0000000000..c7bbbd2213 --- /dev/null +++ b/concepts/blocks/introduction.md @@ -0,0 +1 @@ +TODO: add introduction for blocks concept diff --git a/concepts/blocks/links.json b/concepts/blocks/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/blocks/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md new file mode 100644 index 0000000000..ccaf2fcd76 --- /dev/null +++ b/concepts/booleans/about.md @@ -0,0 +1,35 @@ +## True, False + +- `true` and `false` are used to represent boolean logical states. + - They are singleton instances of the [`TrueClass`][true-class] and [`FalseClass`][false-class] objects. + - they may occur as literals in code, or as the result of logical (`&&`, `||`, `!`) or [comparison][comparable-class] (`<`, `>`, `==`) methods. + +## _Truthy_ and _falsey_ + +- When not using strict Boolean values, _truthy_ and _falsey_ evaluation rules are applied: + + - Only `false` and `nil` evaluates as _falsey_. + - Everything else evaluates as _truthy_. + + ```ruby + # A simplified definition + def falsey + nil || false + end + + def truthy + not falsey + end + ``` + +[c-family]: https://en.wikipedia.org/wiki/List_of_C-family_programming_languages +[control-expressions]: https://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Control_Structures +[true-class]: https://docs.ruby-lang.org/en/master/TrueClass.html +[false-class]: https://docs.ruby-lang.org/en/master/FalseClass.html +[nil-class]: https://docs.ruby-lang.org/en/master/NilClass.html +[comparable-class]: https://docs.ruby-lang.org/en/master/Comparable.html +[constants]: https://www.rubyguides.com/2017/07/ruby-constants/ +[integer-class]: https://docs.ruby-lang.org/en/master/Integer.html +[kernel-class]: https://docs.ruby-lang.org/en/master/Kernel.html +[methods]: https://launchschool.com/books/ruby/read/methods +[returns]: https://www.freecodecamp.org/news/idiomatic-ruby-writing-beautiful-code-6845c830c664/ diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md new file mode 100644 index 0000000000..1107f71068 --- /dev/null +++ b/concepts/booleans/introduction.md @@ -0,0 +1,64 @@ +TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction + +## booleans + +## True and False + +True and false logical states are represented with `true` and `false` in Ruby. These may either be used as literals on their own, or as a result of logical or comparison methods. + +```ruby +happy = true +sad = false + +true && false +# => false + +1 < 2 +# => true +``` + +## _Truthy_ and _falsey_ + +When evaluating objects in `if` statements or other boolean contexts, all objects evaluate as _truthy_ **except** for `false` and `nil`. + +## Control flow + +_Truthy_ and _falsey_ evaluations are useful in the context of control flow. Like in procedural languages, Ruby has an `if`...`else` construct, but it may be more common to use `if` as a "guarding" statement to modify the evaluation of an expression. + +```ruby +def falsey + nil || false +end + +def truthy + not falsey +end + +if truthy + # this block is evaluated +end + +if falsey + # this block is not evaluated +else + # this block is evaluated +end + +1 + 1 if truthy +# => this will evaluate and return 2 + +2 + 2 if falsey +# => the numbers are not added because of the modifier, nil is returned +``` + +Ruby provides `unless` to make code read well. E.g.) Rather than `eat_desert if not too_full`, we can also write `eat_desert unless too_full`. + +```ruby +3 + 3 unless truthy +# => the numbers are not added because of the modifier, nil is returned + +4 + 4 unless falsey +# => this will evaluate and return 8 +``` + +[nil-dictionary]: https://www.merriam-webster.com/dictionary/nil diff --git a/concepts/booleans/links.json b/concepts/booleans/links.json new file mode 100644 index 0000000000..8695de3794 --- /dev/null +++ b/concepts/booleans/links.json @@ -0,0 +1,26 @@ +[ + { + "url": "https://docs.ruby-lang.org/en/master/TrueClass.html", + "description": "true-class" + }, + { + "url": "https://docs.ruby-lang.org/en/master/FalseClass.html", + "description": "false-class" + }, + { + "url": "https://docs.ruby-lang.org/en/master/Comparable.html", + "description": "comparable-class" + }, + { + "url": "https://docs.ruby-lang.org/en/master/syntax/control_expressions_rdoc.html", + "description": "control-expressions" + }, + { + "url": "https://en.wikipedia.org/wiki/List_of_C-family_programming_languages", + "description": "c-family" + }, + { + "url": "https://docs.ruby-lang.org/en/master/syntax/control_expressions_rdoc.html#label-Modifier\u002Bif\u002Band\u002Bunless", + "description": "if-modifier" + } +] diff --git a/concepts/classes/about.md b/concepts/classes/about.md new file mode 100644 index 0000000000..608d2f539e --- /dev/null +++ b/concepts/classes/about.md @@ -0,0 +1 @@ +TODO: add information on classes concept diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md new file mode 100644 index 0000000000..cacf371834 --- /dev/null +++ b/concepts/classes/introduction.md @@ -0,0 +1 @@ +TODO: add introduction for classes concept diff --git a/concepts/classes/links.json b/concepts/classes/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/classes/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/conditionals/about.md b/concepts/conditionals/about.md new file mode 100644 index 0000000000..92750518df --- /dev/null +++ b/concepts/conditionals/about.md @@ -0,0 +1,81 @@ +One of the key aspects of working with numbers in Ruby is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). +They are implemented through the [`Integer`][integer-ruby] and [`Float`][float-ruby] class. + +```ruby +a = 1 +b = 1.0 +a.class +#=> Integer +b.class +#=> Float +``` + +- Arithmetic is done using the basic [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, `/`). Numbers can be compared using the standard [comparison operators][comparison-operators]. +- Basic arithmetic operations between instances of `Integer`, will always result in an instance of `Integer`. +- Basic arithmetic operations between instances of `Float` will result in other instances of `Float`. +- Basic arithmetic operations between instances of `Integer` and instances of `Float` will result in instances of `Float`. +- The `Float` and `Integer` classes have methods that will coerce values from one to the other. `Integer` numbers are precise to a whole unit, while `Float` has precision that is fractional to an whole number. This means that coercing a float to an integer may result in loss of precision. + +```ruby +4.9.to_i +#=> 4 + +5.to_f +#=> 5.0 + +7 - 3.0 +#=> 4.0 + +2 == 4 +#=> false + +1.0 == 1 +#=> true +``` + +An `if` statement can be used to conditionally execute code: + +```ruby +x = 5 + +if x == 5 + # Execute logic if x equals 5 +elsif x > 7 + # Execute logic if x greater than 7 +else + # Execute logic in all other cases +end +``` + +Sometimes you want to execute a statement (or statements) if a condition is _not_ true, for situations like that, Ruby implements the `unless` keyword: + +```ruby +x = 4 +unless x == 5 + # Execute logic if x does not equal 5 +else + # Execute logic if x == 5 +end +``` + +If you want to execute different code depending on the value of a variable, Ruby's `case` statement might come useful: + +```ruby +y = 5 +case y +when 3 + # Execute logic if y equals 3 +when 5 + # Execute logic if y equals 5 +else + # Execute logic in all other cases +end +``` + +The same problem can sometimes be solved using different types of conditional statements, sometimes one might be more suited for the problem than the other. It's a good idea to stop for a moment and also consider the other two options when using any of the three conditional statements. + +[arithmetic-operators]: https://www.tutorialspoint.com/ruby/ruby_operators.htm +[comparison-operators]: https://www.w3resource.com/ruby/ruby-comparison-operators.php +[if-else-unless]: https://www.w3resource.com/ruby/ruby-if-else-unless.php +[integer-ruby]: https://ruby-doc.org/core-2.7.1/Integer.html +[float-ruby]: https://ruby-doc.org/core-2.7.1/Float.html diff --git a/concepts/conditionals/introduction.md b/concepts/conditionals/introduction.md new file mode 100644 index 0000000000..bf9d71ae7d --- /dev/null +++ b/concepts/conditionals/introduction.md @@ -0,0 +1,22 @@ +Two common types of numbers in Ruby are: + +- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. +- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. + +They are implemented through the `Integer` and `Float` classes. + +The `Float` and `Integer` classes have methods that will coerce values from one to the other. `Integer` numbers are precise to a whole unit, while `Float` has precision that is fractional to an whole number. + +In this exercise you must conditionally execute logic. A common way to do this in Ruby is by using an `if/else` statement: + +```ruby +x = 5 + +if x == 5 + # Execute logic if x equals 5 +elsif x > 7 + # Execute logic if x greater than 7 +else + # Execute logic in all other cases +end +``` diff --git a/concepts/conditionals/links.json b/concepts/conditionals/links.json new file mode 100644 index 0000000000..a58c1c1b77 --- /dev/null +++ b/concepts/conditionals/links.json @@ -0,0 +1,18 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.1/Integer.html", + "description": "integer-ruby" + }, + { + "url": "https://ruby-doc.org/core-2.7.1/Float.html", + "description": "float-ruby" + }, + { + "url": "https://www.tutorialspoint.com/ruby/ruby_operators.htm", + "description": "arithmetic-operators" + }, + { + "url": "https://www.w3resource.com/ruby/ruby-comparison-operators.php", + "description": "comparison-operators" + } +] diff --git a/concepts/exceptions/about.md b/concepts/exceptions/about.md new file mode 100644 index 0000000000..ceb3d04ce7 --- /dev/null +++ b/concepts/exceptions/about.md @@ -0,0 +1,66 @@ +It is important to note that exceptions should be used in cases where something exceptional happens, an error that needs special handling. Exceptions should not be used for control-flow of a program, as that is considered bad design, which often leads to bad performance and maintainability. + +In Ruby exceptions follow a class hierarchy where `Exception` is the base class. These are the most common Ruby's built-in exceptions: + +``` +Exception + NoMemoryError + ScriptError + LoadError + NotImplementedError + SyntaxError + SignalException + Interrupt + StandardError + ArgumentError + IOError + EOFError + IndexError + LocalJumpError + NameError + NoMethodError + RangeError + FloatDomainError + RegexpError + RuntimeError + SecurityError + SystemCallError + SystemStackError + ThreadError + TypeError + ZeroDivisionError + SystemExit +``` + +Rescuing errors of a specific class also rescues errors of its children. This is why rescuing from `Exception` can be dangerous. +Ruby uses exceptions to also handle messages from the operative system "Signals", for example `ctrl-c`. This means that rescuing from `Exception` will also capture this system "Signals". So in order to prevent unexpected behaviours the common practice to capture "all errors" is to rescue form `StandardError`. + +Ruby also provide extended rescue clauses for situations that require an special treatment: + +```ruby +begin +... +rescue CustomError => error + # This block is run if a CustomError occurs +rescue AnotherCustomError => error + # This block is run if a AnotherCustomError occurs +else + # This block is run if no exception occurred at all +ensure + # This block always run, regardless of whether an exception occurred +end +``` + +This can be useful for example when working with network IO where we always need to remember to close a connection. + +Ruby rescue blocks can also use the `retry` keyword which re-runs everything between begin and rescue: + +```ruby +counter = 0 +begin + counter += 1 + api_request +rescue + retry if counter <= 3 +end +``` diff --git a/concepts/exceptions/links.json b/concepts/exceptions/links.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/concepts/floating-point-numbers/about.md b/concepts/floating-point-numbers/about.md new file mode 100644 index 0000000000..a31d87ed0c --- /dev/null +++ b/concepts/floating-point-numbers/about.md @@ -0,0 +1,53 @@ +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `4.0`, `0.1`, `3.14`, `-6.4` `16.984025` and `1024.0`. In Ruby, floating-point numbers are implemented through the [Float](https://ruby-doc.org/core-2.7.0/Float.html) class. + +You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. + +The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. + +To repeatedly execute logic, one can use loops. In this example the `while` loop is useful because it keeps on looping _while_ a condition evaluates to some truthy value (i.e. not `false` or `nil`). Ruby implements a loop similar to the `while` loop. It's called the `until` loop, and you've probably guessed what it does. It keeps looping _until_ a boolean condition evaluates to `true`. In some languages, to make a piece of code execute an unlimited number of times, constructs like `while true` are used. In Ruby, the `loop` loop exists for that purpose. Even though the `loop` loop does not depend on a single condition, it can be canceled by using a `return` or `break` keyword. + +The `#years_before_desired_balance` method from the previous exercise could have been written by using any of the three mentioned loops: + +### `while` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + while current_balance < desired_balance + current_balance = annual_balance_update(current_balance) + years += 1 + end + years +end +``` + +### `until` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + until current_balance >= desired_balance + current_balance = annual_balance_update(current_balance) + years += 1 + end + years +end +``` + +### `loop` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + loop do + current_balance = annual_balance_update(current_balance) + years += 1 + return years if current_balance >= desired_balance + end +end +``` + +As you have probably noticed, Ruby has no increment operator (`i++`) like some other languages do. Instead, constructs like `i += 1` (which is equal to `i = i + 1`) can be used. + +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[evanw.github.io-float-toy]: https://evanw.github.io/float-toy/ diff --git a/concepts/floating-point-numbers/introduction.md b/concepts/floating-point-numbers/introduction.md new file mode 100644 index 0000000000..aff33f5e92 --- /dev/null +++ b/concepts/floating-point-numbers/introduction.md @@ -0,0 +1,18 @@ +TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction + +## floating-point-numbers + +## loops + +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `4.0`, `0.1`, `3.14`, `-6.4` `16.984025` and `1024.0`. +In Ruby, floating-point numbers are implemented through the [Float](https://ruby-doc.org/core-2.7.0/Float.html) class. + +In this exercise you may also want to use a loop. There are several ways to write loops in Ruby, one of them is the `while` loop: + +```ruby +counter = 0 + +while counter < 5 + counter += 1 +end +``` diff --git a/concepts/floating-point-numbers/links.json b/concepts/floating-point-numbers/links.json new file mode 100644 index 0000000000..20dc68f0a4 --- /dev/null +++ b/concepts/floating-point-numbers/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.0/Float.html", + "description": "Float" + }, + { + "url": "https://0.30000000000000004.com/", + "description": "0.30000000000000004.com" + }, + { + "url": "https://evanw.github.io/float-toy/", + "description": "evanw.github.io-float-toy" + } +] diff --git a/concepts/instance-variables/about.md b/concepts/instance-variables/about.md new file mode 100644 index 0000000000..003910afc0 --- /dev/null +++ b/concepts/instance-variables/about.md @@ -0,0 +1,63 @@ +## Key Points: + +- When a class' `.new` method is called to create an object instance, the `.initialize` method is passed all arguments to initialize the instance's state. +- instance variable names are prefixed with `@`. +- instance variables default to `nil` until they are explicitly set. +- instance variables are private by default, and they should be manipulated with getters and setters + +```ruby +class Backpack + initialize(owner) + @owner = owner + end + + def owner + @owner + end + + def owner=(new_owner) + @owner = new_owner + end +end +``` + +- Methods named with a trailing `=` are recognized as setters by Ruby, and allow the syntactic "sugar" use of the assignment syntax, e.g. `Backpack.new("Sven").owner = "Ayah"`. Notice the space between `owner` and `=` while the actual method name is `owner=`. +- Getters and setters can be created using the `attr_reader`, `attr_writer`, and `attr_accessor` methods: + - `attr_reader`: Create getters for the symbols listed + - `attr_writer`: Create setters for the symbols listed + - `attr_accessor`: Create getters and setters for the symbols listed + +```ruby +class Backpack + attr_accessor :owner + + initialize(owner) + @owner = owner + end +end +``` + +- Why use getters and setters rather than the instance variable directly? + - If there was a typographical error (we call these "typo") in the previous example (e.g. `@ownar`), it would fail silently, potentially introducing a bug into the system. + - Getters and setters make this explicit, and will raise an error when a typo is made + +## References + +### Initializing object instances + +- [Ruby Guides: Initialize Method][rg-initialize-method] + +### Instance variables + +- [Ruby For Beginners: Instance variables][rfb-instance-variables] +- [Ruby Guides: Instance variables][rg-instance-variables] +- [Ruby User's Guide: Instance variables][rug-instance-variables] +- [Geeks for Geeks: Ruby Getters and Setters Methods][gfg-getter-setters] +- [Mix & Go: Ruby's attr_accessor, attr_reader, attr_writer][mg-attr] + +[mg-attr]: https://mixandgo.com/learn/ruby_attr_accessor_attr_reader_attr_writer +[rfb-instance-variables]: http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html +[rg-initialize-method]: https://www.rubyguides.com/2019/01/ruby-initialize-method/ +[rg-instance-variables]: https://www.rubyguides.com/2019/07/ruby-instance-variables/ +[rug-instance-variables]: https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html +[gfg-getter-setters]: https://www.geeksforgeeks.org/ruby-getters-and-setters-method/ diff --git a/concepts/instance-variables/introduction.md b/concepts/instance-variables/introduction.md new file mode 100644 index 0000000000..cfbb665e99 --- /dev/null +++ b/concepts/instance-variables/introduction.md @@ -0,0 +1,62 @@ +TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction + +## instance-variables + +## nil + +## Object state, instance variables + +Objects can hold their own state by setting _instance variables_, which are created by prefixing `@` to a variable name. + +```ruby +@name = 2 +``` + +Objects usually set their initial state in an `initialize` method, which is automatically called when calling `new` on a class. + +```ruby +class Airplane + def initialize + @wings = 2 + end +end +``` + +The `initialize` method may also take arguments, so that each instance can start with a custom state: + +```ruby +class Suitcase + def initialize(locked) + @locked = locked + end +end +``` + +Consider _instance_ variables to be private from external read and writes. _Instance_ methods should be used for getting and setting instance variables: + +```ruby +class Suitcase + #... + + def locked? # Query methods should be named with a trailing `?` + @locked + end + + def unlock! # Methods which mutate state should have trailing `!` + @locked = false + end +end +``` + +## Nil + +[Nil][nil-dictionary] is an English word meaning "nothing" or "zero". In Ruby, `nil` is used to express the _absence_ of an object. In other programming languages, `null` or `none` values may play a similar role. + +```ruby +# I do not have a favorite color +favorite_color = nil +``` + +Ruby gives any instance variable the default value of `nil` when it is first encountered, until it is set otherwise. + +[nil-dictionary]: https://www.merriam-webster.com/dictionary/nil diff --git a/concepts/instance-variables/links.json b/concepts/instance-variables/links.json new file mode 100644 index 0000000000..42d0ff212c --- /dev/null +++ b/concepts/instance-variables/links.json @@ -0,0 +1,26 @@ +[ + { + "url": "https://www.rubyguides.com/2019/01/ruby-initialize-method/", + "description": "rg-initialize-method" + }, + { + "url": "http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html", + "description": "rfb-instance-variables" + }, + { + "url": "https://www.rubyguides.com/2019/07/ruby-instance-variables/", + "description": "rg-instance-variables" + }, + { + "url": "https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html", + "description": "rug-instance-variables" + }, + { + "url": "https://www.geeksforgeeks.org/ruby-getters-and-setters-method/", + "description": "gfg-getter-setters" + }, + { + "url": "https://mixandgo.com/learn/ruby_attr_accessor_attr_reader_attr_writer", + "description": "mg-attr" + } +] diff --git a/concepts/loops/about.md b/concepts/loops/about.md new file mode 100644 index 0000000000..a31d87ed0c --- /dev/null +++ b/concepts/loops/about.md @@ -0,0 +1,53 @@ +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `4.0`, `0.1`, `3.14`, `-6.4` `16.984025` and `1024.0`. In Ruby, floating-point numbers are implemented through the [Float](https://ruby-doc.org/core-2.7.0/Float.html) class. + +You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. + +The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. + +To repeatedly execute logic, one can use loops. In this example the `while` loop is useful because it keeps on looping _while_ a condition evaluates to some truthy value (i.e. not `false` or `nil`). Ruby implements a loop similar to the `while` loop. It's called the `until` loop, and you've probably guessed what it does. It keeps looping _until_ a boolean condition evaluates to `true`. In some languages, to make a piece of code execute an unlimited number of times, constructs like `while true` are used. In Ruby, the `loop` loop exists for that purpose. Even though the `loop` loop does not depend on a single condition, it can be canceled by using a `return` or `break` keyword. + +The `#years_before_desired_balance` method from the previous exercise could have been written by using any of the three mentioned loops: + +### `while` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + while current_balance < desired_balance + current_balance = annual_balance_update(current_balance) + years += 1 + end + years +end +``` + +### `until` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + until current_balance >= desired_balance + current_balance = annual_balance_update(current_balance) + years += 1 + end + years +end +``` + +### `loop` + +```ruby +def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + loop do + current_balance = annual_balance_update(current_balance) + years += 1 + return years if current_balance >= desired_balance + end +end +``` + +As you have probably noticed, Ruby has no increment operator (`i++`) like some other languages do. Instead, constructs like `i += 1` (which is equal to `i = i + 1`) can be used. + +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[evanw.github.io-float-toy]: https://evanw.github.io/float-toy/ diff --git a/concepts/loops/introduction.md b/concepts/loops/introduction.md new file mode 100644 index 0000000000..050095f094 --- /dev/null +++ b/concepts/loops/introduction.md @@ -0,0 +1,12 @@ +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `4.0`, `0.1`, `3.14`, `-6.4` `16.984025` and `1024.0`. +In Ruby, floating-point numbers are implemented through the [Float](https://ruby-doc.org/core-2.7.0/Float.html) class. + +In this exercise you may also want to use a loop. There are several ways to write loops in Ruby, one of them is the `while` loop: + +```ruby +counter = 0 + +while counter < 5 + counter += 1 +end +``` diff --git a/concepts/loops/links.json b/concepts/loops/links.json new file mode 100644 index 0000000000..20dc68f0a4 --- /dev/null +++ b/concepts/loops/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.0/Float.html", + "description": "Float" + }, + { + "url": "https://0.30000000000000004.com/", + "description": "0.30000000000000004.com" + }, + { + "url": "https://evanw.github.io/float-toy/", + "description": "evanw.github.io-float-toy" + } +] diff --git a/concepts/nil/about.md b/concepts/nil/about.md new file mode 100644 index 0000000000..51f90cc44a --- /dev/null +++ b/concepts/nil/about.md @@ -0,0 +1,63 @@ +## Key Points: + +- When a class' `.new` method is called to create an object instance, the `.initialize` method is passed all arguments to initialize the instance's state. +- instance variable names are prefixed with `@`. +- instance variables default to `nil` until they are explicitly set. +- instance variables are private by default, and they should be manipulated with getters and setters + +```ruby +class Backpack + initialize(owner) + @owner = owner + end + + def owner + @owner + end + + def owner=(new_owner) + @owner = new_owner + end +end +``` + +- Methods named with a trailing `=` are recognized as setters by Ruby, and allow the optional use of the assignment syntax, e.g. `Backpack.new("Sven").owner = "Ayah"` +- Getters and setters can be shortened using the `attr_reader`, `attr_writer`, and `attr_accessor` methods: + - `attr_reader`: Create getters for the symbols listed + - `attr_writer`: Create setters for the symbols listed + - `attr_accessor`: Create getters and setters for the symbols listed + +```ruby +class Backpack + attr_accessor :owner + + initialize(owner) + @owner = owner + end +end +``` + +- Why use getters and setters rather than the instance variable directly? + - If there was a typogrpahical error (we call this "typo") in the previous example (e.g. `@ownar`), it would silently be assigned `nil`, potentially introducing a bug into the system. + - Getters and setters make this explicit, and will raise an error when a typo is made + +## References + +### Initializing object instances + +- [Ruby Guides: Initialize Method][rg-initialize-method] + +### Instance variables + +- [Ruby For Beginners: Instance variables][rfb-instance-variables] +- [Ruby Guides: Instance variables][rg-instance-variables] +- [Ruby User's Guide: Instance variables][rug-instance-variables] +- [Geeks for Geeks: Ruby Getters and Setters Methods][gfg-getter-setters] +- [Mix & Go: Ruby's attr_accessor, attr_reader, attr_writer][mg-attr] + +[mg-attr]: https://mixandgo.com/learn/ruby_attr_accessor_attr_reader_attr_writer +[rfb-instance-variables]: http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html +[rg-initialize-method]: https://www.rubyguides.com/2019/01/ruby-initialize-method/ +[rg-instance-variables]: https://www.rubyguides.com/2019/07/ruby-instance-variables/ +[rug-instance-variables]: https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html +[gfg-getter-setters]: https://www.geeksforgeeks.org/ruby-getters-and-setters-method/ diff --git a/concepts/nil/introduction.md b/concepts/nil/introduction.md new file mode 100644 index 0000000000..cfbb665e99 --- /dev/null +++ b/concepts/nil/introduction.md @@ -0,0 +1,62 @@ +TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction + +## instance-variables + +## nil + +## Object state, instance variables + +Objects can hold their own state by setting _instance variables_, which are created by prefixing `@` to a variable name. + +```ruby +@name = 2 +``` + +Objects usually set their initial state in an `initialize` method, which is automatically called when calling `new` on a class. + +```ruby +class Airplane + def initialize + @wings = 2 + end +end +``` + +The `initialize` method may also take arguments, so that each instance can start with a custom state: + +```ruby +class Suitcase + def initialize(locked) + @locked = locked + end +end +``` + +Consider _instance_ variables to be private from external read and writes. _Instance_ methods should be used for getting and setting instance variables: + +```ruby +class Suitcase + #... + + def locked? # Query methods should be named with a trailing `?` + @locked + end + + def unlock! # Methods which mutate state should have trailing `!` + @locked = false + end +end +``` + +## Nil + +[Nil][nil-dictionary] is an English word meaning "nothing" or "zero". In Ruby, `nil` is used to express the _absence_ of an object. In other programming languages, `null` or `none` values may play a similar role. + +```ruby +# I do not have a favorite color +favorite_color = nil +``` + +Ruby gives any instance variable the default value of `nil` when it is first encountered, until it is set otherwise. + +[nil-dictionary]: https://www.merriam-webster.com/dictionary/nil diff --git a/concepts/nil/links.json b/concepts/nil/links.json new file mode 100644 index 0000000000..42d0ff212c --- /dev/null +++ b/concepts/nil/links.json @@ -0,0 +1,26 @@ +[ + { + "url": "https://www.rubyguides.com/2019/01/ruby-initialize-method/", + "description": "rg-initialize-method" + }, + { + "url": "http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html", + "description": "rfb-instance-variables" + }, + { + "url": "https://www.rubyguides.com/2019/07/ruby-instance-variables/", + "description": "rg-instance-variables" + }, + { + "url": "https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html", + "description": "rug-instance-variables" + }, + { + "url": "https://www.geeksforgeeks.org/ruby-getters-and-setters-method/", + "description": "gfg-getter-setters" + }, + { + "url": "https://mixandgo.com/learn/ruby_attr_accessor_attr_reader_attr_writer", + "description": "mg-attr" + } +] diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md new file mode 100644 index 0000000000..92750518df --- /dev/null +++ b/concepts/numbers/about.md @@ -0,0 +1,81 @@ +One of the key aspects of working with numbers in Ruby is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). +They are implemented through the [`Integer`][integer-ruby] and [`Float`][float-ruby] class. + +```ruby +a = 1 +b = 1.0 +a.class +#=> Integer +b.class +#=> Float +``` + +- Arithmetic is done using the basic [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, `/`). Numbers can be compared using the standard [comparison operators][comparison-operators]. +- Basic arithmetic operations between instances of `Integer`, will always result in an instance of `Integer`. +- Basic arithmetic operations between instances of `Float` will result in other instances of `Float`. +- Basic arithmetic operations between instances of `Integer` and instances of `Float` will result in instances of `Float`. +- The `Float` and `Integer` classes have methods that will coerce values from one to the other. `Integer` numbers are precise to a whole unit, while `Float` has precision that is fractional to an whole number. This means that coercing a float to an integer may result in loss of precision. + +```ruby +4.9.to_i +#=> 4 + +5.to_f +#=> 5.0 + +7 - 3.0 +#=> 4.0 + +2 == 4 +#=> false + +1.0 == 1 +#=> true +``` + +An `if` statement can be used to conditionally execute code: + +```ruby +x = 5 + +if x == 5 + # Execute logic if x equals 5 +elsif x > 7 + # Execute logic if x greater than 7 +else + # Execute logic in all other cases +end +``` + +Sometimes you want to execute a statement (or statements) if a condition is _not_ true, for situations like that, Ruby implements the `unless` keyword: + +```ruby +x = 4 +unless x == 5 + # Execute logic if x does not equal 5 +else + # Execute logic if x == 5 +end +``` + +If you want to execute different code depending on the value of a variable, Ruby's `case` statement might come useful: + +```ruby +y = 5 +case y +when 3 + # Execute logic if y equals 3 +when 5 + # Execute logic if y equals 5 +else + # Execute logic in all other cases +end +``` + +The same problem can sometimes be solved using different types of conditional statements, sometimes one might be more suited for the problem than the other. It's a good idea to stop for a moment and also consider the other two options when using any of the three conditional statements. + +[arithmetic-operators]: https://www.tutorialspoint.com/ruby/ruby_operators.htm +[comparison-operators]: https://www.w3resource.com/ruby/ruby-comparison-operators.php +[if-else-unless]: https://www.w3resource.com/ruby/ruby-if-else-unless.php +[integer-ruby]: https://ruby-doc.org/core-2.7.1/Integer.html +[float-ruby]: https://ruby-doc.org/core-2.7.1/Float.html diff --git a/concepts/numbers/introduction.md b/concepts/numbers/introduction.md new file mode 100644 index 0000000000..9e1c8ab66f --- /dev/null +++ b/concepts/numbers/introduction.md @@ -0,0 +1,28 @@ +TODO: the content below is copied from the exercise introduction and probably needs rewriting to a proper concept introduction + +## numbers + +## conditionals + +Two common types of numbers in Ruby are: + +- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. +- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. + +They are implemented through the `Integer` and `Float` classes. + +The `Float` and `Integer` classes have methods that will coerce values from one to the other. `Integer` numbers are precise to a whole unit, while `Float` has precision that is fractional to an whole number. + +In this exercise you must conditionally execute logic. A common way to do this in Ruby is by using an `if/else` statement: + +```ruby +x = 5 + +if x == 5 + # Execute logic if x equals 5 +elsif x > 7 + # Execute logic if x greater than 7 +else + # Execute logic in all other cases +end +``` diff --git a/concepts/numbers/links.json b/concepts/numbers/links.json new file mode 100644 index 0000000000..a58c1c1b77 --- /dev/null +++ b/concepts/numbers/links.json @@ -0,0 +1,18 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.1/Integer.html", + "description": "integer-ruby" + }, + { + "url": "https://ruby-doc.org/core-2.7.1/Float.html", + "description": "float-ruby" + }, + { + "url": "https://www.tutorialspoint.com/ruby/ruby_operators.htm", + "description": "arithmetic-operators" + }, + { + "url": "https://www.w3resource.com/ruby/ruby-comparison-operators.php", + "description": "comparison-operators" + } +] diff --git a/concepts/strings/about.md b/concepts/strings/about.md new file mode 100644 index 0000000000..493d294a0e --- /dev/null +++ b/concepts/strings/about.md @@ -0,0 +1,9 @@ +The key thing to remember about Ruby strings is that they are objects that you call methods on. You can find all the methods in the [Ruby docs][ruby-doc.org-string] + +It's also worth knowing that strings can be created using single quotes (`'`) or double quotes (`"`). Single-quoted strings don't process ASCII escape codes(\n, \t etc.), and they don't do [string interpolation][ruby-for-beginners.rubymonstas.org-interpolation] while double-quoted does both. + +You can also create strings using the [heredoc syntax][ruby-heredoc] or using the `%q` and `%Q` helpers. + +[ruby-for-beginners.rubymonstas.org-interpolation]: http://ruby-for-beginners.rubymonstas.org/bonus/string_interpolation.html +[ruby-doc.org-string]: https://ruby-doc.org/core-2.7.0/String.html +[ruby-heredoc]: https://www.rubyguides.com/2018/11/ruby-heredoc/ diff --git a/concepts/strings/introduction.md b/concepts/strings/introduction.md new file mode 100644 index 0000000000..b2515ab7bf --- /dev/null +++ b/concepts/strings/introduction.md @@ -0,0 +1 @@ +A `String` in Ruby is an object that holds and manipulates an arbitrary sequence of bytes, typically representing characters. Strings are manipulated by calling the string's methods. diff --git a/concepts/strings/links.json b/concepts/strings/links.json new file mode 100644 index 0000000000..55b943ee3c --- /dev/null +++ b/concepts/strings/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://ruby-doc.org/core-2.7.0/String.html", + "description": "ruby-doc.org-string" + }, + { + "url": "http://ruby-for-beginners.rubymonstas.org/bonus/string_interpolation.html", + "description": "ruby-for-beginners.rubymonstas.org-interpolation" + }, + { + "url": "https://www.rubyguides.com/2018/11/ruby-heredoc/", + "description": "ruby-heredoc" + } +] diff --git a/config.json b/config.json index 753f4e6390..5b905fb43f 100644 --- a/config.json +++ b/config.json @@ -1,1250 +1,1419 @@ { "language": "Ruby", + "slug": "ruby", "active": true, + "status": { + "concept_exercises": false, + "test_runner": false, + "representer": false, + "analyzer": false + }, "blurb": "Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.", + "version": 3, "gitter": "ruby", "solution_pattern": "[Ee]xample|\\.meta/solutions/[^/]*\\.rb", "online_editor": { "indent_style": "space", "indent_size": 2 }, - "exercises": [ - { - "slug": "hello-world", - "uuid": "4fe19484-4414-471b-a106-73c776c61388", - "core": true, - "auto_approve": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "strings" - ] - }, - { - "slug": "two-fer", - "uuid": "1304b188-6d08-4361-be40-c6b1b88e5e54", - "core": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "conditionals", - "strings" - ] - }, - { - "slug": "resistor-color-duo", - "uuid": "57b0c57e-26a5-4ccf-aaf2-2fefddd918c1", - "core": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "array", - "loops" - ] - }, - { - "slug": "acronym", - "uuid": "74468206-68a2-4efb-8caa-782634674c7f", - "core": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "regular_expressions", - "strings", - "transforming" - ] - }, - { - "slug": "high-scores", - "uuid": "9124339c-94fb-46eb-aad2-25944214799d", - "core": true, - "unlocked_by": null, - "difficulty": 2, - "topics": [ - "arrays" - ] - }, - { - "slug": "matrix", - "uuid": "3de21c18-a533-4150-8a73-49df8fcb8c61", - "core": true, - "unlocked_by": null, - "difficulty": 4, - "topics": [ - "arrays", - "exception_handling", - "matrices", - "strings", - "type_conversion" - ] - }, - { - "slug": "series", - "uuid": "2de036e4-576d-47fc-bb03-4ed1612e79da", - "core": true, - "unlocked_by": null, - "difficulty": 3, - "topics": [ - "arrays", - "enumerable", - "loops" - ] - }, - { - "slug": "word-count", - "uuid": "e9d29769-8d4d-4159-8d6f-762db5339707", - "core": true, - "unlocked_by": null, - "difficulty": 3, - "topics": [ - "enumerable", - "hash", - "loops" - ] - }, - { - "slug": "hamming", - "uuid": "d33dec8a-e2b4-40bc-8be9-3f49de084d43", - "core": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "equality", - "loops", - "strings" - ] - }, - { - "slug": "raindrops", - "uuid": "efad2cea-1e0b-4fb8-a452-a8e91be73638", - "core": true, - "unlocked_by": null, - "difficulty": 1, - "topics": [ - "conditionals", - "filtering", - "strings" - ] - }, - { - "slug": "isogram", - "uuid": "a79eb8cd-d2db-48f5-a7dc-055039dcee62", - "core": true, - "unlocked_by": null, - "difficulty": 2, - "topics": [ - "regular_expressions", - "sequences", - "strings" - ] - }, - { - "slug": "scrabble-score", - "uuid": "d934ebce-9ac3-4a41-bcb8-d70480170438", - "core": true, - "unlocked_by": null, - "difficulty": 2, - "topics": [ - "loops", - "maps", - "strings" - ] - }, - { - "slug": "luhn", - "uuid": "bee97539-b8c1-460e-aa14-9336008df2b6", - "core": true, - "unlocked_by": null, - "difficulty": 2, - "topics": [ - "algorithms", - "integers", - "strings" - ] - }, - { - "slug": "clock", - "uuid": "f95ebf09-0f32-4e60-867d-60cb81dd9a62", - "core": true, - "unlocked_by": null, - "difficulty": 3, - "topics": [ - "equality", - "text_formatting", - "time" - ] - }, - { - "slug": "twelve-days", - "uuid": "eeb64dda-b79f-4920-8fa3-04810e8d37ab", - "core": true, - "unlocked_by": null, - "difficulty": 4, - "topics": [ - "algorithms", - "pattern_recognition", - "sequences", - "strings", - "text_formatting" - ] - }, - { - "slug": "tournament", - "uuid": "486becee-9d85-4139-ab89-db254d385ade", - "core": true, - "unlocked_by": null, - "difficulty": 3, - "topics": [ - "integers", - "parsing", - "records", - "sorting", - "strings", - "text_formatting", - "transforming" - ] - }, - { - "slug": "armstrong-numbers", - "uuid": "77c5c7e6-265a-4f1a-9bc4-851f8f825420", - "core": false, - "unlocked_by": "series", - "difficulty": 3, - "topics": [ - "math" - ] - }, - { - "slug": "difference-of-squares", - "uuid": "f1e4ee0c-8718-43f2-90a5-fb1e915288da", - "core": false, - "unlocked_by": "matrix", - "difficulty": 2, - "topics": [ - "algorithms", - "math" - ] - }, - { - "slug": "gigasecond", - "uuid": "0fb594a1-193b-4ccf-8de2-eb6a81708b29", - "core": false, - "unlocked_by": "hello-world", - "difficulty": 1, - "topics": [ - "time" - ] - }, - { - "slug": "grains", - "uuid": "22519f53-4516-43bc-915e-07d58e48f617", - "core": false, - "unlocked_by": "series", - "difficulty": 4, - "topics": [ - "bitwise_operations", - "math" - ] - }, - { - "slug": "rna-transcription", - "uuid": "41f66d2a-1883-4a2c-875f-663c46fa88aa", - "core": false, - "unlocked_by": "two-fer", - "difficulty": 2, - "topics": [ - "maps", - "transforming" - ] - }, - { - "slug": "robot-name", - "uuid": "76a0fd0a-cc65-4be3-acc8-7348bb67ad5a", - "core": false, - "unlocked_by": "luhn", - "difficulty": 3, - "topics": [ - "randomness" - ] - }, - { - "slug": "pangram", - "uuid": "fcf07149-b2cb-4042-90e6-fb3350e0fdf6", - "core": false, - "unlocked_by": "acronym", - "difficulty": 2, - "topics": [ - "loops", - "strings" - ] - }, - { - "slug": "sieve", - "uuid": "80f9af5a-ea29-4937-9333-b4494aaf2446", - "core": false, - "unlocked_by": "hamming", - "difficulty": 3, - "topics": [ - "algorithms", - "integers", - "loops", - "math", - "sorting" - ] - }, - { - "slug": "roman-numerals", - "uuid": "b7ca9519-c33b-418b-a4ef-858a3d4d6855", - "core": false, - "unlocked_by": "clock", - "difficulty": 2, - "topics": [ - "numbers", - "transforming" - ] - }, - { - "slug": "nth-prime", - "uuid": "16baef71-6234-4928-a2d4-a19eb8e110b8", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 3, - "topics": [ - "algorithms", - "integers", - "math" - ] - }, - { - "slug": "leap", - "uuid": "06eaa2dd-dc80-4d38-b10d-11174183b0b6", - "core": false, - "unlocked_by": "resistor-color-duo", - "difficulty": 1, - "topics": [ - "booleans", - "conditionals", - "integers", - "logic" - ] - }, - { - "slug": "bob", - "uuid": "70fec82e-3038-468f-96ef-bfb48ce03ef3", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 2, - "topics": [ - "conditionals", - "strings" - ] - }, - { - "slug": "run-length-encoding", - "uuid": "9d6a8c89-41c1-4c4e-b24c-476ba0dfa5f9", - "core": false, - "unlocked_by": "isogram", - "difficulty": 4, - "topics": [ - "parsing", - "strings", - "transforming" - ] - }, - { - "slug": "binary", - "uuid": "43bc27ed-d2fa-4173-8665-4459b71c9a3a", - "core": false, - "unlocked_by": null, - "difficulty": 0, - "topics": null, - "deprecated": true - }, - { - "slug": "accumulate", - "uuid": "2c71fc3a-2c93-402b-b091-697b795ce3ba", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 1, - "topics": [ - "lists" - ] - }, - { - "slug": "sum-of-multiples", - "uuid": "4fc25295-5d6a-4d13-9b87-064167d8980e", - "core": false, - "unlocked_by": "matrix", - "difficulty": 5, - "topics": [ - "loops", - "math" - ] - }, - { - "slug": "grade-school", - "uuid": "4460742c-2beb-48d7-94e6-72ff13c68c71", - "core": false, - "unlocked_by": "luhn", - "difficulty": 5, - "topics": [ - "lists", - "sorting", - "structs" - ] - }, - { - "slug": "phone-number", - "uuid": "b68665d5-14ef-4351-ac4a-c28a80c27b3d", - "core": false, - "unlocked_by": "series", - "difficulty": 3, - "topics": [ - "conditionals", - "regular_expressions", - "strings", - "text_formatting", - "transforming" - ] - }, - { - "slug": "prime-factors", - "uuid": "a18daa31-88d3-45ba-84ca-f1d52fe23a79", - "core": false, - "unlocked_by": "clock", - "difficulty": 3, - "topics": [ - "algorithms", - "integers", - "math" - ] - }, - { - "slug": "strain", - "uuid": "ac0966a9-822b-45be-91d9-36f6706ea76f", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 2, - "topics": [ - "arrays", - "filtering", - "loops" - ] - }, - { - "slug": "etl", - "uuid": "0d66f3db-69a4-44b9-80be-9366f8b189ec", - "core": false, - "unlocked_by": "word-count", - "difficulty": 4, - "topics": [ - "loops", - "maps", - "transforming" - ] - }, - { - "slug": "trinary", - "uuid": "f6735416-4be6-4eb8-b6b9-cb61671ce25e", - "core": false, - "unlocked_by": null, - "difficulty": 0, - "topics": null, - "deprecated": true - }, - { - "slug": "beer-song", - "uuid": "50c34698-7767-42b3-962f-21c735e49787", - "core": false, - "unlocked_by": "scrabble-score", - "difficulty": 3, - "topics": [ - "loops", - "strings", - "text_formatting" - ] - }, - { - "slug": "bowling", - "uuid": "051f0825-8357-4ca6-b24f-40a373deac19", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 5, - "topics": [ - "algorithms", - "arrays", - "conditionals" - ] - }, - { - "slug": "space-age", - "uuid": "c971a2b5-ccd4-4e55-9fc7-33e991bc0676", - "core": false, - "unlocked_by": "acronym", - "difficulty": 2, - "topics": [ - "floating_point_numbers", - "if_else_statements" - ] - }, - { - "slug": "anagram", - "uuid": "36df18ba-580d-4982-984e-ba50eb1f8c0b", - "core": false, - "unlocked_by": "matrix", - "difficulty": 5, - "topics": [ - "filtering", - "parsing", - "sorting", - "strings" - ] - }, - { - "slug": "binary-search-tree", - "uuid": "0e05bfcf-17ae-4884-803a-fa1428bc1702", - "core": false, - "unlocked_by": "luhn", - "difficulty": 5, - "topics": [ - "algorithms", - "recursion", - "searching", - "sorting", - "structs", - "trees" - ] - }, - { - "slug": "crypto-square", - "uuid": "86f8e33d-31b7-43e3-8ea3-2e391133704a", - "core": false, - "unlocked_by": "luhn", - "difficulty": 3, - "topics": [ - "cryptography", - "filtering", - "strings", - "text_formatting", - "transforming" - ] - }, - { - "slug": "alphametics", - "uuid": "2323a2a5-c181-4c1e-9c5f-f6b92b2de511", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 5, - "topics": [ - "algorithms", - "arrays", - "searching" - ] - }, - { - "slug": "rail-fence-cipher", - "uuid": "64196fe5-2270-4113-a614-fbfbb6d00f2b", - "core": false, - "unlocked_by": "isogram", - "difficulty": 4, - "topics": [ - "algorithms", - "cryptography", - "loops", - "sorting", - "strings", - "text_formatting", - "transforming" - ] - }, - { - "slug": "nucleotide-count", - "uuid": "8ad2bffd-1d79-4e1f-8ef3-ece0214d2804", - "core": false, - "unlocked_by": "word-count", - "difficulty": 4, - "topics": [ - "maps", - "parsing", - "strings" - ] - }, - { - "slug": "flatten-array", - "uuid": "2df8ed82-2a04-4112-a17b-7813bcdc0e84", - "core": false, - "unlocked_by": "series", - "difficulty": 3, - "topics": [ - "arrays", - "recursion" - ] - }, - { - "slug": "hexadecimal", - "uuid": "6984cc14-91f8-47a7-b7e2-4b210a5dbc5c", - "core": false, - "unlocked_by": null, - "difficulty": 0, - "topics": null, - "deprecated": true - }, - { - "slug": "say", - "uuid": "2a410923-6445-41fc-9cf3-a60209e1c1c2", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 7, - "topics": [ - "numbers", - "strings", - "text_formatting", - "transforming" - ] - }, - { - "slug": "meetup", - "uuid": "8120e133-9561-4f82-8081-10c19f7f6ba3", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 3, - "topics": [ - "dates", - "time", - "transforming", - "type_conversion" - ] - }, - { - "slug": "queen-attack", - "uuid": "2ce9b158-e730-4c86-8639-bd08af9f80f4", - "core": false, - "unlocked_by": "tournament", - "difficulty": 5, - "topics": [ - "booleans", - "errors", - "games", - "logic" - ] - }, - { - "slug": "palindrome-products", - "uuid": "abd68340-91b9-48c1-8567-79822bb2165c", - "core": false, - "unlocked_by": "hamming", - "difficulty": 6, - "topics": [ - "algorithms", - "math" - ] - }, - { - "slug": "matching-brackets", - "uuid": "26f6e297-7980-4472-8ce7-157b62b0ff40", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 7, - "topics": [ - "parsing", - "strings" - ] - }, - { - "slug": "food-chain", - "uuid": "6f0919eb-2160-4cca-8504-286acc2ae9c8", - "core": false, - "unlocked_by": "tournament", - "difficulty": 4, - "topics": [ - "conditionals", - "loops", - "recursion", - "strings", - "text_formatting" - ] - }, - { - "slug": "saddle-points", - "uuid": "38bb4ac6-a5ec-4448-8b86-cdaff13a8be3", - "core": false, - "unlocked_by": "series", - "difficulty": 5, - "topics": [ - "arrays", - "integers", - "matrices", - "searching" - ] - }, - { - "slug": "triangle", - "uuid": "5c797eb2-155d-47ca-8f85-2ba5803f9713", - "core": false, - "unlocked_by": "high-scores", - "difficulty": 3, - "topics": [ - "booleans", - "conditionals", - "logic" - ] - }, - { - "slug": "atbash-cipher", - "uuid": "1e737640-9785-4a47-866a-46298104d891", - "core": false, - "unlocked_by": "luhn", - "difficulty": 3, - "topics": [ - "algorithms", - "cryptography", - "strings", - "transforming" - ] - }, - { - "slug": "house", - "uuid": "df5d771a-e57b-4a96-8a29-9bd4ce7f88d2", - "core": false, - "unlocked_by": "clock", - "difficulty": 4, - "topics": [ - "recursion", - "strings", - "text_formatting" - ] - }, - { - "slug": "secret-handshake", - "uuid": "c1ebad1b-d5aa-465a-b5ef-9e717ab5db9e", - "core": false, - "unlocked_by": "scrabble-score", - "difficulty": 5, - "topics": [ - "arrays", - "bitwise_operations", - "integers" - ] - }, - { - "slug": "proverb", - "uuid": "3c5193ab-6471-4be2-9d24-1d2b51ad822a", - "core": false, - "unlocked_by": "hamming", - "difficulty": 4, - "topics": [ - "arrays", - "loops", - "strings" - ] - }, - { - "slug": "ocr-numbers", - "uuid": "dd13bb29-589c-497d-9580-3f288f353fb2", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 7, - "topics": [ - "parsing", - "pattern_recognition" - ] - }, - { - "slug": "pig-latin", - "uuid": "efc0e498-891a-4e91-a6aa-fae635573a83", - "core": false, - "unlocked_by": "luhn", - "difficulty": 4, - "topics": [ - "conditionals", - "strings", - "transforming" - ] - }, - { - "slug": "simple-linked-list", - "uuid": "fa7b91c2-842c-42c8-bdf9-00bb3e71a7f5", - "core": false, - "unlocked_by": "luhn", - "difficulty": 4, - "topics": [ - "arrays", - "loops" - ] - }, - { - "slug": "simple-cipher", - "uuid": "29c66e8a-b1b0-4bbd-be7b-9979ff51ba8f", - "core": false, - "unlocked_by": "luhn", - "difficulty": 3, - "topics": [ - "algorithms", - "cryptography", - "interfaces", - "strings", - "transforming" - ] - }, - { - "slug": "wordy", - "uuid": "cb58e4cf-e3af-469c-9f2d-02557b9f61ed", - "core": false, - "unlocked_by": "scrabble-score", - "difficulty": 3, - "topics": [ - "conditionals", - "integers", - "parsing", - "strings", - "type_conversion" - ] - }, - { - "slug": "allergies", - "uuid": "b306bdaa-438e-46a2-ba54-82cb2c0be882", - "core": false, - "unlocked_by": "isogram", - "difficulty": 4, - "topics": [ - "bitwise_operations", - "enumeration" - ] - }, - { - "slug": "poker", - "uuid": "9a59ba44-34f5-410b-a1e6-9a5c47c52d9e", - "core": false, - "unlocked_by": "clock", - "difficulty": 5, - "topics": [ - "equality", - "games", - "parsing", - "pattern_matching", - "sequences", - "strings" - ] - }, - { - "slug": "kindergarten-garden", - "uuid": "04bde625-e363-4d8b-880f-db7bf86286eb", - "core": false, - "unlocked_by": "clock", - "difficulty": 3, - "topics": [ - "parsing", - "records", - "searching", - "strings", - "structs" - ] - }, - { - "slug": "largest-series-product", - "uuid": "7cb55328-1b11-4544-94c0-945444d9a6a4", - "core": false, - "unlocked_by": "clock", - "difficulty": 3, - "topics": [ - "algorithms", - "integers", - "math", - "sequences" - ] - }, - { - "slug": "pythagorean-triplet", - "uuid": "43aad536-0e24-464c-9554-cbc2699d0543", - "core": false, - "unlocked_by": "word-count", - "difficulty": 5, - "topics": [ - "algorithms", - "math" - ] - }, - { - "slug": "scale-generator", - "uuid": "4134d491-8ec5-480b-aa61-37a02689db1f", - "core": false, - "unlocked_by": "isogram", - "difficulty": 3, - "topics": [ - "pattern_matching", - "strings" - ] - }, - { - "slug": "protein-translation", - "uuid": "00c6f623-2e54-4f90-ae3f-07e493f93c7c", - "core": false, - "unlocked_by": "scrabble-score", - "difficulty": 3, - "topics": [ - "filtering", - "maps", - "sequences" - ] - }, - { - "slug": "perfect-numbers", - "uuid": "76ad732a-6e58-403b-ac65-9091d355241f", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 4, - "topics": [ - "algorithms", - "filtering", - "integers", - "math" - ] - }, - { - "slug": "circular-buffer", - "uuid": "f3419fe3-a5f5-4bc9-bc40-49f450b8981e", - "core": false, - "unlocked_by": "luhn", - "difficulty": 5, - "topics": [ - "queues", - "structs" - ] - }, - { - "slug": "diamond", - "uuid": "c55c75fb-6140-4042-967a-39c75b7781bd", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 4, - "topics": [ - "algorithms", - "conditionals", - "loops", - "strings", - "text_formatting" - ] - }, - { - "slug": "custom-set", - "uuid": "4f74b3cd-f995-4b8c-9b57-23f073261d0e", - "core": false, - "unlocked_by": "clock", - "difficulty": 4, - "topics": [ - "filtering", - "loops", - "sets" - ] - }, - { - "slug": "transpose", - "uuid": "4a6bc7d3-5d3b-4ad8-96ae-783e17af7c32", - "core": false, - "unlocked_by": "matrix", - "difficulty": 5, - "topics": [ - "loops", - "strings", - "transforming" - ] - }, - { - "slug": "pascals-triangle", - "uuid": "4ff8b056-f27d-4bdf-b7af-214448db4260", - "core": false, - "unlocked_by": "tournament", - "difficulty": 4, - "topics": [ - "algorithms", - "arrays", - "math", - "recursion" - ] - }, - { - "slug": "linked-list", - "uuid": "92c9aafc-791d-4aaf-a136-9bee14f6ff95", - "core": false, - "unlocked_by": "clock", - "difficulty": 4, - "topics": [ - "data_structure", - "pointer" - ] - }, - { - "slug": "binary-search", - "uuid": "b1ba445d-4908-4922-acc0-de3a0ec92c53", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 5, - "topics": [ - "algorithms", - "arrays", - "searching", - "sorting" - ] - }, - { - "slug": "minesweeper", - "uuid": "9d6808fb-d367-4df9-a1f0-47ff83b75544", - "core": false, - "unlocked_by": "isogram", - "difficulty": 5, - "topics": [ - "arrays", - "games", - "loops", - "matrices", - "transforming" - ] - }, - { - "slug": "robot-simulator", - "uuid": "724e6a6e-2e6e-45a9-ab0e-0d8d50a06085", - "core": false, - "unlocked_by": "isogram", - "difficulty": 6, - "topics": [ - "concurrency", - "loops", - "sequences", - "strings", - "structs" - ] - }, - { - "slug": "all-your-base", - "uuid": "3ce4bd3e-0380-498a-8d0a-b79cf3fedc10", - "core": false, - "unlocked_by": "isogram", - "difficulty": 3, - "topics": [ - "integers", - "math", - "transforming" - ] - }, - { - "slug": "connect", - "uuid": "538a6768-bae5-437c-9cdf-765d73a79643", - "core": false, - "unlocked_by": "tournament", - "difficulty": 9, - "topics": [ - "arrays", - "games", - "graphs", - "loops", - "searching" - ] - }, - { - "slug": "change", - "uuid": "dc6c3e44-1027-4d53-9653-ba06824f8bcf", - "core": false, - "unlocked_by": "luhn", - "difficulty": 5, - "topics": [ - "algorithms", - "arrays", - "loops", - "searching" - ] - }, - { - "slug": "collatz-conjecture", - "uuid": "af961c87-341c-4dd3-a1eb-272501b9b0e4", - "core": false, - "unlocked_by": "hamming", - "difficulty": 1, - "topics": [ - "conditionals", - "control_flow_loops", - "integers", - "math" - ] - }, - { - "slug": "book-store", - "uuid": "0ec96460-08be-49a0-973a-4336f21b763c", - "core": false, - "unlocked_by": "tournament", - "difficulty": 8, - "topics": [ - "algorithms", - "floating_point_numbers", - "integers", - "lists" - ] - }, - { - "slug": "rotational-cipher", - "uuid": "af5ccf14-eff2-4dc6-b1db-e209cddca62a", - "core": false, - "unlocked_by": "clock", - "difficulty": 2, - "topics": [ - "cryptography", - "integers", - "strings" - ] - }, - { - "slug": "isbn-verifier", - "uuid": "a0aac827-8f7a-4065-9d05-a57009f5668d", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 2, - "topics": [ - "arrays" - ] - }, - { - "slug": "dominoes", - "uuid": "705f3eb6-55a9-476c-b3f2-e9f3cb0bbe37", - "core": false, - "unlocked_by": "luhn", - "difficulty": 4, - "topics": [ - "algorithms", - "arrays", - "searching" - ] - }, + "exercises": { + "concept": [ + { + "slug": "arrays", + "uuid": "4d271980-ab4b-11ea-bb37-0242ac130002", + "concepts": [ + "arrays" + ], + "prerequisites": [ + "classes", + "booleans", + "conditionals", + "blocks" + ], + "status": "wip" + }, + { + "slug": "strings", + "uuid": "e5476046-5289-11ea-8d77-2e728ce88125", + "concepts": [ + "strings" + ], + "prerequisites": [ + "basics" + ], + "status": "wip" + }, + { + "slug": "lasagna", + "uuid": "71ae39c4-7364-11ea-bc55-0242ac130003", + "concepts": [ + "basics" + ], + "prerequisites": [], + "status": "wip" + }, + { + "slug": "numbers", + "uuid": "d7108eb2-326c-446d-9140-228e0f220975", + "concepts": [ + "numbers", + "conditionals" + ], + "prerequisites": [ + "booleans" + ], + "status": "wip" + }, + { + "slug": "floating-point-numbers", + "uuid": "970d3f26-1891-40c7-9550-42d529f5780f", + "concepts": [ + "floating-point-numbers", + "loops" + ], + "prerequisites": [ + "numbers", + "conditionals" + ], + "status": "wip" + }, + { + "slug": "amusement_park_rides", + "uuid": "06ea7869-4907-454d-a5e5-9d5b71098b17", + "concepts": [ + "booleans" + ], + "prerequisites": [ + "instance-variables" + ], + "status": "wip" + }, + { + "slug": "instance-variables", + "uuid": "6905e411-ae01-46b6-a31c-8867b768856e", + "concepts": [ + "instance-variables", + "nil" + ], + "prerequisites": [ + "basics" + ], + "status": "wip" + } + ], + "practice": [ + { + "slug": "hello-world", + "name": "Hello World", + "uuid": "4fe19484-4414-471b-a106-73c776c61388", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "strings" + ] + }, + { + "slug": "two-fer", + "name": "Two Fer", + "uuid": "1304b188-6d08-4361-be40-c6b1b88e5e54", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "conditionals", + "strings" + ] + }, + { + "slug": "resistor-color-duo", + "name": "Resistor Color Duo", + "uuid": "57b0c57e-26a5-4ccf-aaf2-2fefddd918c1", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "array", + "loops" + ] + }, + { + "slug": "acronym", + "name": "Acronym", + "uuid": "74468206-68a2-4efb-8caa-782634674c7f", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "regular_expressions", + "strings", + "transforming" + ] + }, + { + "slug": "high-scores", + "name": "High Scores", + "uuid": "9124339c-94fb-46eb-aad2-25944214799d", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "arrays" + ] + }, + { + "slug": "matrix", + "name": "Matrix", + "uuid": "3de21c18-a533-4150-8a73-49df8fcb8c61", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "arrays", + "exception_handling", + "matrices", + "strings", + "type_conversion" + ] + }, + { + "slug": "series", + "name": "Series", + "uuid": "2de036e4-576d-47fc-bb03-4ed1612e79da", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "arrays", + "enumerable", + "loops" + ] + }, + { + "slug": "word-count", + "name": "Word Count", + "uuid": "e9d29769-8d4d-4159-8d6f-762db5339707", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "enumerable", + "hash", + "loops" + ] + }, + { + "slug": "hamming", + "name": "Hamming", + "uuid": "d33dec8a-e2b4-40bc-8be9-3f49de084d43", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "equality", + "loops", + "strings" + ] + }, + { + "slug": "raindrops", + "name": "Raindrops", + "uuid": "efad2cea-1e0b-4fb8-a452-a8e91be73638", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "conditionals", + "filtering", + "strings" + ] + }, + { + "slug": "isogram", + "name": "Isogram", + "uuid": "a79eb8cd-d2db-48f5-a7dc-055039dcee62", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "regular_expressions", + "sequences", + "strings" + ] + }, + { + "slug": "scrabble-score", + "name": "Scrabble Score", + "uuid": "d934ebce-9ac3-4a41-bcb8-d70480170438", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "loops", + "maps", + "strings" + ] + }, + { + "slug": "luhn", + "name": "Luhn", + "uuid": "bee97539-b8c1-460e-aa14-9336008df2b6", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "algorithms", + "integers", + "strings" + ] + }, + { + "slug": "clock", + "name": "Clock", + "uuid": "f95ebf09-0f32-4e60-867d-60cb81dd9a62", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "equality", + "text_formatting", + "time" + ] + }, + { + "slug": "twelve-days", + "name": "Twelve Days", + "uuid": "eeb64dda-b79f-4920-8fa3-04810e8d37ab", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "pattern_recognition", + "sequences", + "strings", + "text_formatting" + ] + }, + { + "slug": "tournament", + "name": "Tournament", + "uuid": "486becee-9d85-4139-ab89-db254d385ade", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "integers", + "parsing", + "records", + "sorting", + "strings", + "text_formatting", + "transforming" + ] + }, + { + "slug": "gigasecond", + "name": "Gigasecond", + "uuid": "0fb594a1-193b-4ccf-8de2-eb6a81708b29", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "time" + ] + }, + { + "slug": "resistor-color", + "name": "Resistor Color", + "uuid": "685634dd-0b38-40bc-b0ad-e8aa2904035f", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "arrays" + ] + }, + { + "slug": "rna-transcription", + "name": "Rna Transcription", + "uuid": "41f66d2a-1883-4a2c-875f-663c46fa88aa", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "maps", + "transforming" + ] + }, + { + "slug": "leap", + "name": "Leap", + "uuid": "06eaa2dd-dc80-4d38-b10d-11174183b0b6", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "booleans", + "conditionals", + "integers", + "logic" + ] + }, + { + "slug": "pangram", + "name": "Pangram", + "uuid": "fcf07149-b2cb-4042-90e6-fb3350e0fdf6", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "loops", + "strings" + ] + }, + { + "slug": "space-age", + "name": "Space Age", + "uuid": "c971a2b5-ccd4-4e55-9fc7-33e991bc0676", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "floating_point_numbers", + "if_else_statements" + ] + }, + { + "slug": "triangle", + "name": "Triangle", + "uuid": "5c797eb2-155d-47ca-8f85-2ba5803f9713", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "booleans", + "conditionals", + "logic" + ] + }, + { + "slug": "difference-of-squares", + "name": "Difference Of Squares", + "uuid": "f1e4ee0c-8718-43f2-90a5-fb1e915288da", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "algorithms", + "math" + ] + }, + { + "slug": "anagram", + "name": "Anagram", + "uuid": "36df18ba-580d-4982-984e-ba50eb1f8c0b", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "filtering", + "parsing", + "sorting", + "strings" + ] + }, + { + "slug": "sum-of-multiples", + "name": "Sum Of Multiples", + "uuid": "4fc25295-5d6a-4d13-9b87-064167d8980e", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "loops", + "math" + ] + }, + { + "slug": "transpose", + "name": "Transpose", + "uuid": "4a6bc7d3-5d3b-4ad8-96ae-783e17af7c32", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "loops", + "strings", + "transforming" + ] + }, + { + "slug": "armstrong-numbers", + "name": "Armstrong Numbers", + "uuid": "77c5c7e6-265a-4f1a-9bc4-851f8f825420", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "math" + ] + }, + { + "slug": "flatten-array", + "name": "Flatten Array", + "uuid": "2df8ed82-2a04-4112-a17b-7813bcdc0e84", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "arrays", + "recursion" + ] + }, + { + "slug": "phone-number", + "name": "Phone Number", + "uuid": "b68665d5-14ef-4351-ac4a-c28a80c27b3d", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "conditionals", + "regular_expressions", + "strings", + "text_formatting", + "transforming" + ] + }, + { + "slug": "grains", + "name": "Grains", + "uuid": "22519f53-4516-43bc-915e-07d58e48f617", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "bitwise_operations", + "math" + ] + }, + { + "slug": "resistor-color-trio", + "name": "Resistor Color Trio", + "uuid": "2df14b68-75c8-4984-8ae2-ecd2cb7ed1d4", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "loops" + ] + }, + { + "slug": "saddle-points", + "name": "Saddle Points", + "uuid": "38bb4ac6-a5ec-4448-8b86-cdaff13a8be3", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "arrays", + "integers", + "matrices", + "searching" + ] + }, + { + "slug": "etl", + "name": "Etl", + "uuid": "0d66f3db-69a4-44b9-80be-9366f8b189ec", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "loops", + "maps", + "transforming" + ] + }, + { + "slug": "nucleotide-count", + "name": "Nucleotide Count", + "uuid": "8ad2bffd-1d79-4e1f-8ef3-ece0214d2804", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "maps", + "parsing", + "strings" + ] + }, + { + "slug": "pythagorean-triplet", + "name": "Pythagorean Triplet", + "uuid": "43aad536-0e24-464c-9554-cbc2699d0543", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "math" + ] + }, + { + "slug": "collatz-conjecture", + "name": "Collatz Conjecture", + "uuid": "af961c87-341c-4dd3-a1eb-272501b9b0e4", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "conditionals", + "control_flow_loops", + "integers", + "math" + ] + }, + { + "slug": "sieve", + "name": "Sieve", + "uuid": "80f9af5a-ea29-4937-9333-b4494aaf2446", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "integers", + "loops", + "math", + "sorting" + ] + }, + { + "slug": "proverb", + "name": "Proverb", + "uuid": "3c5193ab-6471-4be2-9d24-1d2b51ad822a", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "arrays", + "loops", + "strings" + ] + }, + { + "slug": "palindrome-products", + "name": "Palindrome Products", + "uuid": "abd68340-91b9-48c1-8567-79822bb2165c", + "prerequisites": [], + "difficulty": 6, + "topics": [ + "algorithms", + "math" + ] + }, + { + "slug": "accumulate", + "name": "Accumulate", + "uuid": "2c71fc3a-2c93-402b-b091-697b795ce3ba", + "prerequisites": [], + "difficulty": 1, + "topics": [ + "lists" + ] + }, + { + "slug": "bob", + "name": "Bob", + "uuid": "70fec82e-3038-468f-96ef-bfb48ce03ef3", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "conditionals", + "strings" + ] + }, + { + "slug": "strain", + "name": "Strain", + "uuid": "ac0966a9-822b-45be-91d9-36f6706ea76f", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "arrays", + "filtering", + "loops" + ] + }, + { + "slug": "nth-prime", + "name": "Nth Prime", + "uuid": "16baef71-6234-4928-a2d4-a19eb8e110b8", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "integers", + "math" + ] + }, + { + "slug": "perfect-numbers", + "name": "Perfect Numbers", + "uuid": "76ad732a-6e58-403b-ac65-9091d355241f", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "filtering", + "integers", + "math" + ] + }, + { + "slug": "alphametics", + "name": "Alphametics", + "uuid": "2323a2a5-c181-4c1e-9c5f-f6b92b2de511", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "arrays", + "searching" + ] + }, + { + "slug": "binary-search", + "name": "Binary Search", + "uuid": "b1ba445d-4908-4922-acc0-de3a0ec92c53", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "arrays", + "searching", + "sorting" + ] + }, + { + "slug": "two-bucket", + "name": "Two Bucket", + "uuid": "e5a2d445-437d-46a8-889b-fbcd62c70fa9", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "conditionals", + "searching" + ] + }, + { + "slug": "matching-brackets", + "name": "Matching Brackets", + "uuid": "26f6e297-7980-4472-8ce7-157b62b0ff40", + "prerequisites": [], + "difficulty": 7, + "topics": [ + "parsing", + "strings" + ] + }, + { + "slug": "all-your-base", + "name": "All Your Base", + "uuid": "3ce4bd3e-0380-498a-8d0a-b79cf3fedc10", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "integers", + "math", + "transforming" + ] + }, + { + "slug": "scale-generator", + "name": "Scale Generator", + "uuid": "4134d491-8ec5-480b-aa61-37a02689db1f", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "pattern_matching", + "strings" + ] + }, + { + "slug": "allergies", + "name": "Allergies", + "uuid": "b306bdaa-438e-46a2-ba54-82cb2c0be882", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "bitwise_operations", + "enumeration" + ] + }, + { + "slug": "rail-fence-cipher", + "name": "Rail Fence Cipher", + "uuid": "64196fe5-2270-4113-a614-fbfbb6d00f2b", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "cryptography", + "loops", + "sorting", + "strings", + "text_formatting", + "transforming" + ] + }, + { + "slug": "run-length-encoding", + "name": "Run Length Encoding", + "uuid": "9d6a8c89-41c1-4c4e-b24c-476ba0dfa5f9", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "parsing", + "strings", + "transforming" + ] + }, + { + "slug": "minesweeper", + "name": "Minesweeper", + "uuid": "9d6808fb-d367-4df9-a1f0-47ff83b75544", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "arrays", + "games", + "loops", + "matrices", + "transforming" + ] + }, + { + "slug": "robot-simulator", + "name": "Robot Simulator", + "uuid": "724e6a6e-2e6e-45a9-ab0e-0d8d50a06085", + "prerequisites": [], + "difficulty": 6, + "topics": [ + "concurrency", + "loops", + "sequences", + "strings", + "structs" + ] + }, + { + "slug": "beer-song", + "name": "Beer Song", + "uuid": "50c34698-7767-42b3-962f-21c735e49787", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "loops", + "strings", + "text_formatting" + ] + }, + { + "slug": "protein-translation", + "name": "Protein Translation", + "uuid": "00c6f623-2e54-4f90-ae3f-07e493f93c7c", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "filtering", + "maps", + "sequences" + ] + }, + { + "slug": "wordy", + "name": "Wordy", + "uuid": "cb58e4cf-e3af-469c-9f2d-02557b9f61ed", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "conditionals", + "integers", + "parsing", + "strings", + "type_conversion" + ] + }, + { + "slug": "secret-handshake", + "name": "Secret Handshake", + "uuid": "c1ebad1b-d5aa-465a-b5ef-9e717ab5db9e", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "arrays", + "bitwise_operations", + "integers" + ] + }, + { + "slug": "atbash-cipher", + "name": "Atbash Cipher", + "uuid": "1e737640-9785-4a47-866a-46298104d891", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "cryptography", + "strings", + "transforming" + ] + }, + { + "slug": "crypto-square", + "name": "Crypto Square", + "uuid": "86f8e33d-31b7-43e3-8ea3-2e391133704a", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "cryptography", + "filtering", + "strings", + "text_formatting", + "transforming" + ] + }, + { + "slug": "list-ops", + "name": "List Ops", + "uuid": "f62e8acb-8370-46e1-ad7f-a6a2644f8602", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "functional_programming", + "lists", + "recursion", + "type_conversion" + ] + }, + { + "slug": "robot-name", + "name": "Robot Name", + "uuid": "76a0fd0a-cc65-4be3-acc8-7348bb67ad5a", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "randomness" + ] + }, + { + "slug": "simple-cipher", + "name": "Simple Cipher", + "uuid": "29c66e8a-b1b0-4bbd-be7b-9979ff51ba8f", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "cryptography", + "interfaces", + "strings", + "transforming" + ] + }, + { + "slug": "dominoes", + "name": "Dominoes", + "uuid": "705f3eb6-55a9-476c-b3f2-e9f3cb0bbe37", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "arrays", + "searching" + ] + }, + { + "slug": "pig-latin", + "name": "Pig Latin", + "uuid": "efc0e498-891a-4e91-a6aa-fae635573a83", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "conditionals", + "strings", + "transforming" + ] + }, + { + "slug": "simple-linked-list", + "name": "Simple Linked List", + "uuid": "fa7b91c2-842c-42c8-bdf9-00bb3e71a7f5", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "arrays", + "loops" + ] + }, + { + "slug": "binary-search-tree", + "name": "Binary Search Tree", + "uuid": "0e05bfcf-17ae-4884-803a-fa1428bc1702", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "recursion", + "searching", + "sorting", + "structs", + "trees" + ] + }, + { + "slug": "change", + "name": "Change", + "uuid": "dc6c3e44-1027-4d53-9653-ba06824f8bcf", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "arrays", + "loops", + "searching" + ] + }, + { + "slug": "circular-buffer", + "name": "Circular Buffer", + "uuid": "f3419fe3-a5f5-4bc9-bc40-49f450b8981e", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "queues", + "structs" + ] + }, + { + "slug": "grade-school", + "name": "Grade School", + "uuid": "4460742c-2beb-48d7-94e6-72ff13c68c71", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "lists", + "sorting", + "structs" + ] + }, + { + "slug": "roman-numerals", + "name": "Roman Numerals", + "uuid": "b7ca9519-c33b-418b-a4ef-858a3d4d6855", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "numbers", + "transforming" + ] + }, + { + "slug": "rotational-cipher", + "name": "Rotational Cipher", + "uuid": "af5ccf14-eff2-4dc6-b1db-e209cddca62a", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "cryptography", + "integers", + "strings" + ] + }, + { + "slug": "affine-cipher", + "name": "Affine Cipher", + "uuid": "d1267415-aff5-411d-b267-49a4a2c8fda2", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "cryptography", + "math", + "strings" + ] + }, + { + "slug": "kindergarten-garden", + "name": "Kindergarten Garden", + "uuid": "04bde625-e363-4d8b-880f-db7bf86286eb", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "parsing", + "records", + "searching", + "strings", + "structs" + ] + }, + { + "slug": "largest-series-product", + "name": "Largest Series Product", + "uuid": "7cb55328-1b11-4544-94c0-945444d9a6a4", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "integers", + "math", + "sequences" + ] + }, + { + "slug": "prime-factors", + "name": "Prime Factors", + "uuid": "a18daa31-88d3-45ba-84ca-f1d52fe23a79", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "algorithms", + "integers", + "math" + ] + }, + { + "slug": "custom-set", + "name": "Custom Set", + "uuid": "4f74b3cd-f995-4b8c-9b57-23f073261d0e", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "filtering", + "loops", + "sets" + ] + }, + { + "slug": "house", + "name": "House", + "uuid": "df5d771a-e57b-4a96-8a29-9bd4ce7f88d2", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "recursion", + "strings", + "text_formatting" + ] + }, + { + "slug": "linked-list", + "name": "Linked List", + "uuid": "92c9aafc-791d-4aaf-a136-9bee14f6ff95", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "data_structure", + "pointer" + ] + }, + { + "slug": "poker", + "name": "Poker", + "uuid": "9a59ba44-34f5-410b-a1e6-9a5c47c52d9e", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "equality", + "games", + "parsing", + "pattern_matching", + "sequences", + "strings" + ] + }, + { + "slug": "isbn-verifier", + "name": "Isbn Verifier", + "uuid": "a0aac827-8f7a-4065-9d05-a57009f5668d", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "arrays" + ] + }, + { + "slug": "complex-numbers", + "name": "Complex Numbers", + "uuid": "d75bd7c0-52c5-44f2-a046-f63cb332425f", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "math" + ] + }, + { + "slug": "meetup", + "name": "Meetup", + "uuid": "8120e133-9561-4f82-8081-10c19f7f6ba3", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "dates", + "time", + "transforming", + "type_conversion" + ] + }, + { + "slug": "diamond", + "name": "Diamond", + "uuid": "c55c75fb-6140-4042-967a-39c75b7781bd", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "conditionals", + "loops", + "strings", + "text_formatting" + ] + }, + { + "slug": "bowling", + "name": "Bowling", + "uuid": "051f0825-8357-4ca6-b24f-40a373deac19", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "algorithms", + "arrays", + "conditionals" + ] + }, + { + "slug": "ocr-numbers", + "name": "Ocr Numbers", + "uuid": "dd13bb29-589c-497d-9580-3f288f353fb2", + "prerequisites": [], + "difficulty": 7, + "topics": [ + "parsing", + "pattern_recognition" + ] + }, + { + "slug": "say", + "name": "Say", + "uuid": "2a410923-6445-41fc-9cf3-a60209e1c1c2", + "prerequisites": [], + "difficulty": 7, + "topics": [ + "numbers", + "strings", + "text_formatting", + "transforming" + ] + }, + { + "slug": "zipper", + "name": "Zipper", + "uuid": "239b8e79-2983-4ce0-9dda-9bb999e79d11", + "prerequisites": [], + "difficulty": 7, + "topics": [ + "data_structures" + ] + }, + { + "slug": "grep", + "name": "Grep", + "uuid": "99485900-5d16-4848-af1c-2f1a62ad35ab", + "prerequisites": [], + "difficulty": 8, + "topics": [ + "files", + "parsing", + "pattern_matching", + "regular_expressions", + "strings", + "text_formatting" + ] + }, + { + "slug": "food-chain", + "name": "Food Chain", + "uuid": "6f0919eb-2160-4cca-8504-286acc2ae9c8", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "conditionals", + "loops", + "recursion", + "strings", + "text_formatting" + ] + }, + { + "slug": "pascals-triangle", + "name": "Pascals Triangle", + "uuid": "4ff8b056-f27d-4bdf-b7af-214448db4260", + "prerequisites": [], + "difficulty": 4, + "topics": [ + "algorithms", + "arrays", + "math", + "recursion" + ] + }, + { + "slug": "queen-attack", + "name": "Queen Attack", + "uuid": "2ce9b158-e730-4c86-8639-bd08af9f80f4", + "prerequisites": [], + "difficulty": 5, + "topics": [ + "booleans", + "errors", + "games", + "logic" + ] + }, + { + "slug": "book-store", + "name": "Book Store", + "uuid": "0ec96460-08be-49a0-973a-4336f21b763c", + "prerequisites": [], + "difficulty": 8, + "topics": [ + "algorithms", + "floating_point_numbers", + "integers", + "lists" + ] + }, + { + "slug": "connect", + "name": "Connect", + "uuid": "538a6768-bae5-437c-9cdf-765d73a79643", + "prerequisites": [], + "difficulty": 9, + "topics": [ + "arrays", + "games", + "graphs", + "loops", + "searching" + ] + }, + { + "slug": "binary", + "name": "Binary", + "uuid": "43bc27ed-d2fa-4173-8665-4459b71c9a3a", + "prerequisites": [], + "difficulty": 0, + "topics": null, + "status": "deprecated" + }, + { + "slug": "hexadecimal", + "name": "Hexadecimal", + "uuid": "6984cc14-91f8-47a7-b7e2-4b210a5dbc5c", + "prerequisites": [], + "difficulty": 0, + "topics": null, + "status": "deprecated" + }, + { + "slug": "octal", + "name": "Octal", + "uuid": "cae4e000-3aac-41f7-b727-f9cce12d058d", + "prerequisites": [], + "difficulty": 0, + "topics": null, + "status": "deprecated" + }, + { + "slug": "point-mutations", + "name": "Point Mutations", + "uuid": "89bd3d71-000f-4cd9-9a84-ad1b22ddbd33", + "prerequisites": [], + "difficulty": 0, + "topics": null, + "status": "deprecated" + }, + { + "slug": "trinary", + "name": "Trinary", + "uuid": "f6735416-4be6-4eb8-b6b9-cb61671ce25e", + "prerequisites": [], + "difficulty": 0, + "topics": null, + "status": "deprecated" + }, + { + "slug": "microwave", + "name": "Microwave", + "uuid": "b960d0fe-a07f-11ea-bb37-0242ac130002", + "prerequisites": [], + "difficulty": 2, + "topics": [ + "math", + "strings", + "interpolation" + ] + }, + { + "slug": "darts", + "name": "Darts", + "uuid": "15b73808-78a4-4854-b7cf-82a478107024", + "prerequisites": [], + "difficulty": 3, + "topics": [ + "math", + "geometry" + ] + } + ] + }, + "concepts": [ { - "slug": "two-bucket", - "uuid": "e5a2d445-437d-46a8-889b-fbcd62c70fa9", - "core": false, - "unlocked_by": "raindrops", - "difficulty": 5, - "topics": [ - "algorithms", - "conditionals", - "searching" - ] + "uuid": "7f2bf3a7-9771-48e8-bb6a-3022ca073a41", + "slug": "arrays", + "name": "Arrays", + "blurb": "TODO: add blurb for arrays concept" }, { - "slug": "list-ops", - "uuid": "f62e8acb-8370-46e1-ad7f-a6a2644f8602", - "core": false, - "unlocked_by": "luhn", - "difficulty": 3, - "topics": [ - "functional_programming", - "lists", - "recursion", - "type_conversion" - ] + "uuid": "fe345fe6-229b-4b4b-a489-4ed3b77a1d7e", + "slug": "basics", + "name": "Basics", + "blurb": "TODO: add blurb for basics concept" }, { - "slug": "octal", - "uuid": "cae4e000-3aac-41f7-b727-f9cce12d058d", - "core": false, - "unlocked_by": null, - "difficulty": 0, - "topics": null, - "deprecated": true + "uuid": "bf57350d-9e18-4ec6-9341-e4d2c289724d", + "slug": "blocks", + "name": "Blocks", + "blurb": "TODO: add blurb for blocks concept" }, { - "slug": "affine-cipher", - "uuid": "d1267415-aff5-411d-b267-49a4a2c8fda2", - "core": false, - "unlocked_by": "clock", - "difficulty": 3, - "topics": [ - "cryptography", - "math", - "strings" - ] + "uuid": "831b4db4-6b75-4a8d-a835-4c2555aacb61", + "slug": "booleans", + "name": "Booleans", + "blurb": "TODO: add blurb for booleans concept" }, { - "slug": "complex-numbers", - "uuid": "d75bd7c0-52c5-44f2-a046-f63cb332425f", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 3, - "topics": [ - "math" - ] + "uuid": "acec3b2a-c1cc-4583-bd4b-9f7ae41acfb3", + "slug": "classes", + "name": "Classes", + "blurb": "TODO: add blurb for classes concept" }, { - "slug": "point-mutations", - "uuid": "89bd3d71-000f-4cd9-9a84-ad1b22ddbd33", - "core": false, - "unlocked_by": null, - "difficulty": 0, - "topics": null, - "deprecated": true + "uuid": "dedd9182-66b7-4fbc-bf4b-ba6603edbfca", + "slug": "conditionals", + "name": "Conditionals", + "blurb": "TODO: add blurb for conditionals concept" }, { - "slug": "zipper", - "uuid": "239b8e79-2983-4ce0-9dda-9bb999e79d11", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 7, - "topics": [ - "data_structures" - ] + "uuid": "01d61b5c-8f50-4b12-9fe0-0723e6f00999", + "slug": "floating-point-numbers", + "name": "Floating Point Numbers", + "blurb": "TODO: add blurb for floating-point-numbers concept" }, { - "slug": "grep", - "uuid": "99485900-5d16-4848-af1c-2f1a62ad35ab", - "core": false, - "unlocked_by": "twelve-days", - "difficulty": 8, - "topics": [ - "files", - "parsing", - "pattern_matching", - "regular_expressions", - "strings", - "text_formatting" - ] + "uuid": "35001ed1-a7b9-4a80-a766-26725a29dc50", + "slug": "instance-variables", + "name": "Instance Variables", + "blurb": "TODO: add blurb for instance-variables concept" }, { - "slug": "resistor-color", - "uuid": "685634dd-0b38-40bc-b0ad-e8aa2904035f", - "core": false, - "unlocked_by": "hello-world", - "difficulty": 1, - "topics": [ - "arrays" - ] + "uuid": "152d3976-dbcb-4a16-9f89-c61e0cdda4e5", + "slug": "loops", + "name": "Loops", + "blurb": "TODO: add blurb for loops concept" }, { - "slug": "resistor-color-trio", - "uuid": "2df14b68-75c8-4984-8ae2-ecd2cb7ed1d4", - "core": false, - "unlocked_by": "series", - "difficulty": 5, - "topics": [ - "loops" - ] + "uuid": "aa31cd95-54b2-4728-8fe3-2fdc244b3f53", + "slug": "nil", + "name": "Nil", + "blurb": "TODO: add blurb for nil concept" }, { - "slug": "darts", - "uuid": "15b73808-78a4-4854-b7cf-82a478107024", - "core": false, - "unlocked_by": null, - "difficulty": 3, - "topics": [ - "math", - "geometry" - ] + "uuid": "162721bd-3d64-43ff-889e-6fb2eac75709", + "slug": "numbers", + "name": "Numbers", + "blurb": "TODO: add blurb for numbers concept" }, { - "slug": "microwave", - "uuid": "b960d0fe-a07f-11ea-bb37-0242ac130002", - "core": false, - "unlocked_by": null, - "difficulty": 2, - "topics": [ - "math", - "strings", - "interpolation" - ] + "uuid": "3b1da281-7099-4c93-a109-178fc9436d68", + "slug": "strings", + "name": "Strings", + "blurb": "TODO: add blurb for strings concept" } - ] + ], + "key_features": [], + "tags": [] } diff --git a/exercises/concept/amusement-park-rides/.docs/hints.md b/exercises/concept/amusement-park-rides/.docs/hints.md new file mode 100644 index 0000000000..cf56e9a576 --- /dev/null +++ b/exercises/concept/amusement-park-rides/.docs/hints.md @@ -0,0 +1,28 @@ +## General + +Review: + +- [Ruby for beginners: Nothingness and the truth][rfb-nothingness-and-truth] + +## 1. Check if an attendee has a ride pass + +- Convert the pass_id to a boolean object. +- Look at the [`BasicObject`][basicobject-class] class, it contains methods which most classes inherit. + +## 2. Check if an attendee fits a ride + +- Compare the ride's minimum height to the attendee's height. +- Look at the [`Comparable`][comparable-module] module, it contains methods for comparing objects which can be used when they are included. + - The [Integer][integer-class] class includes the [`Comparable`][comparable-module] module. + +## 3. Check if an attendee is allowed to ride + +- Combine the instance methods you've created using a [boolean operator][pr-boolean-operator] to return the result. + +[pr-boolean-operator]: https://ruby-doc.com/docs/ProgrammingRuby/html/tut_expressions.html#UG +[rfb-nothingness-and-truth]: http://ruby-for-beginners.rubymonstas.org/conditionals/nothing_and_truth.html +[basicobject-class]: https://docs.ruby-lang.org/en/master/BasicObject.html +[comparable-module]: https://docs.ruby-lang.org/en/master/Comparable.html +[integer-class]: https://docs.ruby-lang.org/en/master/Integer.html +[kernel-class]: https://docs.ruby-lang.org/en/master/Kernel.html +[methods]: https://launchschool.com/books/ruby/read/methods diff --git a/exercises/concept/amusement-park-rides/.docs/instructions.md b/exercises/concept/amusement-park-rides/.docs/instructions.md new file mode 100644 index 0000000000..29311a7155 --- /dev/null +++ b/exercises/concept/amusement-park-rides/.docs/instructions.md @@ -0,0 +1,30 @@ +Continuing your work with the amusement park, you are tasked with writing some utility methods to facilitate checking an attendee can use a ride. + +## 1. Check if an attendee has a ride pass + +Implement the `Attendee#pass?` method to return a boolean (`true`/`false`) value based on the presence of a ride pass. + +```ruby +Attendee.new(100).has_pass? +# => false +``` + +## 2. Check if an attendee fits a ride + +Implement the `Attendee#fits_ride?` method to see if an attendee fits a ride based on their height and the minimum height of required by the ride. + +```ruby +Attendee.new(140).fits_ride?(100) +# => true +``` + +## 3. Check if an attendee is allowed to ride + +Implement the `Attendee#allowed_to_ride?` method to see if an attendee is allowed to go on a ride. The ride's required minimum height is provided as an argument. An attendee must have a ride pass and be able to fit the ride. + +```ruby +attendee = Attendee.new(100) +attendee.issue_pass!(42) +attendee.allowed_to_ride(120) +# => false +``` diff --git a/exercises/concept/amusement-park-rides/.docs/introduction.md b/exercises/concept/amusement-park-rides/.docs/introduction.md new file mode 100644 index 0000000000..15134a787f --- /dev/null +++ b/exercises/concept/amusement-park-rides/.docs/introduction.md @@ -0,0 +1,30 @@ +## True and False + +True and false logical states are represented with `true` and `false` in Ruby. These may either be used as literals on their own, or as a result of logical or comparison methods. + +```ruby +happy = true +sad = false + +true && false +# => false + +1 < 2 +# => true +``` + +## _Truthy_ and _falsey_ + +When evaluating objects in `if` statements or other boolean contexts, all objects evaluate as _truthy_ **except** for `false` and `nil`. + +```ruby +def falsey + nil || false +end + +def truthy + not falsey +end +``` + +[nil-dictionary]: https://www.merriam-webster.com/dictionary/nil diff --git a/exercises/concept/amusement-park-rides/.meta/config.json b/exercises/concept/amusement-park-rides/.meta/config.json new file mode 100644 index 0000000000..e9bbfa3844 --- /dev/null +++ b/exercises/concept/amusement-park-rides/.meta/config.json @@ -0,0 +1,28 @@ +{ + "authors": [ + { + "github_username": "neenjaw", + "exercism_username": "neenjaw" + } + ], + "contributors": [ + { + "github_username": "kotp", + "exercism_username": "kotp" + }, + { + "github_username": "iHiD", + "exercism_username": "iHiD" + }, + { + "github_username": "kayn1", + "exercism_username": "kayn1" + } + ], + "language_versions": ">=2.6.6", + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/amusement-park-rides/.meta/design.md b/exercises/concept/amusement-park-rides/.meta/design.md new file mode 100644 index 0000000000..5ff6515da7 --- /dev/null +++ b/exercises/concept/amusement-park-rides/.meta/design.md @@ -0,0 +1,49 @@ +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of "nil" in Ruby. + +## Learning objectives + +- Know that `true` is a Ruby object used to represent logical `true` +- Know that `false` is a Ruby object used to represent logical `false` +- Know that `nil` is a Ruby object used to represent "nothingness" +- Know that everything except `false` and `nil` is truthy +- Know that `nil` is falsey + +## Out of scope + +- None as it relates to this concept + +## Reference + +- `TrueClass` +- `FalseClass` +- `NilClass` + +## Concepts + +- `boolean` +- `nil` + +## Prerequisites + +- `basics` +- `numbers` + +## Resources + +### Hints + +- [Data Types in Ruby - True, False, and Nil Explained with Examples](https://www.freecodecamp.org/news/data-types-in-ruby-true-false-and-nil-explained-with-examples/) + +### After + +- [The nil value in Ruby](https://medium.com/rubycademy/the-nil-value-in-ruby-d60e6a3642b9#:~:text=method%20implementation-,The%20nil%20value,%E2%80%9Clack%20of%20an%20object%E2%80%9D.&text=Unlike%20other%20languages%2C%20the%20nil,the%20non%2Dinstantiable%20NilClass%20class.) + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer](https://github.com/exercism/ruby-representer). + +## Analyzer + +This exercise does not require any specific analyzer logic to be added to the [analyzer](https://github.com/exercism/ruby-analyzer). diff --git a/exercises/concept/amusement-park-rides/.meta/exemplar.rb b/exercises/concept/amusement-park-rides/.meta/exemplar.rb new file mode 100644 index 0000000000..2f9e4566b5 --- /dev/null +++ b/exercises/concept/amusement-park-rides/.meta/exemplar.rb @@ -0,0 +1,29 @@ +class Attendee + attr_reader :height, :pass_id + + def initialize(height) + @height = height + end + + def issue_pass!(pass_id) + @pass_id = pass_id + end + + def revoke_pass! + @pass_id = nil + end + + # Do not edit above methods, add your own methods below. + + def pass? + !pass_id.nil? + end + + def fits_ride?(ride_minimum_height) + height >= ride_minimum_height + end + + def allowed_to_ride?(ride_minimum_height) + pass_id && fits_ride?(ride_minimum_height) + end +end diff --git a/exercises/concept/amusement-park-rides/attendee.rb b/exercises/concept/amusement-park-rides/attendee.rb new file mode 100644 index 0000000000..c93d32b608 --- /dev/null +++ b/exercises/concept/amusement-park-rides/attendee.rb @@ -0,0 +1,29 @@ +class Attendee + attr_reader :height, :pass_id + + def initialize(height) + @height = height + end + + def issue_pass!(pass_id) + @pass_id = pass_id + end + + def revoke_pass! + @pass_id = nil + end + + # Do not edit above methods, add your own methods below. + + def pass? + raise NotImplementedError, 'Please implement the Attendee#pass? method' + end + + def fits_ride?(ride_minimum_height) + raise NotImplementedError, 'Please implement the Attendee#fits_ride? method' + end + + def allowed_to_ride?(ride_minimum_height) + raise NotImplementedError, 'Please implement the Attendee#allowed_to_ride? method' + end +end diff --git a/exercises/concept/amusement-park-rides/attendee_test.rb b/exercises/concept/amusement-park-rides/attendee_test.rb new file mode 100644 index 0000000000..2defdddedc --- /dev/null +++ b/exercises/concept/amusement-park-rides/attendee_test.rb @@ -0,0 +1,81 @@ +require 'minitest/autorun' +require_relative 'attendee' + +class AttendeeTest < Minitest::Test + # Tests carried over from `instance-variables` exercise + + def test_new_instance + height = 100 + assert_equal Attendee, Attendee.new(height).class + end + + def test_new_instance_height + height = 100 + assert_equal height, Attendee.new(height).height + end + + def test_new_instance_pass_id + height = 100 + assert_nil Attendee.new(height).pass_id + end + + def test_issue_pass + height = 100 + attendee = Attendee.new(height) + + pass_id = 1 + attendee.issue_pass!(pass_id) + + assert_equal pass_id, attendee.pass_id + end + + def test_pass_after_revoked + height = 100 + attendee = Attendee.new(height) + pass_id = 1 + attendee.issue_pass!(pass_id) + attendee.revoke_pass! + refute attendee.pass_id + end + + # New tests for `booleans` exercise + + def test_new_instance_doesnt_have_pass + refute Attendee.new(100).pass? + end + + def test_when_issued_pass + attendee = Attendee.new(100) + attendee.issue_pass!(1) + assert attendee.pass? + end + + def test_when_revoked_doesnt_have_pass + attendee = Attendee.new(100) + attendee.issue_pass!(1) + attendee.revoke_pass! + refute attendee.pass? + end + + def test_fits_ride_exactly + assert Attendee.new(100).fits_ride?(100) + end + + def test_fits_small_ride + assert Attendee.new(100).fits_ride?(80) + end + + def test_doesnt_fit_big_ride + refute Attendee.new(100).fits_ride?(110) + end + + def test_fits_ride_but_no_pass + refute Attendee.new(100).allowed_to_ride?(100) + end + + def test_fits_ride_and_pass + attendee = Attendee.new(100) + attendee.issue_pass!(1) + assert attendee.allowed_to_ride?(100) + end +end diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/arrays/.docs/hints.md new file mode 100644 index 0000000000..0fdabafeee --- /dev/null +++ b/exercises/concept/arrays/.docs/hints.md @@ -0,0 +1,35 @@ +### General + +- The bird count per day is stored in a [instance variable][instace-variable] named `birds_per_day`. +- The bird count per day is an array that contains exactly 7 integers. + +### 1. Check what the counts were last week + +- As this method does _not_ depend on the current week's count, it is defined as a [`class` method][class-method]. +- There are [several ways to define an array][array-definition]. + +### 2. Check how many birds visited yesterday + +- Remember that the counts are ordered by day from oldest to most recent, with the last element representing today. +- Accessing the second last element can be done either by using its (fixed) index (remember to start counting from zero) or by calculating its index using the [array's size][array-length]. + +### 3. Calculate the total number of visiting birds + +- It's possible to calculate the sum of a collection using the [Array#sum][array-sum] method. + +### 4. Calculate the number of busy days + +- Ruby also provides a method for [counting elements on a collection][array-count] + +### 5. Check if there was a day with no visiting birds + +- There are some methods that can be use to check the existence on an element on a colection. For example [Enumerable#any?][enumerable-any] and [Enumerable#all?][enumerable-all] + +[instance-variables]: http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html +[class-method]: http://www.rubyfleebie.com/2007/04/09/understanding-class-methods-in-ruby/ +[array-definition]: https://ruby-doc.org/core-2.7.0/Array.html#class-Array-label-Creating+Arrays +[array-length]: https://ruby-doc.org/core-2.7.0/Array.html#class-Array-label-Obtaining+Information+about+an+Array +[array-sum]: https://ruby-doc.org/core-2.7.0/Array.html#method-i-sum +[array-count]: https://ruby-doc.org/core-2.7.0/Array.html#method-i-count +[enumerable-any]: https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-any-3F +[enumerable-all]: https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-all-3F diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md new file mode 100644 index 0000000000..859f8a1dcc --- /dev/null +++ b/exercises/concept/arrays/.docs/instructions.md @@ -0,0 +1,57 @@ +You're an avid bird watcher that keeps track of how many birds have visited your garden in the last seven days. + +You have five tasks, all dealing with the numbers of birds that visited your garden. + +### 1. Check what the counts were last week + +For comparison purposes, you always keep a copy of last week's counts nearby, which were: 0, 2, 5, 3, 7, 8 and 4. Implement the `BirdCount.last_week` method that returns last week's counts: + +```ruby +BirdCount.last_week +# => [0, 2, 5, 3, 7, 8, 4] +``` + +### 2. Check how many birds visited yesterday + +Implement the `BirdCount#yesterday` method to return how many birds visited your garden yesterday. The bird counts are ordered by day, with the first element being the count of the oldest day, and the last element being today's count. + +```ruby +birds_per_day = [2, 5, 0, 7, 4, 1] +bird_count = new BirdCount(birds_per_day) +bird_count.yesterday +# => 4 +``` + +### 3. Calculate the total number of visiting birds + +Implement the `BirdCount#total` method to return the total number of birds that have visited your garden: + +```ruby +birds_per_day = [2, 5, 0, 7, 4, 1] +bird_count = new BirdCount(birds_per_day) +bird_count.total +# => 19 +``` + +### 4. Calculate the number of busy days + +Some days are busier that others. A busy day is one where five or more birds have visited your garden. +Implement the `BirdCount#busy_days` method to return the number of busy days: + +```ruby +birds_per_day = [2, 5, 0, 7, 4, 1] +bird_count = new BirdCount(birds_per_day) +bird_count.busy_days +# => 2 +``` + +### 5. Check if there was a day with no visiting birds + +Implement the `BirdCount#day_without_birds?` method that returns `true` if there was a day at which zero birds visited the garden; otherwise, return `false`: + +```ruby +birds_per_day = [2, 5, 0, 7, 4, 1] +ird_count = new BirdCount(birds_per_day) +bird_count.day_without_birds? +# => true +``` diff --git a/exercises/concept/arrays/.docs/introduction.md b/exercises/concept/arrays/.docs/introduction.md new file mode 100644 index 0000000000..ac17cb6f6b --- /dev/null +++ b/exercises/concept/arrays/.docs/introduction.md @@ -0,0 +1,84 @@ +In Ruby, **arrays** are ordered, integer-indexed collections of any object. Array indexing starts at `0`. A negative index is assumed to be relative to the end of the array — i.e. an index of `-1` indicates the last element of the array, `-2` is the next to last element in the array, and so on. +Ruby arrays mix in the [Enumerable module][enumerable-module], which adds several traversal and searching methods, and with the ability to sort. + +### Create array. + +- An array in Ruby can contain different types of objects. + +```ruby +array = [1, "two", 3.0] #=> [1, "two", 3.0] +``` + +### Element Assignment + +Elements can accessed or changed using indexes. Subarrays can be accessed by specifying a start index and a size. + +```ruby +a = ["", "", "", "", ""] + +a[4] = "hello" #=> [nil, nil, nil, nil, "hello"] +a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "hello"] +``` + +- Negative indices will count backward from the end of the array. + +```ruby +a = ['a', 'b'] + +a[-1] = "Z" +a #=> ["a", "Z"] +``` + +### Element Reference + +- Elements in an array can be retrieved using the #[] method. It returns the element at index, or returns a subarray starting at the start index and continuing for length elements. + +```ruby +a = [ "a", "b", "c", "d", "e" ] + +a[2] #=> "c" +a[6] #=> nil +a[1, 2] #=> [ "b", "c" ] +``` + +- Negative indices count backward from the end of the array (-1 is the last element) + +```ruby +a = [ "a", "b", "c", "d", "e" ] + +a[-2] #=> "d" +a[-3, 3] #=> [ "c", "d", "e" ] +``` + +### Obtaining Information about an Array + +Arrays keep track of their own length at all times. To query an array about the number of elements it contains, use length, count or size. + +```ruby +browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] +browsers.length #=> 5 +browsers.count #=> 5 +browsers.size #=> 5 +``` + +### Adding Items to Arrays + +Items can be added to the end of an array by using either push or << + +```ruby +arr = [1, 2, 3, 4] +arr.push(5) #=> [1, 2, 3, 4, 5] +arr << 6 #=> [1, 2, 3, 4, 5, 6] +``` + +### Removing Items from an Array + +The method pop removes the last element in an array and returns it + +```ruby +arr = [1, 2, 3, 4, 5, 6] +arr.pop #=> 6 +arr #=> [1, 2, 3, 4, 5] +``` + +[enumerable-module]: https://ruby-doc.org/core-2.7.1/Enumerable.html diff --git a/exercises/concept/arrays/.meta/config.json b/exercises/concept/arrays/.meta/config.json new file mode 100644 index 0000000000..5aea4614fe --- /dev/null +++ b/exercises/concept/arrays/.meta/config.json @@ -0,0 +1,14 @@ +{ + "authors": [ + { + "github_username": "pvcarrera", + "exercism_username": "pvcarrera" + } + ], + "forked_from": ["csharp/arrays"], + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md new file mode 100644 index 0000000000..c21cae5b86 --- /dev/null +++ b/exercises/concept/arrays/.meta/design.md @@ -0,0 +1,52 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Arrays in Ruby. + +Of the many available Ruby collections, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons: + +- Arrays are a common data type in many languages. +- Arrays have a fixed length. No complexity in adding or removing elements. +- Arrays have a simple shorthand syntax. No need to understand how initializers work to define an array. + +## Learning objectives + +- The existence of the `Array` object. +- Defining an array. +- Accessing elements in an array by index. +- Iterating over elements in an array. +- Basic array methods (like size or sum). + +## Out of scope + +- Multi-dimensional/jagged arrays. +- Memory and performance characteristics of arrays. +- Iterators. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `arrays`: know of the existence of the `Array` object; know how to define an array; know how to access elements in an array by index; know how to iterate over elements in an array; know of some basic functions. +- `each loops`: know how to iterate over a collection. + +## Prerequisites + +This exercise's prerequisites Concepts are: + +- `classes`: know how to work with instance variables. +- `for-loops`: know what a `for` loop is. +- `booleans`: know what a `boolean` is. +- `basics`: know how to assign and update variables. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer diff --git a/exercises/concept/arrays/.meta/exemplar.rb b/exercises/concept/arrays/.meta/exemplar.rb new file mode 100644 index 0000000000..401eda615b --- /dev/null +++ b/exercises/concept/arrays/.meta/exemplar.rb @@ -0,0 +1,26 @@ +class BirdCount + def self.last_week + [0, 2, 5, 3, 7, 8, 4] + end + + def initialize(birds_per_day) + @birds_per_day = birds_per_day + end + + def yesterday + @birds_per_day[5] + end + + def total + @birds_per_day.sum + end + + def busy_days + @birds_per_day.count { |birds| birds >= 5 } + end + + def day_without_birds? + @birds_per_day.any? { |birds| birds == 0 } + end +end + diff --git a/exercises/concept/arrays/bird_count.rb b/exercises/concept/arrays/bird_count.rb new file mode 100644 index 0000000000..91827423b1 --- /dev/null +++ b/exercises/concept/arrays/bird_count.rb @@ -0,0 +1,26 @@ +class BirdCount + def self.lastWeek + raise NotImplementedError, 'Please implement the BirdCount.lastWeek method' + end + + def initialize(birds_per_day) + raise NotImplementedError, 'Please implement the BirdCount#initialize method' + end + + def yesterday + raise NotImplementedError, 'Please implement the BirdCount#yesterday method' + end + + def total + raise NotImplementedError, 'Please implement the BirdCount#total method' + end + + def busy_days + raise NotImplementedError, 'Please implement the BirdCount#busy_days method' + end + + def day_without_birds? + raise NotImplementedError, 'Please implement the BirdCount#day_without_birds method' + end +end + diff --git a/exercises/concept/arrays/bird_count_test.rb b/exercises/concept/arrays/bird_count_test.rb new file mode 100644 index 0000000000..e52e554604 --- /dev/null +++ b/exercises/concept/arrays/bird_count_test.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require_relative 'bird_count' + +class LasagnaTest < Minitest::Test + def test_last_week + assert_equal [0, 2, 5, 3, 7, 8, 4], BirdCount.last_week + end + + def test_yesterday_for_dissapointing_week + counts = [0, 0, 1, 0, 0, 1, 0] + bird_count = BirdCount.new(counts) + + assert_equal 1, bird_count.yesterday + end + + def test_yesterday_for_busy_week + counts = [8, 8, 9, 5, 4, 7, 10] + bird_count = BirdCount.new(counts) + + assert_equal 7, bird_count.yesterday + end + + def test_total_for_dissapointing_week + counts = [0, 0, 1, 0, 0, 1, 0] + bird_count = BirdCount.new(counts) + + assert_equal 2, bird_count.total + end + + def test_total_for_busy_week + counts = [5, 9, 12, 6, 8, 8, 17] + bird_count = BirdCount.new(counts) + + assert_equal 65, bird_count.total + end + + def test_busy_days_for_dissapointing_week + counts = [1, 1, 1, 0, 0, 0, 0] + bird_count = BirdCount.new(counts) + + assert_equal 0, bird_count.busy_days + end + + def test_busy_days_for_busy_week + counts = [4, 9, 5, 7, 8, 8, 2] + bird_count = BirdCount.new(counts) + + assert_equal 5, bird_count.busy_days + end + + def test_has_day_without_birds + counts = [5, 5, 4, 0, 7, 6] + bird_count = BirdCount.new(counts) + + assert bird_count.day_without_birds? + end + + def test_has_day_without_birds_whith_no_day_without_birds + counts = [4, 5, 9, 10, 9, 4, 3] + bird_count = BirdCount.new(counts) + + refute bird_count.day_without_birds? + end +end + diff --git a/exercises/concept/conditionals-ternary/.docs/instructions.md b/exercises/concept/conditionals-ternary/.docs/instructions.md new file mode 100644 index 0000000000..28831b385c --- /dev/null +++ b/exercises/concept/conditionals-ternary/.docs/instructions.md @@ -0,0 +1,39 @@ +In this exercise you will rewrite `if/else` statements from a movie theater's website into ternary conditionals. + +## 1. Check if a moviegoer is entitled to the seniors' discount + +Rewrite the `Moviegoer#ticket_price` method to utilize the ternary operator. + +```ruby + def ticket_price + if age < 60 + 15 + else + 10 + end + end +``` + +## 2. Check if a moviegoer is allowed to see scary movies + +```ruby + def watch_scary_movie + if age >= 18 + "Enjoy the movie!" + else + "You must be over 18 to see this movie." + end + end +``` + +## 3. Check if a moviegoer is entitled to free popcorn + +```ruby + def claim_free_popcorn + if movie_club_member + "Enjoy your free popcorn!" + else + "Join the Movie Club to get free popcorn." + end + end +``` diff --git a/exercises/concept/conditionals-ternary/.docs/introduction.md b/exercises/concept/conditionals-ternary/.docs/introduction.md new file mode 100644 index 0000000000..220dce4dc1 --- /dev/null +++ b/exercises/concept/conditionals-ternary/.docs/introduction.md @@ -0,0 +1,21 @@ +A ternary conditional in Ruby is a shorter way of writing simple `if/else` statements. If an `if/else` statement contains only two branches, one for when the condition is true and one for when it is false, it can be re-written as a ternary conditional. + +It uses a combination of the `?` and `:` symbols, often called the ternary operator(s). + +For example: + +```ruby +if traffic_light == 'green' + cross_the_road +else + wait +end +``` + +can be re-written as: + +```ruby +traffic_light == 'green' ? cross_the_road : wait +``` + +The code on the left side of the `?` is the condition and the code on the right contains the two possible branches, separated by the `:`. If the condition is _true_, the code on the _left_ side of the `:` is executed; if the condition is _false_, then the code on the _right_ of the `:` gets executed. diff --git a/exercises/concept/conditionals-ternary/.meta/exemplar.rb b/exercises/concept/conditionals-ternary/.meta/exemplar.rb new file mode 100644 index 0000000000..b20bb2087a --- /dev/null +++ b/exercises/concept/conditionals-ternary/.meta/exemplar.rb @@ -0,0 +1,22 @@ +class Moviegoer + attr_reader :age, :movie_club_member + + def initialize(age, movie_club_member: false) + @age = age + @movie_club_member = movie_club_member + end + + # Do not edit above methods, add your own methods below. + + def ticket_price + age < 60 ? 15 : 10 + end + + def watch_scary_movie + age >= 18 ? "Enjoy the movie!" : "You must be over 18 to see this movie." + end + + def claim_free_popcorn + movie_club_member ? "Enjoy your free popcorn!" : "Join the Movie Club to get free popcorn." + end +end diff --git a/exercises/concept/conditionals-ternary/moviegoer.rb b/exercises/concept/conditionals-ternary/moviegoer.rb new file mode 100644 index 0000000000..a770d280d1 --- /dev/null +++ b/exercises/concept/conditionals-ternary/moviegoer.rb @@ -0,0 +1,22 @@ +class Moviegoer + attr_reader :age, :movie_club_member + + def initialize(age, movie_club_member: false) + @age = age + @movie_club_member = movie_club_member + end + + # Do not edit above methods, add your own methods below. + + def ticket_price + raise NotImplementedError, 'Please implement the Moviegoer#ticket_price method' + end + + def watch_scary_movie + raise NotImplementedError, 'Please implement the Moviegoer#watch_scary_movie method' + end + + def claim_free_popcorn + raise NotImplementedError, 'Please implement the Moviegoer#claim_free_popcorn method' + end +end diff --git a/exercises/concept/conditionals-ternary/moviegoer_test.rb b/exercises/concept/conditionals-ternary/moviegoer_test.rb new file mode 100644 index 0000000000..bab7ffda21 --- /dev/null +++ b/exercises/concept/conditionals-ternary/moviegoer_test.rb @@ -0,0 +1,34 @@ +require 'minitest/autorun' +require_relative 'moviegoer' + +class MoviegoerTest < Minitest::Test + def test_regular_ticket_price + moviegoer = Moviegoer.new(25) + assert_equal 15, moviegoer.ticket_price + end + + def test_seniors_discount + moviegoer = Moviegoer.new(60) + assert_equal 10, moviegoer.ticket_price + end + + def test_adults_can_see_the_scary_movie + moviegoer = Moviegoer.new(25) + assert_equal "Enjoy the movie!", moviegoer.watch_scary_movie + end + + def test_kids_cant_see_the_scary_movie + moviegoer = Moviegoer.new(10) + assert_equal "You must be over 18 to see this movie.", moviegoer.watch_scary_movie + end + + def test_movie_club_members_get_free_popcorn + moviegoer = Moviegoer.new(25, movie_club_member: true) + assert_equal "Enjoy your free popcorn!", moviegoer.claim_free_popcorn + end + + def test_regular_moviegoers_dont_get_free_popcorn + moviegoer = Moviegoer.new(25) + assert_equal "Join the Movie Club to get free popcorn.", moviegoer.claim_free_popcorn + end +end diff --git a/exercises/concept/exceptions/.docs/hints.md b/exercises/concept/exceptions/.docs/hints.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/exceptions/.docs/instructions.md b/exercises/concept/exceptions/.docs/instructions.md new file mode 100644 index 0000000000..318bc0db90 --- /dev/null +++ b/exercises/concept/exceptions/.docs/instructions.md @@ -0,0 +1,33 @@ +In this exercise you will be building error handling for a simple calculator. + +The goal is to have a working calculator that returns a string with the following pattern: `16 + 51 = 67`, when provided with arguments `16`, `51` and `+`. + +```ruby +SimpleCalculator.calculate(16, 51, "+"); // => returns "16 + 51 = 67" +SimpleCalculator.calculate(32, 6, "*"); // => returns "32 * 6 = 192" +SimpleCalculator.calculate(512, 4, "/"); // => returns "512 / 4 = 128" +``` + +## 1. Handle the code that may raise errors within the method `calculate` + +The main method for implementation in this task will be the class method `SimpleCalculator.calculate()` method. It takes three arguments. The first two arguments are numbers on which an operation is going to be conducted. The third argument is of type string and for this exercise it is necessary to implement the following operations: + +- addition using the `+` string +- multiplication using the `*` string +- division using the `/` string + +## 2. Handle illegal operations + +Update the `SimpleCalculator.calculate()` method to raise an `UnsupportedOperation` exception for unknown operation symbols. + +```ruby +SimpleCalculator.calculate(1, '2', '-'); // => Raises an UnsupportedOperation +``` + +## 4. Handle DivideByZero exceptions + +Update the `SimpleCalculator.calculate()` to handle `ZeroDivisionError` exceptions. The handling code should return the string with the content `Division by zero is not allowed.`. Any other exception should not be handled by the `SimpleCalculator.calculate()` method. + +```ruby +SimpleCalculator.calculate(512, 0, "/"); # => returns "Division by zero is not allowed." +``` diff --git a/exercises/concept/exceptions/.docs/introduction.md b/exercises/concept/exceptions/.docs/introduction.md new file mode 100644 index 0000000000..82e93186f4 --- /dev/null +++ b/exercises/concept/exceptions/.docs/introduction.md @@ -0,0 +1,61 @@ +Exceptions in Ruby, as in many languages, provide a way of dealing with unexpected events. Proper handling of exceptions is important when trying to prevent your program from crashing. + +When an exception is raised, either by raising it explicitly or by the Ruby interpreter raising it, the program diverts normal operation and eventually exits with an error message: + +```ruby +raise ArgumentError.new("Something went wrong!") +=> Traceback (most recent call last): +. +. +ArgumentError (Something went wrong!) +``` + +```ruby +1/0 +=> Traceback (most recent call last): +. +. +ZeroDivisionError (divided by 0) +``` + +In case we want to stop this shut down process we need to react to the exception. This is called "rescuing" an exception: + +```ruby +begin + # ...any code that raises an exception +rescue + puts 'Got an exception' +end +``` + +This program will not crash and it'll output "Got an exception". Instead of exiting, Ruby runs the code in the rescue block, which prints out a message. + +As everything in Ruby, exceptions are also objects and they usually hold data about the exception. This is how we can get the exception object: + +```ruby +begin + # ...any code that raises an exception +rescue => e + puts "Exception class: #{ e.class.name }" + puts "Exception Message:#{e.message}" +end +``` + +In Ruby it's also possible to raise your own exceptions. For example: + +```ruby +begin + raise ArgumentError.new("Invalid argument") +rescue ArgumentError => e + puts e.message +end +``` + +The previous exception is one of the Ruby's built in exceptions but it's also possible to define custom exceptions and raise them: + +```ruby +class CustomError < StandardError +end + +raise CustomError.new("Something went wrong") +``` diff --git a/exercises/concept/exceptions/.meta/config.json b/exercises/concept/exceptions/.meta/config.json new file mode 100644 index 0000000000..fb09e4edab --- /dev/null +++ b/exercises/concept/exceptions/.meta/config.json @@ -0,0 +1,14 @@ +{ + "authors": [ + { + "github_username": "pvcarrera", + "exercism_username": "pvcarrera" + } + ], + "forked_from": ["csharp/exceptions"], + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/exceptions/.meta/design.md b/exercises/concept/exceptions/.meta/design.md new file mode 100644 index 0000000000..b6dd82efd7 --- /dev/null +++ b/exercises/concept/exceptions/.meta/design.md @@ -0,0 +1,38 @@ +## Goal + +The goal of this exercise is to teach the student the Concept of Exceptions in Ruby. + +## Learning objectives + +- Know what exceptions are. +- Know when an exception should be raised. +- Know how to raised an exception. +- Know how to rescue an when to re-raise an exception. +- Know the most important built-in exceptions (`Error`, `StandardError`, `ArgumentError`). +- Know how to create custom exceptions. + +## Out of scope + +- Memory and performance characteristics. + +## Concepts + +- `exceptions`: know what exceptions are; know when an exception should be raised; know how to raised an exception; know how to rescue an when to re-raise an exception; know the most important built-in exceptions (`Error`, `StandardError`, `ArgumentError`); know how to create custom exceptions + +## Prequisites + +- `basics`: know how to do string interpolation and how to work with `int`s +- `inheritance`: know about class hierarchies +- `nullability`: know what `nil` is + +## Resources to refer to + +### Hints + +- [Exceptions in Ruby][exceptions]: The Pragmatic Programmer's Guide. Exceptions chapter. + +### After + +- [Exceptions in Ruby][exceptions]: The Pragmatic Programmer's Guide. Exceptions chapter. + +[exceptions]: https://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html diff --git a/exercises/concept/exceptions/.meta/exemplar.rb b/exercises/concept/exceptions/.meta/exemplar.rb new file mode 100644 index 0000000000..2fe9d5090f --- /dev/null +++ b/exercises/concept/exceptions/.meta/exemplar.rb @@ -0,0 +1,16 @@ +class SimpleCalculator + ALLOWED_OPERATIONS = ['+', '/', '*'] + + UnsupportedOperation = Class.new(StandardError) + + def self.calculate(first_operand, second_operand, operation) + raise ArgumentError unless (first_operand.is_a?(Number) && second_operand.is_a?(Number)) + raise UnsupportedOperation.new unless ALLOWED_OPERATIONS.include?(operation) + + result = first_operand.public_send(operation, second_operand) + + "#{first_operand} #{operation} #{second_operand} = #{result}" + rescue ZeroDivisionError + 'Division by zero is not allowed.' + end +end diff --git a/exercises/concept/exceptions/simple_calculator.rb b/exercises/concept/exceptions/simple_calculator.rb new file mode 100644 index 0000000000..19e98f51bd --- /dev/null +++ b/exercises/concept/exceptions/simple_calculator.rb @@ -0,0 +1,7 @@ +class SimpleCalculator + ALLOWED_OPERATIONS = ['+', '/', '*'] + + def self.calculate(first_operand, second_operand, operation) + raise NotImplementedError, 'Please implement the SimpleCalculator.calculate method' + end +end diff --git a/exercises/concept/exceptions/simple_calculator_test.rb b/exercises/concept/exceptions/simple_calculator_test.rb new file mode 100644 index 0000000000..1b26e42796 --- /dev/null +++ b/exercises/concept/exceptions/simple_calculator_test.rb @@ -0,0 +1,40 @@ +require 'minitest/autorun' +require_relative 'simple_calculator' + +class SimpleCalculatorTest < Minitest::Test + def test_addition_with + assert_equal '22 + 25 = 47', SimpleCalculator.calculate(22, 25, '+') + end + + def test_multiplication + assert_equal '3 * 21 = 63', SimpleCalculator.calculate(3, 21, '*') + end + + def test_division + assert_equal '72 / 9 = 8', SimpleCalculator.calculate(72, 9, '/') + end + + def test_rescues_division_by_0_exception + assert_equal "Division by zero is not allowed.", SimpleCalculator.calculate(33, 0, "/") + end + + def test_no_number_first_operand_raises_exception + assert_raises(ArgumentError) { SimpleCalculator.calculate('1', 2, '+') } + end + + def test_no_number_second_operand_raises_exception + assert_raises(ArgumentError) { SimpleCalculator.calculate(1, '2', '+') } + end + + def test_raises_exception_for_non_valid_operations + assert_raises(SimpleCalculator::UnsupportedOperation) { SimpleCalculator.calculate(1, 2, '**') } + end + + def test_raises_exception_when_operation_is_nil + assert_raises(SimpleCalculator::UnsupportedOperation) { SimpleCalculator.calculate(1, 2, nil) } + end + + def test_raises_exception_when_operation_is_an_empty_string + assert_raises(SimpleCalculator::UnsupportedOperation) { SimpleCalculator.calculate(1, 2, '') } + end +end diff --git a/exercises/concept/floating-point-numbers/.docs/hints.md b/exercises/concept/floating-point-numbers/.docs/hints.md new file mode 100644 index 0000000000..48fe320a80 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.docs/hints.md @@ -0,0 +1,13 @@ +## General + +## 1. Calculate the interest rate + +- Using an `if` or `case` statement can be useful when checking conditions. + +## 2. Calculate the annual balance update + +- When calculating the annual yield, it might be useful to temporarily convert a negative balance to a positive one. The `Float` class has a method to convert both positive and negative values to their absolute value. + +## 3. Calculate the years before reaching the desired balance + +- To calculate the years, one can keep looping until the desired balance is reached. diff --git a/exercises/concept/floating-point-numbers/.docs/instructions.md b/exercises/concept/floating-point-numbers/.docs/instructions.md new file mode 100644 index 0000000000..ed013ef5d9 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.docs/instructions.md @@ -0,0 +1,41 @@ +In this exercise you'll be working with savings accounts. Each year, the balance of a savings account is updated based on the interest rate. The interest rate the bank gives depends on the amount of money in the accounts (its balance): + +- -3.213% for a negative balance. +- 0.5% for a positive balance less than `1000` dollars. +- 1.621% for a positive balance greater or equal than `1000` dollars and less than `5000` dollars. +- 2.475% for a positive balance greater or equal than `5000` dollars. + +You have three tasks, each of which will deal the balance and its interest rate. + +## 1. Calculate the interest rate + +Implement the `SavingsAccount.interest_rate` method to calculate the interest rate based on the specified balance: + +```ruby +SavingsAccount.interest_rate(200.75) +#=> 0.5 +``` + +Note that the value returned is an instance of `Float`. + +## 2. Calculate the annual balance update + +Implement the `SavingsAccount.annual_balance_update` method to calculate the annual balance update, taking into account the interest rate: + +```ruby +SavingsAccount.annual_balance_update(200.75) +#=> 201.75375 +``` + +Note that the value returned is an instance of `Float`. + +## 3. Calculate the years before reaching the desired balance + +Implement the `SavingsAccount.years_before_desired_balance` method to calculate the minimum number of years required to reach the desired balance: + +```ruby +SavingsAccount.years_before_desired_balance(200.75, 214.88) +#=> 14 +``` + +Note that the value returned is an instance of `Integer`. diff --git a/exercises/concept/floating-point-numbers/.docs/introduction.md b/exercises/concept/floating-point-numbers/.docs/introduction.md new file mode 100644 index 0000000000..d295e22232 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.docs/introduction.md @@ -0,0 +1,16 @@ +## Floating Point Numbers + +## Loops + +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `4.0`, `0.1`, `3.14`, `-6.4` `16.984025` and `1024.0`. +In Ruby, floating-point numbers are implemented through the [Float](https://ruby-doc.org/core-2.7.0/Float.html) class. + +In this exercise you may also want to use a loop. There are several ways to write loops in Ruby, one of them is the `while` loop: + +```ruby +counter = 0 + +while counter < 5 + counter += 1 +end +``` diff --git a/exercises/concept/floating-point-numbers/.meta/config.json b/exercises/concept/floating-point-numbers/.meta/config.json new file mode 100644 index 0000000000..0dfdd2ac30 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "dvik1950", + "exercism_username": "dvik1950" + } + ], + "forked_from": ["csharp/floating-point-numbers"], + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md new file mode 100644 index 0000000000..a0dac57c18 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -0,0 +1,40 @@ +## Goal + +The goal of this exercise is to teach the student the concept of floating-point numbers and introduce them to loops. + +## Learning objectives + +- Know about the [Float][float-class] class and some of its methods. +- Know how to write a `while`, `until` and `loop` loop. + +## Out of scope + +- Parsing floating-point types from strings. +- Converting floating-point types to strings. +- Using standard or custom format strings. + +## Concepts + +The Concepts this exercise unlocks are: + +- `floating-point-numbers` +- `loops`: know how to write a `while`, `until` and `loop` loop. + +## Prerequisites + +This exercise's prerequisite concepts are: + +- `numbers`: define numbers and apply arithmetic and boolean logic to them. +- `conditionals`: conditionally execute code based on value of floating-point numbers. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[float-class]: https://ruby-doc.org/core-2.7.0/Float.html +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer diff --git a/exercises/concept/floating-point-numbers/.meta/exemplar.rb b/exercises/concept/floating-point-numbers/.meta/exemplar.rb new file mode 100644 index 0000000000..8ffc22bb95 --- /dev/null +++ b/exercises/concept/floating-point-numbers/.meta/exemplar.rb @@ -0,0 +1,37 @@ +module SavingsAccount + + NEGATIVE_RATE = -3.213 + SMALL_POSITIVE_RATE = 0.5 + MEDIUM_POSITIVE_RATE = 1.621 + LARGE_POSITIVE_RATE = 2.475 + + def self.interest_rate(balance) + if balance.negative? + NEGATIVE_RATE + elsif balance < 1000 + SMALL_POSITIVE_RATE + elsif balance < 5000 + MEDIUM_POSITIVE_RATE + else + LARGE_POSITIVE_RATE + end + end + + def self.annual_balance_update(balance) + balance + annual_yield(balance) + end + + def self.years_before_desired_balance(current_balance, desired_balance) + years = 0 + while current_balance < desired_balance + current_balance = annual_balance_update(current_balance) + years += 1 + end + years + end + + def self.annual_yield(balance) + multiplier = interest_rate(balance) / 100 + balance.abs * multiplier + end +end diff --git a/exercises/concept/floating-point-numbers/savings_account.rb b/exercises/concept/floating-point-numbers/savings_account.rb new file mode 100644 index 0000000000..5979d9f202 --- /dev/null +++ b/exercises/concept/floating-point-numbers/savings_account.rb @@ -0,0 +1,13 @@ +module SavingsAccount + def self.interest_rate(balance) + raise NotImplementedError, 'Please implement the SavingsAccount.interest_rate method' + end + + def self.annual_balance_update(balance) + raise NotImplementedError, 'Please implement the SavingsAccount.annual_balance_update method' + end + + def self.years_before_desired_balance(current_balance, desired_balance) + raise NotImplementedError, 'Please implement the SavingsAccount.years_before_desired_balance method' + end +end diff --git a/exercises/concept/floating-point-numbers/savings_account_test.rb b/exercises/concept/floating-point-numbers/savings_account_test.rb new file mode 100644 index 0000000000..94ecd86d31 --- /dev/null +++ b/exercises/concept/floating-point-numbers/savings_account_test.rb @@ -0,0 +1,105 @@ +require 'minitest/autorun' +require_relative 'savings_account' + +class SavingsAccountTest < Minitest::Test + + def test_minimal_first_interest_rate + assert_equal 0.5, SavingsAccount.interest_rate(0) + end + + def test_tiny_first_interest_rate + assert_equal 0.5, SavingsAccount.interest_rate(0.000_001) + end + + def test_maximal_first_interest_rate + assert_equal 0.5, SavingsAccount.interest_rate(999.999) + end + + def test_minimal_second_interest_rate + assert_equal 1.621, SavingsAccount.interest_rate(1_000.0) + end + + def test_tiny_second_interest_rate + assert_equal 1.621, SavingsAccount.interest_rate(1_000.001) + end + + def test_maximal_second_interest_rate + assert_equal 1.621, SavingsAccount.interest_rate(4_999.999) + end + + def test_minimal_third_interest_rate + assert_equal 2.475, SavingsAccount.interest_rate(5_000.0) + end + + def test_tiny_third_interest_rate + assert_equal 2.475, SavingsAccount.interest_rate(5_000.001) + end + + def test_large_third_interest_rate + assert_equal 2.475, SavingsAccount.interest_rate(555_555_555.555) + end + + def test_minimal_negative_interest_rate + assert_equal -3.213, SavingsAccount.interest_rate(-0.0001) + end + + def test_small_negative_interest_rate + assert_equal -3.213, SavingsAccount.interest_rate(-0.123) + end + + def test_regular_negative_interest_rate + assert_equal -3.213, SavingsAccount.interest_rate(-300.0) + end + + def test_large_negative_interest_rate + assert_equal -3.213, SavingsAccount.interest_rate(-55_555.444) + end + + def test_annual_balance_update_for_empty_start_balance + assert_equal 0, SavingsAccount.annual_balance_update(0.0) + end + + def test_annual_balance_update_for_small_positive_start_balance + assert_equal 0.000_001_005, SavingsAccount.annual_balance_update(0.000_001) + end + + def test_annual_balance_update_for_avarage_positive_start_balance + assert_equal 1_016.21, SavingsAccount.annual_balance_update(1_000.0) + end + + def test_annual_balance_update_for_large_positive_start_balance + assert_equal 1_016.2_101_016_209_999, SavingsAccount.annual_balance_update(1_000.0001) + end + + def test_annual_balance_update_for_huge_positive_start_balance + assert_equal 920_352_587.26_744_292_868_451_875, SavingsAccount.annual_balance_update(898_124_017.826_243_404_425) + end + + def test_annual_balance_update_for_small_negative_start_balance + assert_equal -0.12_695_199, SavingsAccount.annual_balance_update(-0.123) + end + + def test_annual_balance_update_for_avarage_negative_start_balance + assert_equal 1_016.21, SavingsAccount.annual_balance_update(1_000.0) + end + + def test_annual_balance_update_for_large_negative_start_balance + assert_equal -157_878.97_174_203, SavingsAccount.annual_balance_update(-152_964.231) + end + + def test_years_before_desired_balance_for_small_start_balance + assert_equal 47, SavingsAccount.years_before_desired_balance(100.0, 125.8) + end + + def test_years_before_desired_balance_for_average_start_balance + assert_equal 6, SavingsAccount.years_before_desired_balance(1_000.0, 1_100.0) + end + + def test_years_before_desired_balance_for_large_start_balance + assert_equal 5, SavingsAccount.years_before_desired_balance(8_080.80, 9_090.9) + end + + def test_years_before_desired_balance_for_large_difference_between_start_and_desired_balance + assert_equal 85, SavingsAccount.years_before_desired_balance(2_345.67, 12_345.6_789) + end +end diff --git a/exercises/concept/instance-variables/.docs/hints.md b/exercises/concept/instance-variables/.docs/hints.md new file mode 100644 index 0000000000..193b842194 --- /dev/null +++ b/exercises/concept/instance-variables/.docs/hints.md @@ -0,0 +1,39 @@ +## General + +About initializing object instances: + +- [Ruby Guides: Initialize Method][rg-initialize-method] + +About instance variables: + +- [Ruby For Beginners: Instance variables][rfb-instance-variables] +- [Ruby Guides: Instance variables][rg-instance-variables] +- [Ruby User's Guide: Instance variables][rug-instance-variables] +- [Geeks for Geeks: Ruby Getters and Setters Methods][gfg-getter-setters] + +## 1. Make new attendees + +- Using the references, complete the initialize method to save the height to the object's state. + +## 2. How tall is the attendee + +- Create a getter for the saved height state. + +## 3. What is the ride pass's id + +- Create a getter for the pass id. +- It is okay and expected to return `nil` before a pass is issued to the `Attendee`. + +## 4. Allow people to buy a pass + +- Using the `Attendee#issue_pass!` method, set the instance's state to the argument. + +## 4. Revoke the pass + +- Using the `Attendee#revoke_pass!` setter method set the instance's state so that no pass exists. + +[rfb-instance-variables]: http://ruby-for-beginners.rubymonstas.org/writing_classes/instance_variables.html +[rg-initialize-method]: https://www.rubyguides.com/2019/01/ruby-initialize-method/ +[rg-instance-variables]: https://www.rubyguides.com/2019/07/ruby-instance-variables/ +[rug-instance-variables]: https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html +[gfg-getter-setters]: https://www.geeksforgeeks.org/ruby-getters-and-setters-method/ diff --git a/exercises/concept/instance-variables/.docs/instructions.md b/exercises/concept/instance-variables/.docs/instructions.md new file mode 100644 index 0000000000..c2fc45e37d --- /dev/null +++ b/exercises/concept/instance-variables/.docs/instructions.md @@ -0,0 +1,51 @@ +Working with an amusement park, you've been handed a specification to design a system to administer attendance and rides. You've been tasked with modeling the Attendee (person visiting the park). + +## 1. Make new attendees + +Implement the `Attendee#initialize` method of the `Attendee` class, it should take a height (in centimeters) and store it as an instance variable + +```ruby +Attendee.new(106) +# => # +``` + +## 2. How tall is the attendee + +Implement the `Attendee#height` getter of the `Attendee` class, it should return the instances height + +```ruby +Attendee.new(106).height +# => 106 +``` + +## 3. What is the ride pass' id + +Not all attendees have bought a ride pass, but we need to know if they have a pass or not. Implement the `Attendee#pass_id` getter for the `Attendee` class, it should return the instance's pass_id or `nil` if the Attendee doesn't have one. + +```ruby +Attendee.new(106).pass_id +# => nil +``` + +## 4. Allow people to buy a pass + +Implement `Attendee#issue_pass!` to mutate the state of the instance, and set the pass id instance varaiable to the argument. It should return the pass id. + +```ruby +attendee = Attendee.new(106) +attendee.issue_pass!(42) +attendee.pass_id +# => 42 +``` + +## 4. Revoke the pass + +Some guests break the rules with unsafe behavior, so the park wants to be able to revoke passes. Implement `Attendee#revoke_pass` to mutate the state of the instance, and set the pass id to `nil` + +```ruby +attendee = Attendee.new(106) +attendee.issue_pass!(42) +attendee.revoke_pass! +attendee.pass_id +# => nil +``` diff --git a/exercises/concept/instance-variables/.docs/introduction.md b/exercises/concept/instance-variables/.docs/introduction.md new file mode 100644 index 0000000000..c80e093b47 --- /dev/null +++ b/exercises/concept/instance-variables/.docs/introduction.md @@ -0,0 +1,60 @@ +## Instance Variables + +## Nil + +## Object state, instance variables + +Objects can hold their own state by setting _instance variables_, which are created by prefixing `@` to a variable name. + +```ruby +@name = 2 +``` + +Objects usually set their initial state in an `initialize` method, which is automatically called when calling `new` on a class. + +```ruby +class Airplane + def initialize + @wings = 2 + end +end +``` + +The `initialize` method may also take arguments, so that each instance can start with a custom state: + +```ruby +class Suitcase + def initialize(locked) + @locked = locked + end +end +``` + +Consider _instance_ variables to be private from external read and writes. _Instance_ methods should be used for getting and setting instance variables: + +```ruby +class Suitcase + #... + + def locked? # Query methods should be named with a trailing `?` + @locked + end + + def unlock! # Methods which mutate state should have trailing `!` + @locked = false + end +end +``` + +## Nil + +[Nil][nil-dictionary] is an English word meaning "nothing" or "zero". In Ruby, `nil` is used to express the _absence_ of an object. In other programming languages, `null` or `none` values may play a similar role. + +```ruby +# I do not have a favorite color +favorite_color = nil +``` + +Ruby gives any instance variable the default value of `nil` when it is first encountered, until it is set otherwise. + +[nil-dictionary]: https://www.merriam-webster.com/dictionary/nil diff --git a/exercises/concept/instance-variables/.meta/config.json b/exercises/concept/instance-variables/.meta/config.json new file mode 100644 index 0000000000..5ed7acc579 --- /dev/null +++ b/exercises/concept/instance-variables/.meta/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + { + "github_username": "neenjaw", + "exercism_username": "neenjaw" + }, + { + "github_username": "iHiD", + "exercism_username": "iHiD" + } + ], + "contributors": [ + { + "github_username": "kotp", + "exercism_username": "kotp" + } + ], + "language_versions": ">=2.6.6", + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/instance-variables/.meta/design.md b/exercises/concept/instance-variables/.meta/design.md new file mode 100644 index 0000000000..b7590fdb18 --- /dev/null +++ b/exercises/concept/instance-variables/.meta/design.md @@ -0,0 +1,38 @@ +## Goal + +The goal of this exercise is to teach the student the basics of the concept instance variables and "nil" in Ruby. + +## Learning objectives + +- Know that objects can store state using instance variables +- Know that instance variables should be treated as private and to use getter and setter methods +- Know that `nil` is a Ruby object used to represent "nothingness" +- Know that instance variables are `nil` before they are assigned otherwise + +## Out of scope + +- Boolean values (True/False) +- Truthy/Falsey-ness + +## Concepts + +- `instance-variables` +- `nil` + +## Prerequisites + +- `basics` + +## Resources + +### After + +- [The nil value in Ruby](https://medium.com/rubycademy/the-nil-value-in-ruby-d60e6a3642b9#:~:text=method%20implementation-,The%20nil%20value,%E2%80%9Clack%20of%20an%20object%E2%80%9D.&text=Unlike%20other%20languages%2C%20the%20nil,the%20non%2Dinstantiable%20NilClass%20class.) + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer](https://github.com/exercism/ruby-representer). + +## Analyzer + +This exercise does not require any specific analyzer logic to be added to the [analyzer](https://github.com/exercism/ruby-analyzer). diff --git a/exercises/concept/instance-variables/.meta/exemplar.rb b/exercises/concept/instance-variables/.meta/exemplar.rb new file mode 100644 index 0000000000..49b0af1aec --- /dev/null +++ b/exercises/concept/instance-variables/.meta/exemplar.rb @@ -0,0 +1,21 @@ +class Attendee + def initialize(height) + @height = height + end + + def height + @height + end + + def pass_id + @pass_id + end + + def issue_pass!(pass_id) + @pass_id = pass_id + end + + def revoke_pass! + @pass_id = nil + end +end diff --git a/exercises/concept/instance-variables/attendee.rb b/exercises/concept/instance-variables/attendee.rb new file mode 100644 index 0000000000..ca3a1a088e --- /dev/null +++ b/exercises/concept/instance-variables/attendee.rb @@ -0,0 +1,21 @@ +class Attendee + def initialize(height) + raise NotImplementedError, 'Implement the Attendee#initialize method' + end + + def height + raise NotImplementedError, 'Implement the Attendee#height method' + end + + def pass_id + raise NotImplementedError, 'Implement the Attendee#pass_id method' + end + + def issue_pass!(pass_id) + raise NotImplementedError, 'Implement the Attendee#issue_pass! method' + end + + def revoke_pass! + raise NotImplementedError, 'Implement the Attendee#revoke_pass! method' + end +end diff --git a/exercises/concept/instance-variables/attendee_test.rb b/exercises/concept/instance-variables/attendee_test.rb new file mode 100644 index 0000000000..d6232d2070 --- /dev/null +++ b/exercises/concept/instance-variables/attendee_test.rb @@ -0,0 +1,38 @@ +require 'minitest/autorun' +require_relative 'attendee' + +class AttendeeTest < Minitest::Test + def test_new_instance + height = 100 + assert_equal Attendee, Attendee.new(height).class + end + + def test_new_instance_height + height = 100 + assert_equal height, Attendee.new(height).height + end + + def test_new_instance_pass_id + height = 100 + assert_nil Attendee.new(height).pass_id + end + + def test_issue_pass + height = 100 + attendee = Attendee.new(height) + + pass_id = 1 + attendee.issue_pass!(pass_id) + + assert_equal pass_id, attendee.pass_id + end + + def test_has_pass_after_revoked + height = 100 + attendee = Attendee.new(height) + pass_id = 1 + attendee.issue_pass!(pass_id) + attendee.revoke_pass! + refute attendee.pass_id + end +end diff --git a/exercises/concept/lasagna/.docs/after.md b/exercises/concept/lasagna/.docs/after.md new file mode 100644 index 0000000000..9b14ae5c43 --- /dev/null +++ b/exercises/concept/lasagna/.docs/after.md @@ -0,0 +1,45 @@ +Ruby is a dynamic and strongly typed language. In dynamic languages the type of a variable or object is resolved at runtime, which means that its value or type can be changed up to the very last moment (when it gets parsed by the interpreter). +And what do we mean with strongly typed? Once we know the type of a variable or object, Ruby is strict about what you can do with it, for example: + +```ruby +x = '2' +y = x + 'n' +=> '2n' +``` + +**But** + +````ruby +x = '2' +y = x + 2 +=> TypeError (no implicit conversion of Integer into String) + +Remember, in Ruby everything is an object. Even classes are instances of the class `Class`. For example: + +```ruby +1.class +=> Integer + +Integer.is_a?(Object) +# => true + +Class.is_a?(Object) +# => true +```` + +This means that we can also define classes like this: + +```ruby +Car = Class.new do + def run + 'running' + end +end + +Car.new.run +=> 'running' +``` + +Finally, bear in mind that the `Integer` object holds values that may be defined as one or more (consecutive) digits and its methods support many of the [mathematical operators][integers-docs]. + +[integers-docs]: https://ruby-doc.org/core-2.7.0/Integer.html diff --git a/exercises/concept/lasagna/.docs/hints.md b/exercises/concept/lasagna/.docs/hints.md new file mode 100644 index 0000000000..aa6d55dd2f --- /dev/null +++ b/exercises/concept/lasagna/.docs/hints.md @@ -0,0 +1,30 @@ +## 1. Define the expected oven time in minutes + +- You need to define a [constant][constant] which should contain the [integer][integers] value specified in the recipe. + +## 2. Calculate the remaining oven time in minutes + +- You need to define a [method][methods] with a single parameter for the actual time so far. +- You can [implicitly return an integer][return] from the method. +- You can use the [mathematical operator for subtraction][operators] to subtract values. + +## 3. Calculate the preparation time in minutes + +- You need to define a [method][methods] with a single parameter for the number of layers. +- You can [implicitly return an integer][return] from the method. +- You can use the [mathematical operator for multiplicaton][operators] to multiply values. +- You could define an extra constant for the time in minutes per layer, or use a "magic number" in the code. + +## 4. Calculate the total working time in minutes + +- You need to define a [method][methods] with two named parameters: `number_of_layers` and `actual_minutes_in_oven`. +- You can [implicitly return an integer][return] from the method. +- You can [invoke][invocation] one of the other methods you've defined previously. +- You can use the [mathematical operator for addition][operators] to add values. + +[methods]: https://launchschool.com/books/ruby/read/methods +[return]: https://www.freecodecamp.org/news/idiomatic-ruby-writing-beautiful-code-6845c830c664/ +[operators]: https://www.w3resource.com/ruby/ruby-arithmetic-operators.php +[constants]: https://www.rubyguides.com/2017/07/ruby-constants/ +[invocation]: http://ruby-for-beginners.rubymonstas.org/objects/calling.html +[integers]: https://ruby-doc.org/core-2.7.0/Integer.html diff --git a/exercises/concept/lasagna/.docs/instructions.md b/exercises/concept/lasagna/.docs/instructions.md new file mode 100644 index 0000000000..c8ac1801e9 --- /dev/null +++ b/exercises/concept/lasagna/.docs/instructions.md @@ -0,0 +1,42 @@ +In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book. + +You have four tasks, all related to the time spent cooking the lasagna. + +## 1. Define the expected oven time in minutes + +Define the `Lasagna::EXPECTED_MINUTES_IN_OVEN` constant that returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: + +```ruby +Lasagna::EXPECTED_MINUTES_IN_OVEN +# => 40 +``` + +## 2. Calculate the remaining oven time in minutes + +Define the `Lasagna#remaining_minutes_in_oven` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. + +```ruby +lasagna = Lasagna.new +lasagna.remaining_minutes_in_oven(30) +# => 10 +``` + +## 3. Calculate the preparation time in minutes + +Define the `Lasagna#preparation_time_in_minutes` method that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. + +```ruby +lasagna = Lasagna.new +lasagna.preparation_time_in_minutes(2) +# => 4 +``` + +## 4. Calculate the total working time in minutes + +Define the `Lasagna#total_time_in_minutes` method that takes two named parameters: the `number_of_layers` parameter is the number of layers you added to the lasagna, and the `actual_minutes_in_oven` parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. + +```ruby +lasagna = Lasagna.new +lasagna.total_time_in_minutes(number_of_layers: 3, actual_minutes_in_oven: 20); +# => 26 +``` diff --git a/exercises/concept/lasagna/.docs/introduction.md b/exercises/concept/lasagna/.docs/introduction.md new file mode 100644 index 0000000000..537bc457d9 --- /dev/null +++ b/exercises/concept/lasagna/.docs/introduction.md @@ -0,0 +1,55 @@ +Ruby is a dynamic [object-oriented language][object-oriented-programming]. Everything in Ruby is an [object][object]. + +There are two primary ways to assign objects to names in Ruby - using variables or constants. Variables are always written in [snake case][snake-case]. A variable can reference different objects over its lifetime. For example, `my_first_variable` can be defined and redefined many times using the `=` operator: + +```ruby +my_first_variable = 1 +my_first_variable = "Some string" +my_first_variable = SomeComplexObject.new +``` + +Constants, however, are meant to be assigned once. They must start with capital letters and are normally written in block capitals with words separated by underscores. For example: + +```ruby +MY_FIRST_CONSTANT = 10 + +# Redefining not allowed +# MY_FIRST_CONSTANT = "Some String" +``` + +Ruby is organised into classes. Classes are defined using the `class` keyword followed by the name of the class. Objects are generally created by instantiating classes using the `.new` method. For example: + +```ruby +# Define the class +class Calculator + #... +end + +# Create an instance of it and assign it to a variable +my_first_calc = Calculator.new +``` + +Units of functionality are encapsulated in methods - similar to _functions_ in other languages. A method can optionally be defined with positional arguments, and/or keyword arguments that are defined and called using the `:` syntax. Methods either implicitly return the result of the last evaluated statement, or can explicitly return an object via the `return` keyword. Methods are invoked using `.` syntax. + +```ruby +class Calculator + + # Unnamed params + def add(num1, num2) + return num1 + num2 # Explicit return + end + + # Named params + def multiply(num1:, num2:) + num1 * num2 # Implicit return + end +end + +calc = Calculator.new +calc.add(1, 3) +calc.multiply(num1: 2, num_2: 5) +``` + +[object-oriented-programming]: https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/oothinking.html +[object]: https://github.com/exercism/v3/blob/main/reference/concepts/objects.md +[snake-case]: https://en.wikipedia.org/wiki/Snake_case diff --git a/exercises/concept/lasagna/.meta/config.json b/exercises/concept/lasagna/.meta/config.json new file mode 100644 index 0000000000..a86dec3861 --- /dev/null +++ b/exercises/concept/lasagna/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + { + "github_username": "iHiD", + "exercism_username": "iHiD" + }, + { + "github_username": "pvcarrera", + "exercism_username": "pvcarrera" + } + ], + "files": { + "solution": ["lasagna.rb"], + "test": ["lasagna_test.rb"], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/lasagna/.meta/design.md b/exercises/concept/lasagna/.meta/design.md new file mode 100644 index 0000000000..37a20d6f26 --- /dev/null +++ b/exercises/concept/lasagna/.meta/design.md @@ -0,0 +1,47 @@ +## Goal + +The goal of this exercise is to teach the student the basics of programming in Ruby. + +## Learning objectives + +- Know what a variable is. +- Know how to define a variable. +- Know how to update a variable. +- Know how to define a method. +- Know how to return a value from a method. +- Know how to call a method. +- Know how to call a method with named parameters. +- Know that methods must be defined in classes. +- Know how to define an integer. +- Know how to use mathematical operators on integers. +- Know how to use constants + +## Out of scope + +- Memory and performance characteristics. +- Method overloads. +- Lambdas. +- Optional parameters. +- Organizing methods in namespaces. +- Visibility. + +## Concepts + +The Concepts this exercise unlocks are: + +- `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define an integer; know how to use mathematical operators on integers. + +## Prerequisites + +There are no prerequisites. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer diff --git a/exercises/concept/lasagna/.meta/exemplar.rb b/exercises/concept/lasagna/.meta/exemplar.rb new file mode 100644 index 0000000000..28d835ff23 --- /dev/null +++ b/exercises/concept/lasagna/.meta/exemplar.rb @@ -0,0 +1,16 @@ +class Lasagna + EXPECTED_MINUTES_IN_OVEN = 40 + PREPARATION_MINUTES_PER_LAYER = 2 + + def remaining_minutes_in_oven(actual_minutes_in_oven) + EXPECTED_MINUTES_IN_OVEN - actual_minutes_in_oven + end + + def preparation_time_in_minutes(layers) + layers * PREPARATION_MINUTES_PER_LAYER + end + + def total_time_in_minutes(number_of_layers:, actual_minutes_in_oven:) + preparation_time_in_minutes(number_of_layers) + actual_minutes_in_oven + end +end diff --git a/exercises/concept/lasagna/lasagna.rb b/exercises/concept/lasagna/lasagna.rb new file mode 100644 index 0000000000..09736d8cbb --- /dev/null +++ b/exercises/concept/lasagna/lasagna.rb @@ -0,0 +1,13 @@ +class Lasagna + def remaining_minutes_in_oven(actual_minutes_in_oven) + raise NotImplementedError, 'Please implement the Lasagna#remaining_minutes_in_oven method' + end + + def preparation_time_in_minutes(layers) + raise NotImplementedError, 'Please implement the Lasagna#preparation_time_in_minutes method' + end + + def total_time_in_minutes(number_of_layers:, actual_minutes_in_oven:) + raise NotImplementedError, 'Please implement the Lasagna#total_time_in_minutes method' + end +end diff --git a/exercises/concept/lasagna/lasagna_test.rb b/exercises/concept/lasagna/lasagna_test.rb new file mode 100644 index 0000000000..dc9ab73450 --- /dev/null +++ b/exercises/concept/lasagna/lasagna_test.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require_relative 'lasagna' + +class LasagnaTest < Minitest::Test + def test_expected_minutes_in_oven + assert_equal 40, Lasagna::EXPECTED_MINUTES_IN_OVEN + end + + def test_remaining_minutes_in_oven + assert_equal 15, Lasagna.new.remaining_minutes_in_oven(25) + end + + def test_preparation_time_in_minutes_with_one_layer + assert_equal 2, Lasagna.new.preparation_time_in_minutes(1) + end + + def test_preparation_time_in_minutes_with_multiple_layers + assert_equal 8, Lasagna.new.preparation_time_in_minutes(4) + end + + def test_total_time_in_minutes_for_one_layer + assert_equal 32, Lasagna.new.total_time_in_minutes( + number_of_layers: 1, + actual_minutes_in_oven: 30 + ) + end + + def test_total_time_in_minutes_for_multiple_layer + assert_equal 16, Lasagna.new.total_time_in_minutes( + number_of_layers: 4, + actual_minutes_in_oven: 8 + ) + end +end diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md new file mode 100644 index 0000000000..f84ce5fcb7 --- /dev/null +++ b/exercises/concept/numbers/.docs/hints.md @@ -0,0 +1,17 @@ +## General + +## 1. Calculate the production rate per second + +- Determining the success rate can be done through a [conditional statement][if-else-unless]. +- Multiplication can be done between instances of `Integer` and `Float`. The result will always be an instance of `Float`. +- Numbers can be compared using the built-in [comparison-operators][comparison-operators]. + +## 2. Calculate the number of working items produced per second + +- The `Float` class implements a [method][to_i] to return an instance of `Integer`. +- The `Integer` class implements a [method][to_f] to return an instance of `Float`. + +[comparison-operators]: https://www.w3resource.com/ruby/ruby-comparison-operators.php +[if-else-unless]: https://www.w3resource.com/ruby/ruby-if-else-unless.php +[to_f]: https://apidock.com/ruby/v2_6_3/Integer/to_f +[to_i]: https://apidock.com/ruby/Float/to_i diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md new file mode 100644 index 0000000000..315dcc571f --- /dev/null +++ b/exercises/concept/numbers/.docs/instructions.md @@ -0,0 +1,32 @@ +In this exercise you'll be writing code to analyze the production of an assembly line in a car factory. The assembly line's speed can range from `0` (off) to `10` (maximum). + +At its slowest speed (`1`), `221` cars are produced each hour. The production increases linearly with the speed. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate: + +- `1` to `4`: 100% success rate. +- `5` to `8`: 90% success rate. +- `9`: 80% success rate. +- `10`: 77% success rate. + +You have two tasks. + +## 1. Calculate the production rate per hour + +Implement the `AssemblyLine.production_rate_per_hour` method to calculate the assembly line's production rate per hour, taking into account its success rate: + +```ruby +AssemblyLine.production_rate_per_hour(6) +#=> 1193.4 +``` + +Note that the value returned is an instance of `Float`. + +## 2. Calculate the number of working items produced per minute + +Implement the `AssemblyLine.working_items_per_minute` method to calculate how many working cars are produced per minute: + +```ruby +AssemblyLine.working_items_per_minute(6) +#=> 19 +``` + +Note that the value returned is an instance of `Integer`. diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md new file mode 100644 index 0000000000..86588046a0 --- /dev/null +++ b/exercises/concept/numbers/.docs/introduction.md @@ -0,0 +1,26 @@ +## Numbers + +## Conditionals + +Two common types of numbers in Ruby are: + +- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. +- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. + +They are implemented through the `Integer` and `Float` classes. + +The `Float` and `Integer` classes have methods that will coerce values from one to the other. `Integer` numbers are precise to a whole unit, while `Float` has precision that is fractional to an whole number. + +In this exercise you must conditionally execute logic. A common way to do this in Ruby is by using an `if/else` statement: + +```ruby +x = 5 + +if x == 5 + # Execute logic if x equals 5 +elsif x > 7 + # Execute logic if x greater than 7 +else + # Execute logic in all other cases +end +``` diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json new file mode 100644 index 0000000000..5eb16a15e1 --- /dev/null +++ b/exercises/concept/numbers/.meta/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + { + "github_username": "dvik1950", + "exercism_username": "dvik1950" + } + ], + "contributors": [ + { + "github_username": "kotp", + "exercism_username": "kotp" + }, + { + "github_username": "iHiD", + "exercism_username": "iHiD" + } + ], + "forked_from": ["csharp/numbers"], + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md new file mode 100644 index 0000000000..85b120bbc8 --- /dev/null +++ b/exercises/concept/numbers/.meta/design.md @@ -0,0 +1,42 @@ +## Goal + +The goal of this exercise is to teach the student how the concept of numbers is implemented in Ruby. It will introduce this concept through the two most common numeric types in Ruby: [`Integer`][integer-ruby] (whole number) and [`Float`][float-ruby] (floating-point number). + +## Learning objectives + +- Know of the existence of `Integer` and `Float`. +- Understand that an `Integer` represents whole numbers, and a `Float` represents floating-point numbers. +- Know of basic operators such as multiplication, comparison and equality. +- Know how to conditionally execute code using an `if`, `unless` or `case` statement. + +## Out of scope + +- Any other numeric types besides `Integer` and `Float` (so no `Rational`, `Complex`, `BigDecimal`, etc.). +- Parsing an instance of `String` to an instance of `Integer` or `Float`. +- Coercing an instance of `Integer` or `Float` to an instance of `String`. + +## Concepts + +The Concepts this exercise unlocks are: + +- `numbers`: know of the existence of the two commonly used number types, `Integer` and `Float`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to coerce one numeric type to another +- `conditionals`: know how to conditionally execute code using an `if`, `unless` or `case` statement. + +## Prerequisites + +This exercise's prerequisite Concepts are: + +- `booleans`: know about `true`/`false` and truthy/falsey values. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[integer-ruby]: https://ruby-doc.org/core-2.7.1/Integer.html +[float-ruby]: https://ruby-doc.org/core-2.7.1/Float.html +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer diff --git a/exercises/concept/numbers/.meta/exemplar.rb b/exercises/concept/numbers/.meta/exemplar.rb new file mode 100644 index 0000000000..06752516b7 --- /dev/null +++ b/exercises/concept/numbers/.meta/exemplar.rb @@ -0,0 +1,30 @@ +class AssemblyLine + + CARS_PER_HOUR = 221 + MINUTES_IN_HOUR = 60 + # Success rates + ONE_TO_FOUR_RATE = 1.00 + FIVE_TO_EIGHT_RATE = 0.90 + NINE_RATE = 0.80 + TEN_RATE = 0.77 + + def self.production_rate_per_hour(speed) + CARS_PER_HOUR * speed * success_rate(speed) + end + + def self.working_items_per_minute(speed) + (production_rate_per_hour(speed) / MINUTES_IN_HOUR).to_i + end + + def self.success_rate(speed) + if speed <= 4 + ONE_TO_FOUR_RATE + elsif speed <= 8 + FIVE_TO_EIGHT_RATE + elsif speed <= 9 + NINE_RATE + else + TEN_RATE + end + end +end diff --git a/exercises/concept/numbers/assembly_line.rb b/exercises/concept/numbers/assembly_line.rb new file mode 100644 index 0000000000..08e2a147bb --- /dev/null +++ b/exercises/concept/numbers/assembly_line.rb @@ -0,0 +1,9 @@ +class AssemblyLine + def self.production_rate_per_hour(speed) + raise NotImplementedError, 'Please implement the AssemblyLine.production_rate_per_hour method' + end + + def self.working_items_per_minute(speed) + raise NotImplementedError, 'Please implement the AssemblyLine.working_items_per_minute method' + end +end diff --git a/exercises/concept/numbers/assembly_line_test.rb b/exercises/concept/numbers/assembly_line_test.rb new file mode 100644 index 0000000000..a4e80a49c4 --- /dev/null +++ b/exercises/concept/numbers/assembly_line_test.rb @@ -0,0 +1,52 @@ +require 'minitest/autorun' +require_relative 'assembly_line' + +class AssemblyLineTest < Minitest::Test + def test_production_rate_per_hour_for_speed_zero + assert_equal 0.0, AssemblyLine.production_rate_per_hour(0) + end + + def test_production_rate_per_hour_for_speed_one + assert_equal 221.0, AssemblyLine.production_rate_per_hour(1) + end + + def test_production_rate_per_hour_for_speed_four + assert_equal 884.0, AssemblyLine.production_rate_per_hour(4) + end + + def test_production_rate_per_hour_for_speed_seven + assert_equal 1392.3, AssemblyLine.production_rate_per_hour(7) + end + + def test_production_rate_per_hour_for_speed_nine + assert_equal 1591.2, AssemblyLine.production_rate_per_hour(9) + end + + def test_production_rate_per_hour_for_speed_ten + assert_equal 1701.7, AssemblyLine.production_rate_per_hour(10) + end + + def test_working_items_per_minute_for_speed_zero + assert_equal 0, AssemblyLine.working_items_per_minute(0) + end + + def test_working_items_per_minute_for_speed_one + assert_equal 3, AssemblyLine.working_items_per_minute(1) + end + + def test_working_items_per_minute_for_speed_five + assert_equal 16, AssemblyLine.working_items_per_minute(5) + end + + def test_working_items_per_minute_for_speed_eight + assert_equal 26, AssemblyLine.working_items_per_minute(8) + end + + def test_working_items_per_minute_for_speed_nine + assert_equal 26, AssemblyLine.working_items_per_minute(9) + end + + def test_working_items_per_minute_for_speed_ten + assert_equal 28, AssemblyLine.working_items_per_minute(10) + end +end diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/strings/.docs/hints.md new file mode 100644 index 0000000000..66d46458fd --- /dev/null +++ b/exercises/concept/strings/.docs/hints.md @@ -0,0 +1,23 @@ +## General + +- The [rubymostas strings guide][ruby-for-beginners.rubymonstas.org-strings] has a nice introduction to Ruby strings. +- The `String` object has many useful [built-in methods][docs-string-methods]. + +## 1. Get message from a log line + +- There are different ways to search for text in a string, which can be found on the [Ruby language official documentation][docs-string-methods]. +- There are [built in methods][strip-white-space] to strip white space. + +## 2. Get log level from a log line + +- Ruby `String` objects have a [method][downcase] to perform this operation. + +## 3. Reformat a log line + +- There are several ways to [concatenate strings][ruby-for-beginners.rubymonstas.org-strings], but the preferred one is usually [string interpolation][ruby-for-beginners.rubymonstas.org-strings] + +[ruby-for-beginners.rubymonstas.org-strings]: http://ruby-for-beginners.rubymonstas.org/built_in_classes/strings.html +[ruby-for-beginners.rubymonstas.org-interpolation]: http://ruby-for-beginners.rubymonstas.org/bonus/string_interpolation.html +[docs-string-methods]: https://ruby-doc.org/core-2.7.0/String.html +[strip-white-space]: https://ruby-doc.org/core-2.7.0/String.html#method-i-strip +[downcase]: https://ruby-doc.org/core-2.7.0/String.html#method-i-downcase diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md new file mode 100644 index 0000000000..a12ad4eddf --- /dev/null +++ b/exercises/concept/strings/.docs/instructions.md @@ -0,0 +1,45 @@ +In this exercise you'll be processing log-lines. + +Each log line is a string formatted as follows: `"[]: "`. + +There are three different log levels: + +- `INFO` +- `WARNING` +- `ERROR` + +You have three tasks, each of which will take a log line and ask you to do something with it. + +## 1. Get message from a log line + +Implement the `LogLineParser.message` method to return a log line's message: + +```ruby +LogLineParser.message('[ERROR]: Invalid operation') +// Returns: "Invalid operation" +``` + +Any leading or trailing white space should be removed: + +```ruby +LogLineParser.message('[WARNING]: Disk almost full\r\n') +// Returns: "Disk almost full" +``` + +## 2. Get log level from a log line + +Implement the `LogLineParser.log_level` method to return a log line's log level, which should be returned in lowercase: + +```ruby +LogLineParser.log_level('[ERROR]: Invalid operation') +// Returns: "error" +``` + +## 3. Reformat a log line + +Implement the `LogLineParser.reformat` method that reformats the log line, putting the message first and the log level after it in parentheses: + +```ruby +LogLineParser.reformat('[INFO]: Operation completed') +// Returns: "Operation completed (info)" +``` diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md new file mode 100644 index 0000000000..b2515ab7bf --- /dev/null +++ b/exercises/concept/strings/.docs/introduction.md @@ -0,0 +1 @@ +A `String` in Ruby is an object that holds and manipulates an arbitrary sequence of bytes, typically representing characters. Strings are manipulated by calling the string's methods. diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json new file mode 100644 index 0000000000..f97639477d --- /dev/null +++ b/exercises/concept/strings/.meta/config.json @@ -0,0 +1,13 @@ +{ + "authors": [ + { + "github_username": "pvcarrera", + "exercism_username": "pvcarrera" + } + ], + "files": { + "solution": [], + "test": [], + "exemplar": [".meta/exemplar.rb"] + } +} diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md new file mode 100644 index 0000000000..d66f045444 --- /dev/null +++ b/exercises/concept/strings/.meta/design.md @@ -0,0 +1,38 @@ +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Strings in [Ruby][ruby-doc.org-string]. + +## Learning objectives + +- Know of the existence of the `String` object. +- Know how to create a string. +- Know of some basic string methods (like finding the index of a character at a position, or returning a part the string). +- Know how to do basic string interpolation. + +## Out of scope + +- Using standard or custom format strings. +- Memory and performance characteristics. +- Strings can be a collection. + +## Concepts + +The Concepts this exercise unlocks are: + +- `strings-basic`: know of the existence of the `String` object; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string interpolation. + +## Prerequisites + +There are no prerequisites. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer +[ruby-doc.org-string]: https://ruby-doc.org/core-2.7.0/String.html diff --git a/exercises/concept/strings/.meta/exemplar.rb b/exercises/concept/strings/.meta/exemplar.rb new file mode 100644 index 0000000000..3f6974f86e --- /dev/null +++ b/exercises/concept/strings/.meta/exemplar.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module LogLineParser + def self.message(line) + line.slice(line.index(':') + 1, line.size).strip + end + + def self.log_level(line) + line.slice(1, line.index(']') - 1).downcase + end + + def self.reformat(line) + "#{self.message(line)} (#{self.log_level(line)})" + end +end diff --git a/exercises/concept/strings/log_line_parser.rb b/exercises/concept/strings/log_line_parser.rb new file mode 100644 index 0000000000..238d6f62fc --- /dev/null +++ b/exercises/concept/strings/log_line_parser.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module LogLineParser + def self.message(line) + raise NotImplementedError, 'Please implement the LogLineParser.message method' + end + + def self.log_level(line) + raise NotImplementedError, 'Please implement the LogLineParser.log_level method' + end + + def self.reformat(line) + raise NotImplementedError, 'Please implement the LogLineParser.reformat method' + end +end diff --git a/exercises/concept/strings/log_line_parser_test.rb b/exercises/concept/strings/log_line_parser_test.rb new file mode 100644 index 0000000000..0c8e1cb9be --- /dev/null +++ b/exercises/concept/strings/log_line_parser_test.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'minitest/autorun' +require_relative 'log_line_parser' + +class LogLineParserTest < Minitest::Test + def test_error_message + assert_equal 'Stack overflow', LogLineParser.message('[ERROR]: Stack overflow') + end + + def test_warning_message + assert_equal 'Disk almost full', LogLineParser.message('[WARNING]: Disk almost full') + end + + def test_info_message + assert_equal 'File moved', LogLineParser.message('[INFO]: File moved') + end + + def test_message_with_leading_and_trailing_space + assert_equal 'Timezone not set', LogLineParser.message("[WARNING]: \tTimezone not set \r\n") + end + + def test_error_log_level + assert_equal 'error', LogLineParser.log_level('[ERROR]: Disk full') + end + + def test_warning_log_level + assert_equal 'warning', LogLineParser.log_level('[WARNING]: Unsafe password') + end + + def test_info_log_level + assert_equal 'info', LogLineParser.log_level('[INFO]: Timezone changed') + end + + def test_erro_reformat + assert_equal 'Segmentation fault (error)', LogLineParser.reformat('[ERROR]: Segmentation fault') + end + + def test_warning_reformat + assert_equal 'Decreased performance (warning)', LogLineParser.reformat('[WARNING]: Decreased performance') + end + + def test_info_reformat + assert_equal 'Disk defragmented (info)', LogLineParser.reformat('[INFO]: Disk defragmented') + end + + def rest_reformat_with_leading_and_trailing_space + assert_equal 'Corrupt disk (error)', LogLineParser.reformat("[ERROR]: \t Corrupt disk\t \t \r\n") + end +end diff --git a/exercises/accumulate/.meta/hints.md b/exercises/practice/accumulate/.meta/hints.md similarity index 100% rename from exercises/accumulate/.meta/hints.md rename to exercises/practice/accumulate/.meta/hints.md diff --git a/exercises/accumulate/.meta/solutions/accumulate.rb b/exercises/practice/accumulate/.meta/solutions/accumulate.rb similarity index 100% rename from exercises/accumulate/.meta/solutions/accumulate.rb rename to exercises/practice/accumulate/.meta/solutions/accumulate.rb diff --git a/exercises/accumulate/README.md b/exercises/practice/accumulate/README.md similarity index 100% rename from exercises/accumulate/README.md rename to exercises/practice/accumulate/README.md diff --git a/exercises/accumulate/accumulate.rb b/exercises/practice/accumulate/accumulate.rb similarity index 100% rename from exercises/accumulate/accumulate.rb rename to exercises/practice/accumulate/accumulate.rb diff --git a/exercises/accumulate/accumulate_test.rb b/exercises/practice/accumulate/accumulate_test.rb similarity index 100% rename from exercises/accumulate/accumulate_test.rb rename to exercises/practice/accumulate/accumulate_test.rb diff --git a/exercises/acronym/.meta/generator/acronym_case.rb b/exercises/practice/acronym/.meta/generator/acronym_case.rb similarity index 100% rename from exercises/acronym/.meta/generator/acronym_case.rb rename to exercises/practice/acronym/.meta/generator/acronym_case.rb diff --git a/exercises/acronym/.meta/solutions/acronym.rb b/exercises/practice/acronym/.meta/solutions/acronym.rb similarity index 100% rename from exercises/acronym/.meta/solutions/acronym.rb rename to exercises/practice/acronym/.meta/solutions/acronym.rb diff --git a/exercises/acronym/.meta/tests.toml b/exercises/practice/acronym/.meta/tests.toml similarity index 100% rename from exercises/acronym/.meta/tests.toml rename to exercises/practice/acronym/.meta/tests.toml diff --git a/exercises/acronym/README.md b/exercises/practice/acronym/README.md similarity index 100% rename from exercises/acronym/README.md rename to exercises/practice/acronym/README.md diff --git a/exercises/acronym/acronym.rb b/exercises/practice/acronym/acronym.rb similarity index 100% rename from exercises/acronym/acronym.rb rename to exercises/practice/acronym/acronym.rb diff --git a/exercises/acronym/acronym_test.rb b/exercises/practice/acronym/acronym_test.rb similarity index 100% rename from exercises/acronym/acronym_test.rb rename to exercises/practice/acronym/acronym_test.rb diff --git a/exercises/affine-cipher/.meta/generator/affine_cipher_case.rb b/exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb similarity index 100% rename from exercises/affine-cipher/.meta/generator/affine_cipher_case.rb rename to exercises/practice/affine-cipher/.meta/generator/affine_cipher_case.rb diff --git a/exercises/affine-cipher/.meta/solutions/affine_cipher.rb b/exercises/practice/affine-cipher/.meta/solutions/affine_cipher.rb similarity index 100% rename from exercises/affine-cipher/.meta/solutions/affine_cipher.rb rename to exercises/practice/affine-cipher/.meta/solutions/affine_cipher.rb diff --git a/exercises/affine-cipher/.meta/tests.toml b/exercises/practice/affine-cipher/.meta/tests.toml similarity index 100% rename from exercises/affine-cipher/.meta/tests.toml rename to exercises/practice/affine-cipher/.meta/tests.toml diff --git a/exercises/affine-cipher/README.md b/exercises/practice/affine-cipher/README.md similarity index 100% rename from exercises/affine-cipher/README.md rename to exercises/practice/affine-cipher/README.md diff --git a/exercises/affine-cipher/affine_cipher.rb b/exercises/practice/affine-cipher/affine_cipher.rb similarity index 100% rename from exercises/affine-cipher/affine_cipher.rb rename to exercises/practice/affine-cipher/affine_cipher.rb diff --git a/exercises/affine-cipher/affine_cipher_test.rb b/exercises/practice/affine-cipher/affine_cipher_test.rb similarity index 100% rename from exercises/affine-cipher/affine_cipher_test.rb rename to exercises/practice/affine-cipher/affine_cipher_test.rb diff --git a/exercises/all-your-base/.meta/generator/all_your_base_case.rb b/exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb similarity index 100% rename from exercises/all-your-base/.meta/generator/all_your_base_case.rb rename to exercises/practice/all-your-base/.meta/generator/all_your_base_case.rb diff --git a/exercises/all-your-base/.meta/solutions/all_your_base.rb b/exercises/practice/all-your-base/.meta/solutions/all_your_base.rb similarity index 100% rename from exercises/all-your-base/.meta/solutions/all_your_base.rb rename to exercises/practice/all-your-base/.meta/solutions/all_your_base.rb diff --git a/exercises/all-your-base/.meta/tests.toml b/exercises/practice/all-your-base/.meta/tests.toml similarity index 100% rename from exercises/all-your-base/.meta/tests.toml rename to exercises/practice/all-your-base/.meta/tests.toml diff --git a/exercises/all-your-base/README.md b/exercises/practice/all-your-base/README.md similarity index 100% rename from exercises/all-your-base/README.md rename to exercises/practice/all-your-base/README.md diff --git a/exercises/all-your-base/all_your_base.rb b/exercises/practice/all-your-base/all_your_base.rb similarity index 100% rename from exercises/all-your-base/all_your_base.rb rename to exercises/practice/all-your-base/all_your_base.rb diff --git a/exercises/all-your-base/all_your_base_test.rb b/exercises/practice/all-your-base/all_your_base_test.rb similarity index 100% rename from exercises/all-your-base/all_your_base_test.rb rename to exercises/practice/all-your-base/all_your_base_test.rb diff --git a/exercises/allergies/.meta/generator/allergies_case.rb b/exercises/practice/allergies/.meta/generator/allergies_case.rb similarity index 100% rename from exercises/allergies/.meta/generator/allergies_case.rb rename to exercises/practice/allergies/.meta/generator/allergies_case.rb diff --git a/exercises/allergies/.meta/solutions/allergies.rb b/exercises/practice/allergies/.meta/solutions/allergies.rb similarity index 100% rename from exercises/allergies/.meta/solutions/allergies.rb rename to exercises/practice/allergies/.meta/solutions/allergies.rb diff --git a/exercises/allergies/.meta/tests.toml b/exercises/practice/allergies/.meta/tests.toml similarity index 100% rename from exercises/allergies/.meta/tests.toml rename to exercises/practice/allergies/.meta/tests.toml diff --git a/exercises/allergies/README.md b/exercises/practice/allergies/README.md similarity index 100% rename from exercises/allergies/README.md rename to exercises/practice/allergies/README.md diff --git a/exercises/allergies/allergies.rb b/exercises/practice/allergies/allergies.rb similarity index 100% rename from exercises/allergies/allergies.rb rename to exercises/practice/allergies/allergies.rb diff --git a/exercises/allergies/allergies_test.rb b/exercises/practice/allergies/allergies_test.rb similarity index 100% rename from exercises/allergies/allergies_test.rb rename to exercises/practice/allergies/allergies_test.rb diff --git a/exercises/alphametics/.meta/generator/alphametics_case.rb b/exercises/practice/alphametics/.meta/generator/alphametics_case.rb similarity index 100% rename from exercises/alphametics/.meta/generator/alphametics_case.rb rename to exercises/practice/alphametics/.meta/generator/alphametics_case.rb diff --git a/exercises/alphametics/.meta/solutions/alphametics.rb b/exercises/practice/alphametics/.meta/solutions/alphametics.rb similarity index 100% rename from exercises/alphametics/.meta/solutions/alphametics.rb rename to exercises/practice/alphametics/.meta/solutions/alphametics.rb diff --git a/exercises/alphametics/.meta/solutions/alphametics_compact.rb b/exercises/practice/alphametics/.meta/solutions/alphametics_compact.rb similarity index 100% rename from exercises/alphametics/.meta/solutions/alphametics_compact.rb rename to exercises/practice/alphametics/.meta/solutions/alphametics_compact.rb diff --git a/exercises/alphametics/.meta/tests.toml b/exercises/practice/alphametics/.meta/tests.toml similarity index 100% rename from exercises/alphametics/.meta/tests.toml rename to exercises/practice/alphametics/.meta/tests.toml diff --git a/exercises/alphametics/README.md b/exercises/practice/alphametics/README.md similarity index 100% rename from exercises/alphametics/README.md rename to exercises/practice/alphametics/README.md diff --git a/exercises/alphametics/alphametics.rb b/exercises/practice/alphametics/alphametics.rb similarity index 100% rename from exercises/alphametics/alphametics.rb rename to exercises/practice/alphametics/alphametics.rb diff --git a/exercises/alphametics/alphametics_test.rb b/exercises/practice/alphametics/alphametics_test.rb similarity index 100% rename from exercises/alphametics/alphametics_test.rb rename to exercises/practice/alphametics/alphametics_test.rb diff --git a/exercises/anagram/.meta/generator/anagram_case.rb b/exercises/practice/anagram/.meta/generator/anagram_case.rb similarity index 100% rename from exercises/anagram/.meta/generator/anagram_case.rb rename to exercises/practice/anagram/.meta/generator/anagram_case.rb diff --git a/exercises/anagram/.meta/solutions/anagram.rb b/exercises/practice/anagram/.meta/solutions/anagram.rb similarity index 100% rename from exercises/anagram/.meta/solutions/anagram.rb rename to exercises/practice/anagram/.meta/solutions/anagram.rb diff --git a/exercises/anagram/.meta/tests.toml b/exercises/practice/anagram/.meta/tests.toml similarity index 100% rename from exercises/anagram/.meta/tests.toml rename to exercises/practice/anagram/.meta/tests.toml diff --git a/exercises/anagram/README.md b/exercises/practice/anagram/README.md similarity index 100% rename from exercises/anagram/README.md rename to exercises/practice/anagram/README.md diff --git a/exercises/anagram/anagram.rb b/exercises/practice/anagram/anagram.rb similarity index 100% rename from exercises/anagram/anagram.rb rename to exercises/practice/anagram/anagram.rb diff --git a/exercises/anagram/anagram_test.rb b/exercises/practice/anagram/anagram_test.rb similarity index 100% rename from exercises/anagram/anagram_test.rb rename to exercises/practice/anagram/anagram_test.rb diff --git a/exercises/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb b/exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb similarity index 100% rename from exercises/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb rename to exercises/practice/armstrong-numbers/.meta/generator/armstrong_numbers_case.rb diff --git a/exercises/armstrong-numbers/.meta/solutions/armstrong_numbers.rb b/exercises/practice/armstrong-numbers/.meta/solutions/armstrong_numbers.rb similarity index 100% rename from exercises/armstrong-numbers/.meta/solutions/armstrong_numbers.rb rename to exercises/practice/armstrong-numbers/.meta/solutions/armstrong_numbers.rb diff --git a/exercises/armstrong-numbers/.meta/tests.toml b/exercises/practice/armstrong-numbers/.meta/tests.toml similarity index 100% rename from exercises/armstrong-numbers/.meta/tests.toml rename to exercises/practice/armstrong-numbers/.meta/tests.toml diff --git a/exercises/armstrong-numbers/README.md b/exercises/practice/armstrong-numbers/README.md similarity index 100% rename from exercises/armstrong-numbers/README.md rename to exercises/practice/armstrong-numbers/README.md diff --git a/exercises/armstrong-numbers/armstrong_numbers.rb b/exercises/practice/armstrong-numbers/armstrong_numbers.rb similarity index 100% rename from exercises/armstrong-numbers/armstrong_numbers.rb rename to exercises/practice/armstrong-numbers/armstrong_numbers.rb diff --git a/exercises/armstrong-numbers/armstrong_numbers_test.rb b/exercises/practice/armstrong-numbers/armstrong_numbers_test.rb similarity index 100% rename from exercises/armstrong-numbers/armstrong_numbers_test.rb rename to exercises/practice/armstrong-numbers/armstrong_numbers_test.rb diff --git a/exercises/atbash-cipher/.meta/generator/atbash_cipher_case.rb b/exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb similarity index 100% rename from exercises/atbash-cipher/.meta/generator/atbash_cipher_case.rb rename to exercises/practice/atbash-cipher/.meta/generator/atbash_cipher_case.rb diff --git a/exercises/atbash-cipher/.meta/solutions/atbash_cipher.rb b/exercises/practice/atbash-cipher/.meta/solutions/atbash_cipher.rb similarity index 100% rename from exercises/atbash-cipher/.meta/solutions/atbash_cipher.rb rename to exercises/practice/atbash-cipher/.meta/solutions/atbash_cipher.rb diff --git a/exercises/atbash-cipher/.meta/tests.toml b/exercises/practice/atbash-cipher/.meta/tests.toml similarity index 100% rename from exercises/atbash-cipher/.meta/tests.toml rename to exercises/practice/atbash-cipher/.meta/tests.toml diff --git a/exercises/atbash-cipher/README.md b/exercises/practice/atbash-cipher/README.md similarity index 100% rename from exercises/atbash-cipher/README.md rename to exercises/practice/atbash-cipher/README.md diff --git a/exercises/atbash-cipher/atbash_cipher.rb b/exercises/practice/atbash-cipher/atbash_cipher.rb similarity index 100% rename from exercises/atbash-cipher/atbash_cipher.rb rename to exercises/practice/atbash-cipher/atbash_cipher.rb diff --git a/exercises/atbash-cipher/atbash_cipher_test.rb b/exercises/practice/atbash-cipher/atbash_cipher_test.rb similarity index 100% rename from exercises/atbash-cipher/atbash_cipher_test.rb rename to exercises/practice/atbash-cipher/atbash_cipher_test.rb diff --git a/exercises/beer-song/.meta/generator/beer_song_case.rb b/exercises/practice/beer-song/.meta/generator/beer_song_case.rb similarity index 100% rename from exercises/beer-song/.meta/generator/beer_song_case.rb rename to exercises/practice/beer-song/.meta/generator/beer_song_case.rb diff --git a/exercises/beer-song/.meta/solutions/beer_song.rb b/exercises/practice/beer-song/.meta/solutions/beer_song.rb similarity index 100% rename from exercises/beer-song/.meta/solutions/beer_song.rb rename to exercises/practice/beer-song/.meta/solutions/beer_song.rb diff --git a/exercises/beer-song/.meta/tests.toml b/exercises/practice/beer-song/.meta/tests.toml similarity index 100% rename from exercises/beer-song/.meta/tests.toml rename to exercises/practice/beer-song/.meta/tests.toml diff --git a/exercises/beer-song/README.md b/exercises/practice/beer-song/README.md similarity index 100% rename from exercises/beer-song/README.md rename to exercises/practice/beer-song/README.md diff --git a/exercises/beer-song/beer_song.rb b/exercises/practice/beer-song/beer_song.rb similarity index 100% rename from exercises/beer-song/beer_song.rb rename to exercises/practice/beer-song/beer_song.rb diff --git a/exercises/beer-song/beer_song_test.rb b/exercises/practice/beer-song/beer_song_test.rb similarity index 100% rename from exercises/beer-song/beer_song_test.rb rename to exercises/practice/beer-song/beer_song_test.rb diff --git a/exercises/binary-search-tree/.meta/solutions/binary_search_tree.rb b/exercises/practice/binary-search-tree/.meta/solutions/binary_search_tree.rb similarity index 100% rename from exercises/binary-search-tree/.meta/solutions/binary_search_tree.rb rename to exercises/practice/binary-search-tree/.meta/solutions/binary_search_tree.rb diff --git a/exercises/binary-search-tree/.meta/tests.toml b/exercises/practice/binary-search-tree/.meta/tests.toml similarity index 100% rename from exercises/binary-search-tree/.meta/tests.toml rename to exercises/practice/binary-search-tree/.meta/tests.toml diff --git a/exercises/binary-search-tree/README.md b/exercises/practice/binary-search-tree/README.md similarity index 100% rename from exercises/binary-search-tree/README.md rename to exercises/practice/binary-search-tree/README.md diff --git a/exercises/binary-search-tree/binary_search_tree.rb b/exercises/practice/binary-search-tree/binary_search_tree.rb similarity index 100% rename from exercises/binary-search-tree/binary_search_tree.rb rename to exercises/practice/binary-search-tree/binary_search_tree.rb diff --git a/exercises/binary-search-tree/binary_search_tree_test.rb b/exercises/practice/binary-search-tree/binary_search_tree_test.rb similarity index 100% rename from exercises/binary-search-tree/binary_search_tree_test.rb rename to exercises/practice/binary-search-tree/binary_search_tree_test.rb diff --git a/exercises/binary-search/.meta/generator/binary_search_case.rb b/exercises/practice/binary-search/.meta/generator/binary_search_case.rb similarity index 100% rename from exercises/binary-search/.meta/generator/binary_search_case.rb rename to exercises/practice/binary-search/.meta/generator/binary_search_case.rb diff --git a/exercises/binary-search/.meta/solutions/binary_search.rb b/exercises/practice/binary-search/.meta/solutions/binary_search.rb similarity index 100% rename from exercises/binary-search/.meta/solutions/binary_search.rb rename to exercises/practice/binary-search/.meta/solutions/binary_search.rb diff --git a/exercises/binary-search/.meta/tests.toml b/exercises/practice/binary-search/.meta/tests.toml similarity index 100% rename from exercises/binary-search/.meta/tests.toml rename to exercises/practice/binary-search/.meta/tests.toml diff --git a/exercises/binary-search/README.md b/exercises/practice/binary-search/README.md similarity index 100% rename from exercises/binary-search/README.md rename to exercises/practice/binary-search/README.md diff --git a/exercises/binary-search/binary_search.rb b/exercises/practice/binary-search/binary_search.rb similarity index 100% rename from exercises/binary-search/binary_search.rb rename to exercises/practice/binary-search/binary_search.rb diff --git a/exercises/binary-search/binary_search_test.rb b/exercises/practice/binary-search/binary_search_test.rb similarity index 100% rename from exercises/binary-search/binary_search_test.rb rename to exercises/practice/binary-search/binary_search_test.rb diff --git a/exercises/binary/.meta/generator/binary_case.rb b/exercises/practice/binary/.meta/generator/binary_case.rb similarity index 100% rename from exercises/binary/.meta/generator/binary_case.rb rename to exercises/practice/binary/.meta/generator/binary_case.rb diff --git a/exercises/binary/.meta/solutions/binary.rb b/exercises/practice/binary/.meta/solutions/binary.rb similarity index 100% rename from exercises/binary/.meta/solutions/binary.rb rename to exercises/practice/binary/.meta/solutions/binary.rb diff --git a/exercises/binary/.meta/tests.toml b/exercises/practice/binary/.meta/tests.toml similarity index 100% rename from exercises/binary/.meta/tests.toml rename to exercises/practice/binary/.meta/tests.toml diff --git a/exercises/binary/README.md b/exercises/practice/binary/README.md similarity index 100% rename from exercises/binary/README.md rename to exercises/practice/binary/README.md diff --git a/exercises/binary/binary.rb b/exercises/practice/binary/binary.rb similarity index 100% rename from exercises/binary/binary.rb rename to exercises/practice/binary/binary.rb diff --git a/exercises/binary/binary_test.rb b/exercises/practice/binary/binary_test.rb similarity index 100% rename from exercises/binary/binary_test.rb rename to exercises/practice/binary/binary_test.rb diff --git a/exercises/bob/.meta/generator/bob_case.rb b/exercises/practice/bob/.meta/generator/bob_case.rb similarity index 100% rename from exercises/bob/.meta/generator/bob_case.rb rename to exercises/practice/bob/.meta/generator/bob_case.rb diff --git a/exercises/bob/.meta/solutions/bob.rb b/exercises/practice/bob/.meta/solutions/bob.rb similarity index 100% rename from exercises/bob/.meta/solutions/bob.rb rename to exercises/practice/bob/.meta/solutions/bob.rb diff --git a/exercises/bob/.meta/tests.toml b/exercises/practice/bob/.meta/tests.toml similarity index 100% rename from exercises/bob/.meta/tests.toml rename to exercises/practice/bob/.meta/tests.toml diff --git a/exercises/bob/README.md b/exercises/practice/bob/README.md similarity index 100% rename from exercises/bob/README.md rename to exercises/practice/bob/README.md diff --git a/exercises/bob/bob.rb b/exercises/practice/bob/bob.rb similarity index 100% rename from exercises/bob/bob.rb rename to exercises/practice/bob/bob.rb diff --git a/exercises/bob/bob_test.rb b/exercises/practice/bob/bob_test.rb similarity index 100% rename from exercises/bob/bob_test.rb rename to exercises/practice/bob/bob_test.rb diff --git a/exercises/book-store/.meta/generator/book_store_case.rb b/exercises/practice/book-store/.meta/generator/book_store_case.rb similarity index 100% rename from exercises/book-store/.meta/generator/book_store_case.rb rename to exercises/practice/book-store/.meta/generator/book_store_case.rb diff --git a/exercises/book-store/.meta/solutions/book_store.rb b/exercises/practice/book-store/.meta/solutions/book_store.rb similarity index 100% rename from exercises/book-store/.meta/solutions/book_store.rb rename to exercises/practice/book-store/.meta/solutions/book_store.rb diff --git a/exercises/book-store/.meta/tests.toml b/exercises/practice/book-store/.meta/tests.toml similarity index 100% rename from exercises/book-store/.meta/tests.toml rename to exercises/practice/book-store/.meta/tests.toml diff --git a/exercises/book-store/README.md b/exercises/practice/book-store/README.md similarity index 100% rename from exercises/book-store/README.md rename to exercises/practice/book-store/README.md diff --git a/exercises/book-store/book_store.rb b/exercises/practice/book-store/book_store.rb similarity index 100% rename from exercises/book-store/book_store.rb rename to exercises/practice/book-store/book_store.rb diff --git a/exercises/book-store/book_store_test.rb b/exercises/practice/book-store/book_store_test.rb similarity index 100% rename from exercises/book-store/book_store_test.rb rename to exercises/practice/book-store/book_store_test.rb diff --git a/exercises/bowling/.meta/generator/bowling_case.rb b/exercises/practice/bowling/.meta/generator/bowling_case.rb similarity index 100% rename from exercises/bowling/.meta/generator/bowling_case.rb rename to exercises/practice/bowling/.meta/generator/bowling_case.rb diff --git a/exercises/bowling/.meta/solutions/bowling.rb b/exercises/practice/bowling/.meta/solutions/bowling.rb similarity index 100% rename from exercises/bowling/.meta/solutions/bowling.rb rename to exercises/practice/bowling/.meta/solutions/bowling.rb diff --git a/exercises/bowling/.meta/tests.toml b/exercises/practice/bowling/.meta/tests.toml similarity index 100% rename from exercises/bowling/.meta/tests.toml rename to exercises/practice/bowling/.meta/tests.toml diff --git a/exercises/bowling/README.md b/exercises/practice/bowling/README.md similarity index 100% rename from exercises/bowling/README.md rename to exercises/practice/bowling/README.md diff --git a/exercises/bowling/bowling.rb b/exercises/practice/bowling/bowling.rb similarity index 100% rename from exercises/bowling/bowling.rb rename to exercises/practice/bowling/bowling.rb diff --git a/exercises/bowling/bowling_test.rb b/exercises/practice/bowling/bowling_test.rb similarity index 100% rename from exercises/bowling/bowling_test.rb rename to exercises/practice/bowling/bowling_test.rb diff --git a/exercises/change/.meta/generator/change_case.rb b/exercises/practice/change/.meta/generator/change_case.rb similarity index 100% rename from exercises/change/.meta/generator/change_case.rb rename to exercises/practice/change/.meta/generator/change_case.rb diff --git a/exercises/change/.meta/solutions/change.rb b/exercises/practice/change/.meta/solutions/change.rb similarity index 100% rename from exercises/change/.meta/solutions/change.rb rename to exercises/practice/change/.meta/solutions/change.rb diff --git a/exercises/change/.meta/tests.toml b/exercises/practice/change/.meta/tests.toml similarity index 100% rename from exercises/change/.meta/tests.toml rename to exercises/practice/change/.meta/tests.toml diff --git a/exercises/change/README.md b/exercises/practice/change/README.md similarity index 100% rename from exercises/change/README.md rename to exercises/practice/change/README.md diff --git a/exercises/change/change.rb b/exercises/practice/change/change.rb similarity index 100% rename from exercises/change/change.rb rename to exercises/practice/change/change.rb diff --git a/exercises/change/change_test.rb b/exercises/practice/change/change_test.rb similarity index 100% rename from exercises/change/change_test.rb rename to exercises/practice/change/change_test.rb diff --git a/exercises/circular-buffer/.meta/solutions/circular_buffer.rb b/exercises/practice/circular-buffer/.meta/solutions/circular_buffer.rb similarity index 100% rename from exercises/circular-buffer/.meta/solutions/circular_buffer.rb rename to exercises/practice/circular-buffer/.meta/solutions/circular_buffer.rb diff --git a/exercises/circular-buffer/.meta/tests.toml b/exercises/practice/circular-buffer/.meta/tests.toml similarity index 100% rename from exercises/circular-buffer/.meta/tests.toml rename to exercises/practice/circular-buffer/.meta/tests.toml diff --git a/exercises/circular-buffer/README.md b/exercises/practice/circular-buffer/README.md similarity index 100% rename from exercises/circular-buffer/README.md rename to exercises/practice/circular-buffer/README.md diff --git a/exercises/circular-buffer/circular_buffer.rb b/exercises/practice/circular-buffer/circular_buffer.rb similarity index 100% rename from exercises/circular-buffer/circular_buffer.rb rename to exercises/practice/circular-buffer/circular_buffer.rb diff --git a/exercises/circular-buffer/circular_buffer_test.rb b/exercises/practice/circular-buffer/circular_buffer_test.rb similarity index 100% rename from exercises/circular-buffer/circular_buffer_test.rb rename to exercises/practice/circular-buffer/circular_buffer_test.rb diff --git a/exercises/clock/.meta/generator/clock_case.rb b/exercises/practice/clock/.meta/generator/clock_case.rb similarity index 100% rename from exercises/clock/.meta/generator/clock_case.rb rename to exercises/practice/clock/.meta/generator/clock_case.rb diff --git a/exercises/clock/.meta/solutions/clock.rb b/exercises/practice/clock/.meta/solutions/clock.rb similarity index 100% rename from exercises/clock/.meta/solutions/clock.rb rename to exercises/practice/clock/.meta/solutions/clock.rb diff --git a/exercises/clock/.meta/tests.toml b/exercises/practice/clock/.meta/tests.toml similarity index 100% rename from exercises/clock/.meta/tests.toml rename to exercises/practice/clock/.meta/tests.toml diff --git a/exercises/clock/README.md b/exercises/practice/clock/README.md similarity index 100% rename from exercises/clock/README.md rename to exercises/practice/clock/README.md diff --git a/exercises/clock/clock.rb b/exercises/practice/clock/clock.rb similarity index 100% rename from exercises/clock/clock.rb rename to exercises/practice/clock/clock.rb diff --git a/exercises/clock/clock_test.rb b/exercises/practice/clock/clock_test.rb similarity index 100% rename from exercises/clock/clock_test.rb rename to exercises/practice/clock/clock_test.rb diff --git a/exercises/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb b/exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb similarity index 100% rename from exercises/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb rename to exercises/practice/collatz-conjecture/.meta/generator/collatz_conjecture_case.rb diff --git a/exercises/collatz-conjecture/.meta/solutions/collatz_conjecture.rb b/exercises/practice/collatz-conjecture/.meta/solutions/collatz_conjecture.rb similarity index 100% rename from exercises/collatz-conjecture/.meta/solutions/collatz_conjecture.rb rename to exercises/practice/collatz-conjecture/.meta/solutions/collatz_conjecture.rb diff --git a/exercises/collatz-conjecture/.meta/tests.toml b/exercises/practice/collatz-conjecture/.meta/tests.toml similarity index 100% rename from exercises/collatz-conjecture/.meta/tests.toml rename to exercises/practice/collatz-conjecture/.meta/tests.toml diff --git a/exercises/collatz-conjecture/README.md b/exercises/practice/collatz-conjecture/README.md similarity index 100% rename from exercises/collatz-conjecture/README.md rename to exercises/practice/collatz-conjecture/README.md diff --git a/exercises/collatz-conjecture/collatz_conjecture.rb b/exercises/practice/collatz-conjecture/collatz_conjecture.rb similarity index 100% rename from exercises/collatz-conjecture/collatz_conjecture.rb rename to exercises/practice/collatz-conjecture/collatz_conjecture.rb diff --git a/exercises/collatz-conjecture/collatz_conjecture_test.rb b/exercises/practice/collatz-conjecture/collatz_conjecture_test.rb similarity index 100% rename from exercises/collatz-conjecture/collatz_conjecture_test.rb rename to exercises/practice/collatz-conjecture/collatz_conjecture_test.rb diff --git a/exercises/complex-numbers/.meta/generator/complex_numbers_case.rb b/exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb similarity index 100% rename from exercises/complex-numbers/.meta/generator/complex_numbers_case.rb rename to exercises/practice/complex-numbers/.meta/generator/complex_numbers_case.rb diff --git a/exercises/complex-numbers/.meta/solutions/complex_numbers.rb b/exercises/practice/complex-numbers/.meta/solutions/complex_numbers.rb similarity index 100% rename from exercises/complex-numbers/.meta/solutions/complex_numbers.rb rename to exercises/practice/complex-numbers/.meta/solutions/complex_numbers.rb diff --git a/exercises/complex-numbers/.meta/tests.toml b/exercises/practice/complex-numbers/.meta/tests.toml similarity index 100% rename from exercises/complex-numbers/.meta/tests.toml rename to exercises/practice/complex-numbers/.meta/tests.toml diff --git a/exercises/complex-numbers/README.md b/exercises/practice/complex-numbers/README.md similarity index 100% rename from exercises/complex-numbers/README.md rename to exercises/practice/complex-numbers/README.md diff --git a/exercises/complex-numbers/complex_numbers.rb b/exercises/practice/complex-numbers/complex_numbers.rb similarity index 100% rename from exercises/complex-numbers/complex_numbers.rb rename to exercises/practice/complex-numbers/complex_numbers.rb diff --git a/exercises/complex-numbers/complex_numbers_test.rb b/exercises/practice/complex-numbers/complex_numbers_test.rb similarity index 100% rename from exercises/complex-numbers/complex_numbers_test.rb rename to exercises/practice/complex-numbers/complex_numbers_test.rb diff --git a/exercises/connect/.meta/generator/connect_case.rb b/exercises/practice/connect/.meta/generator/connect_case.rb similarity index 100% rename from exercises/connect/.meta/generator/connect_case.rb rename to exercises/practice/connect/.meta/generator/connect_case.rb diff --git a/exercises/connect/.meta/solutions/connect.rb b/exercises/practice/connect/.meta/solutions/connect.rb similarity index 100% rename from exercises/connect/.meta/solutions/connect.rb rename to exercises/practice/connect/.meta/solutions/connect.rb diff --git a/exercises/connect/.meta/tests.toml b/exercises/practice/connect/.meta/tests.toml similarity index 100% rename from exercises/connect/.meta/tests.toml rename to exercises/practice/connect/.meta/tests.toml diff --git a/exercises/connect/README.md b/exercises/practice/connect/README.md similarity index 100% rename from exercises/connect/README.md rename to exercises/practice/connect/README.md diff --git a/exercises/connect/connect.rb b/exercises/practice/connect/connect.rb similarity index 100% rename from exercises/connect/connect.rb rename to exercises/practice/connect/connect.rb diff --git a/exercises/connect/connect_test.rb b/exercises/practice/connect/connect_test.rb similarity index 100% rename from exercises/connect/connect_test.rb rename to exercises/practice/connect/connect_test.rb diff --git a/exercises/crypto-square/.meta/generator/crypto_square_case.rb b/exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb similarity index 100% rename from exercises/crypto-square/.meta/generator/crypto_square_case.rb rename to exercises/practice/crypto-square/.meta/generator/crypto_square_case.rb diff --git a/exercises/crypto-square/.meta/solutions/crypto_square.rb b/exercises/practice/crypto-square/.meta/solutions/crypto_square.rb similarity index 100% rename from exercises/crypto-square/.meta/solutions/crypto_square.rb rename to exercises/practice/crypto-square/.meta/solutions/crypto_square.rb diff --git a/exercises/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml similarity index 100% rename from exercises/crypto-square/.meta/tests.toml rename to exercises/practice/crypto-square/.meta/tests.toml diff --git a/exercises/crypto-square/README.md b/exercises/practice/crypto-square/README.md similarity index 100% rename from exercises/crypto-square/README.md rename to exercises/practice/crypto-square/README.md diff --git a/exercises/crypto-square/crypto_square.rb b/exercises/practice/crypto-square/crypto_square.rb similarity index 100% rename from exercises/crypto-square/crypto_square.rb rename to exercises/practice/crypto-square/crypto_square.rb diff --git a/exercises/crypto-square/crypto_square_test.rb b/exercises/practice/crypto-square/crypto_square_test.rb similarity index 100% rename from exercises/crypto-square/crypto_square_test.rb rename to exercises/practice/crypto-square/crypto_square_test.rb diff --git a/exercises/custom-set/.meta/generator/custom_set_case.rb b/exercises/practice/custom-set/.meta/generator/custom_set_case.rb similarity index 100% rename from exercises/custom-set/.meta/generator/custom_set_case.rb rename to exercises/practice/custom-set/.meta/generator/custom_set_case.rb diff --git a/exercises/custom-set/.meta/solutions/custom_set.rb b/exercises/practice/custom-set/.meta/solutions/custom_set.rb similarity index 100% rename from exercises/custom-set/.meta/solutions/custom_set.rb rename to exercises/practice/custom-set/.meta/solutions/custom_set.rb diff --git a/exercises/custom-set/.meta/tests.toml b/exercises/practice/custom-set/.meta/tests.toml similarity index 100% rename from exercises/custom-set/.meta/tests.toml rename to exercises/practice/custom-set/.meta/tests.toml diff --git a/exercises/custom-set/README.md b/exercises/practice/custom-set/README.md similarity index 100% rename from exercises/custom-set/README.md rename to exercises/practice/custom-set/README.md diff --git a/exercises/custom-set/custom_set.rb b/exercises/practice/custom-set/custom_set.rb similarity index 100% rename from exercises/custom-set/custom_set.rb rename to exercises/practice/custom-set/custom_set.rb diff --git a/exercises/custom-set/custom_set_test.rb b/exercises/practice/custom-set/custom_set_test.rb similarity index 100% rename from exercises/custom-set/custom_set_test.rb rename to exercises/practice/custom-set/custom_set_test.rb diff --git a/exercises/darts/.meta/generator/darts_case.rb b/exercises/practice/darts/.meta/generator/darts_case.rb similarity index 100% rename from exercises/darts/.meta/generator/darts_case.rb rename to exercises/practice/darts/.meta/generator/darts_case.rb diff --git a/exercises/darts/.meta/solutions/darts.rb b/exercises/practice/darts/.meta/solutions/darts.rb similarity index 100% rename from exercises/darts/.meta/solutions/darts.rb rename to exercises/practice/darts/.meta/solutions/darts.rb diff --git a/exercises/darts/.meta/tests.toml b/exercises/practice/darts/.meta/tests.toml similarity index 100% rename from exercises/darts/.meta/tests.toml rename to exercises/practice/darts/.meta/tests.toml diff --git a/exercises/darts/README.md b/exercises/practice/darts/README.md similarity index 100% rename from exercises/darts/README.md rename to exercises/practice/darts/README.md diff --git a/exercises/darts/darts.rb b/exercises/practice/darts/darts.rb similarity index 100% rename from exercises/darts/darts.rb rename to exercises/practice/darts/darts.rb diff --git a/exercises/darts/darts_test.rb b/exercises/practice/darts/darts_test.rb similarity index 100% rename from exercises/darts/darts_test.rb rename to exercises/practice/darts/darts_test.rb diff --git a/exercises/diamond/.meta/solutions/diamond.rb b/exercises/practice/diamond/.meta/solutions/diamond.rb similarity index 100% rename from exercises/diamond/.meta/solutions/diamond.rb rename to exercises/practice/diamond/.meta/solutions/diamond.rb diff --git a/exercises/diamond/.meta/tests.toml b/exercises/practice/diamond/.meta/tests.toml similarity index 100% rename from exercises/diamond/.meta/tests.toml rename to exercises/practice/diamond/.meta/tests.toml diff --git a/exercises/diamond/README.md b/exercises/practice/diamond/README.md similarity index 100% rename from exercises/diamond/README.md rename to exercises/practice/diamond/README.md diff --git a/exercises/diamond/diamond.rb b/exercises/practice/diamond/diamond.rb similarity index 100% rename from exercises/diamond/diamond.rb rename to exercises/practice/diamond/diamond.rb diff --git a/exercises/diamond/diamond_test.rb b/exercises/practice/diamond/diamond_test.rb similarity index 100% rename from exercises/diamond/diamond_test.rb rename to exercises/practice/diamond/diamond_test.rb diff --git a/exercises/difference-of-squares/.meta/generator/difference_of_squares_case.rb b/exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb similarity index 100% rename from exercises/difference-of-squares/.meta/generator/difference_of_squares_case.rb rename to exercises/practice/difference-of-squares/.meta/generator/difference_of_squares_case.rb diff --git a/exercises/difference-of-squares/.meta/solutions/difference_of_squares.rb b/exercises/practice/difference-of-squares/.meta/solutions/difference_of_squares.rb similarity index 100% rename from exercises/difference-of-squares/.meta/solutions/difference_of_squares.rb rename to exercises/practice/difference-of-squares/.meta/solutions/difference_of_squares.rb diff --git a/exercises/difference-of-squares/.meta/tests.toml b/exercises/practice/difference-of-squares/.meta/tests.toml similarity index 100% rename from exercises/difference-of-squares/.meta/tests.toml rename to exercises/practice/difference-of-squares/.meta/tests.toml diff --git a/exercises/difference-of-squares/README.md b/exercises/practice/difference-of-squares/README.md similarity index 100% rename from exercises/difference-of-squares/README.md rename to exercises/practice/difference-of-squares/README.md diff --git a/exercises/difference-of-squares/difference_of_squares.rb b/exercises/practice/difference-of-squares/difference_of_squares.rb similarity index 100% rename from exercises/difference-of-squares/difference_of_squares.rb rename to exercises/practice/difference-of-squares/difference_of_squares.rb diff --git a/exercises/difference-of-squares/difference_of_squares_test.rb b/exercises/practice/difference-of-squares/difference_of_squares_test.rb similarity index 100% rename from exercises/difference-of-squares/difference_of_squares_test.rb rename to exercises/practice/difference-of-squares/difference_of_squares_test.rb diff --git a/exercises/dominoes/.meta/generator/dominoes_case.rb b/exercises/practice/dominoes/.meta/generator/dominoes_case.rb similarity index 100% rename from exercises/dominoes/.meta/generator/dominoes_case.rb rename to exercises/practice/dominoes/.meta/generator/dominoes_case.rb diff --git a/exercises/dominoes/.meta/solutions/dominoes.rb b/exercises/practice/dominoes/.meta/solutions/dominoes.rb similarity index 100% rename from exercises/dominoes/.meta/solutions/dominoes.rb rename to exercises/practice/dominoes/.meta/solutions/dominoes.rb diff --git a/exercises/dominoes/.meta/tests.toml b/exercises/practice/dominoes/.meta/tests.toml similarity index 100% rename from exercises/dominoes/.meta/tests.toml rename to exercises/practice/dominoes/.meta/tests.toml diff --git a/exercises/dominoes/README.md b/exercises/practice/dominoes/README.md similarity index 100% rename from exercises/dominoes/README.md rename to exercises/practice/dominoes/README.md diff --git a/exercises/dominoes/dominoes.rb b/exercises/practice/dominoes/dominoes.rb similarity index 100% rename from exercises/dominoes/dominoes.rb rename to exercises/practice/dominoes/dominoes.rb diff --git a/exercises/dominoes/dominoes_test.rb b/exercises/practice/dominoes/dominoes_test.rb similarity index 100% rename from exercises/dominoes/dominoes_test.rb rename to exercises/practice/dominoes/dominoes_test.rb diff --git a/exercises/etl/.meta/generator/etl_case.rb b/exercises/practice/etl/.meta/generator/etl_case.rb similarity index 100% rename from exercises/etl/.meta/generator/etl_case.rb rename to exercises/practice/etl/.meta/generator/etl_case.rb diff --git a/exercises/etl/.meta/solutions/etl.rb b/exercises/practice/etl/.meta/solutions/etl.rb similarity index 100% rename from exercises/etl/.meta/solutions/etl.rb rename to exercises/practice/etl/.meta/solutions/etl.rb diff --git a/exercises/etl/.meta/tests.toml b/exercises/practice/etl/.meta/tests.toml similarity index 100% rename from exercises/etl/.meta/tests.toml rename to exercises/practice/etl/.meta/tests.toml diff --git a/exercises/etl/README.md b/exercises/practice/etl/README.md similarity index 100% rename from exercises/etl/README.md rename to exercises/practice/etl/README.md diff --git a/exercises/etl/etl.rb b/exercises/practice/etl/etl.rb similarity index 100% rename from exercises/etl/etl.rb rename to exercises/practice/etl/etl.rb diff --git a/exercises/etl/etl_test.rb b/exercises/practice/etl/etl_test.rb similarity index 100% rename from exercises/etl/etl_test.rb rename to exercises/practice/etl/etl_test.rb diff --git a/exercises/flatten-array/.meta/generator/flatten_array_case.rb b/exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb similarity index 100% rename from exercises/flatten-array/.meta/generator/flatten_array_case.rb rename to exercises/practice/flatten-array/.meta/generator/flatten_array_case.rb diff --git a/exercises/flatten-array/.meta/solutions/flatten_array.rb b/exercises/practice/flatten-array/.meta/solutions/flatten_array.rb similarity index 100% rename from exercises/flatten-array/.meta/solutions/flatten_array.rb rename to exercises/practice/flatten-array/.meta/solutions/flatten_array.rb diff --git a/exercises/flatten-array/.meta/tests.toml b/exercises/practice/flatten-array/.meta/tests.toml similarity index 100% rename from exercises/flatten-array/.meta/tests.toml rename to exercises/practice/flatten-array/.meta/tests.toml diff --git a/exercises/flatten-array/README.md b/exercises/practice/flatten-array/README.md similarity index 100% rename from exercises/flatten-array/README.md rename to exercises/practice/flatten-array/README.md diff --git a/exercises/flatten-array/flatten_array.rb b/exercises/practice/flatten-array/flatten_array.rb similarity index 100% rename from exercises/flatten-array/flatten_array.rb rename to exercises/practice/flatten-array/flatten_array.rb diff --git a/exercises/flatten-array/flatten_array_test.rb b/exercises/practice/flatten-array/flatten_array_test.rb similarity index 100% rename from exercises/flatten-array/flatten_array_test.rb rename to exercises/practice/flatten-array/flatten_array_test.rb diff --git a/exercises/food-chain/.meta/solutions/food_chain.rb b/exercises/practice/food-chain/.meta/solutions/food_chain.rb similarity index 100% rename from exercises/food-chain/.meta/solutions/food_chain.rb rename to exercises/practice/food-chain/.meta/solutions/food_chain.rb diff --git a/exercises/food-chain/.meta/tests.toml b/exercises/practice/food-chain/.meta/tests.toml similarity index 100% rename from exercises/food-chain/.meta/tests.toml rename to exercises/practice/food-chain/.meta/tests.toml diff --git a/exercises/food-chain/README.md b/exercises/practice/food-chain/README.md similarity index 100% rename from exercises/food-chain/README.md rename to exercises/practice/food-chain/README.md diff --git a/exercises/food-chain/food_chain.rb b/exercises/practice/food-chain/food_chain.rb similarity index 100% rename from exercises/food-chain/food_chain.rb rename to exercises/practice/food-chain/food_chain.rb diff --git a/exercises/food-chain/food_chain_test.rb b/exercises/practice/food-chain/food_chain_test.rb similarity index 100% rename from exercises/food-chain/food_chain_test.rb rename to exercises/practice/food-chain/food_chain_test.rb diff --git a/exercises/food-chain/song.txt b/exercises/practice/food-chain/song.txt similarity index 100% rename from exercises/food-chain/song.txt rename to exercises/practice/food-chain/song.txt diff --git a/exercises/gigasecond/.meta/generator/gigasecond_case.rb b/exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb similarity index 100% rename from exercises/gigasecond/.meta/generator/gigasecond_case.rb rename to exercises/practice/gigasecond/.meta/generator/gigasecond_case.rb diff --git a/exercises/gigasecond/.meta/solutions/gigasecond.rb b/exercises/practice/gigasecond/.meta/solutions/gigasecond.rb similarity index 100% rename from exercises/gigasecond/.meta/solutions/gigasecond.rb rename to exercises/practice/gigasecond/.meta/solutions/gigasecond.rb diff --git a/exercises/gigasecond/.meta/tests.toml b/exercises/practice/gigasecond/.meta/tests.toml similarity index 100% rename from exercises/gigasecond/.meta/tests.toml rename to exercises/practice/gigasecond/.meta/tests.toml diff --git a/exercises/gigasecond/README.md b/exercises/practice/gigasecond/README.md similarity index 100% rename from exercises/gigasecond/README.md rename to exercises/practice/gigasecond/README.md diff --git a/exercises/gigasecond/gigasecond.rb b/exercises/practice/gigasecond/gigasecond.rb similarity index 100% rename from exercises/gigasecond/gigasecond.rb rename to exercises/practice/gigasecond/gigasecond.rb diff --git a/exercises/gigasecond/gigasecond_test.rb b/exercises/practice/gigasecond/gigasecond_test.rb similarity index 100% rename from exercises/gigasecond/gigasecond_test.rb rename to exercises/practice/gigasecond/gigasecond_test.rb diff --git a/exercises/grade-school/.meta/solutions/grade_school.rb b/exercises/practice/grade-school/.meta/solutions/grade_school.rb similarity index 100% rename from exercises/grade-school/.meta/solutions/grade_school.rb rename to exercises/practice/grade-school/.meta/solutions/grade_school.rb diff --git a/exercises/grade-school/.meta/tests.toml b/exercises/practice/grade-school/.meta/tests.toml similarity index 100% rename from exercises/grade-school/.meta/tests.toml rename to exercises/practice/grade-school/.meta/tests.toml diff --git a/exercises/grade-school/README.md b/exercises/practice/grade-school/README.md similarity index 100% rename from exercises/grade-school/README.md rename to exercises/practice/grade-school/README.md diff --git a/exercises/grade-school/grade_school.rb b/exercises/practice/grade-school/grade_school.rb similarity index 100% rename from exercises/grade-school/grade_school.rb rename to exercises/practice/grade-school/grade_school.rb diff --git a/exercises/grade-school/grade_school_test.rb b/exercises/practice/grade-school/grade_school_test.rb similarity index 100% rename from exercises/grade-school/grade_school_test.rb rename to exercises/practice/grade-school/grade_school_test.rb diff --git a/exercises/grains/.meta/generator/grains_case.rb b/exercises/practice/grains/.meta/generator/grains_case.rb similarity index 100% rename from exercises/grains/.meta/generator/grains_case.rb rename to exercises/practice/grains/.meta/generator/grains_case.rb diff --git a/exercises/grains/.meta/solutions/grains.rb b/exercises/practice/grains/.meta/solutions/grains.rb similarity index 100% rename from exercises/grains/.meta/solutions/grains.rb rename to exercises/practice/grains/.meta/solutions/grains.rb diff --git a/exercises/grains/README.md b/exercises/practice/grains/README.md similarity index 100% rename from exercises/grains/README.md rename to exercises/practice/grains/README.md diff --git a/exercises/grains/grains.rb b/exercises/practice/grains/grains.rb similarity index 100% rename from exercises/grains/grains.rb rename to exercises/practice/grains/grains.rb diff --git a/exercises/grains/grains_test.rb b/exercises/practice/grains/grains_test.rb similarity index 100% rename from exercises/grains/grains_test.rb rename to exercises/practice/grains/grains_test.rb diff --git a/exercises/grep/.meta/generator/grep_case.rb b/exercises/practice/grep/.meta/generator/grep_case.rb similarity index 100% rename from exercises/grep/.meta/generator/grep_case.rb rename to exercises/practice/grep/.meta/generator/grep_case.rb diff --git a/exercises/grep/.meta/generator/test_template.erb b/exercises/practice/grep/.meta/generator/test_template.erb similarity index 100% rename from exercises/grep/.meta/generator/test_template.erb rename to exercises/practice/grep/.meta/generator/test_template.erb diff --git a/exercises/grep/.meta/solutions/grep.rb b/exercises/practice/grep/.meta/solutions/grep.rb similarity index 100% rename from exercises/grep/.meta/solutions/grep.rb rename to exercises/practice/grep/.meta/solutions/grep.rb diff --git a/exercises/grep/.meta/tests.toml b/exercises/practice/grep/.meta/tests.toml similarity index 100% rename from exercises/grep/.meta/tests.toml rename to exercises/practice/grep/.meta/tests.toml diff --git a/exercises/grep/README.md b/exercises/practice/grep/README.md similarity index 100% rename from exercises/grep/README.md rename to exercises/practice/grep/README.md diff --git a/exercises/grep/grep.rb b/exercises/practice/grep/grep.rb similarity index 100% rename from exercises/grep/grep.rb rename to exercises/practice/grep/grep.rb diff --git a/exercises/grep/grep_test.rb b/exercises/practice/grep/grep_test.rb similarity index 100% rename from exercises/grep/grep_test.rb rename to exercises/practice/grep/grep_test.rb diff --git a/exercises/hamming/.meta/generator/hamming_case.rb b/exercises/practice/hamming/.meta/generator/hamming_case.rb similarity index 100% rename from exercises/hamming/.meta/generator/hamming_case.rb rename to exercises/practice/hamming/.meta/generator/hamming_case.rb diff --git a/exercises/hamming/.meta/solutions/hamming.rb b/exercises/practice/hamming/.meta/solutions/hamming.rb similarity index 100% rename from exercises/hamming/.meta/solutions/hamming.rb rename to exercises/practice/hamming/.meta/solutions/hamming.rb diff --git a/exercises/hamming/.meta/tests.toml b/exercises/practice/hamming/.meta/tests.toml similarity index 100% rename from exercises/hamming/.meta/tests.toml rename to exercises/practice/hamming/.meta/tests.toml diff --git a/exercises/hamming/README.md b/exercises/practice/hamming/README.md similarity index 100% rename from exercises/hamming/README.md rename to exercises/practice/hamming/README.md diff --git a/exercises/hamming/RUNNING_TESTS.md b/exercises/practice/hamming/RUNNING_TESTS.md similarity index 100% rename from exercises/hamming/RUNNING_TESTS.md rename to exercises/practice/hamming/RUNNING_TESTS.md diff --git a/exercises/hamming/hamming.rb b/exercises/practice/hamming/hamming.rb similarity index 100% rename from exercises/hamming/hamming.rb rename to exercises/practice/hamming/hamming.rb diff --git a/exercises/hamming/hamming_test.rb b/exercises/practice/hamming/hamming_test.rb similarity index 100% rename from exercises/hamming/hamming_test.rb rename to exercises/practice/hamming/hamming_test.rb diff --git a/exercises/hello-world/.meta/generator/hello_world_case.rb b/exercises/practice/hello-world/.meta/generator/hello_world_case.rb similarity index 100% rename from exercises/hello-world/.meta/generator/hello_world_case.rb rename to exercises/practice/hello-world/.meta/generator/hello_world_case.rb diff --git a/exercises/hello-world/.meta/generator/test_template.erb b/exercises/practice/hello-world/.meta/generator/test_template.erb similarity index 100% rename from exercises/hello-world/.meta/generator/test_template.erb rename to exercises/practice/hello-world/.meta/generator/test_template.erb diff --git a/exercises/hello-world/.meta/solutions/hello_world.rb b/exercises/practice/hello-world/.meta/solutions/hello_world.rb similarity index 100% rename from exercises/hello-world/.meta/solutions/hello_world.rb rename to exercises/practice/hello-world/.meta/solutions/hello_world.rb diff --git a/exercises/hello-world/.meta/tests.toml b/exercises/practice/hello-world/.meta/tests.toml similarity index 100% rename from exercises/hello-world/.meta/tests.toml rename to exercises/practice/hello-world/.meta/tests.toml diff --git a/exercises/hello-world/GETTING_STARTED.md b/exercises/practice/hello-world/GETTING_STARTED.md similarity index 100% rename from exercises/hello-world/GETTING_STARTED.md rename to exercises/practice/hello-world/GETTING_STARTED.md diff --git a/exercises/hello-world/README.md b/exercises/practice/hello-world/README.md similarity index 100% rename from exercises/hello-world/README.md rename to exercises/practice/hello-world/README.md diff --git a/exercises/hello-world/hello_world.rb b/exercises/practice/hello-world/hello_world.rb similarity index 100% rename from exercises/hello-world/hello_world.rb rename to exercises/practice/hello-world/hello_world.rb diff --git a/exercises/hello-world/hello_world_test.rb b/exercises/practice/hello-world/hello_world_test.rb similarity index 100% rename from exercises/hello-world/hello_world_test.rb rename to exercises/practice/hello-world/hello_world_test.rb diff --git a/exercises/hexadecimal/.meta/solutions/hexadecimal.rb b/exercises/practice/hexadecimal/.meta/solutions/hexadecimal.rb similarity index 100% rename from exercises/hexadecimal/.meta/solutions/hexadecimal.rb rename to exercises/practice/hexadecimal/.meta/solutions/hexadecimal.rb diff --git a/exercises/hexadecimal/README.md b/exercises/practice/hexadecimal/README.md similarity index 100% rename from exercises/hexadecimal/README.md rename to exercises/practice/hexadecimal/README.md diff --git a/exercises/hexadecimal/hexadecimal.rb b/exercises/practice/hexadecimal/hexadecimal.rb similarity index 100% rename from exercises/hexadecimal/hexadecimal.rb rename to exercises/practice/hexadecimal/hexadecimal.rb diff --git a/exercises/hexadecimal/hexadecimal_test.rb b/exercises/practice/hexadecimal/hexadecimal_test.rb similarity index 100% rename from exercises/hexadecimal/hexadecimal_test.rb rename to exercises/practice/hexadecimal/hexadecimal_test.rb diff --git a/exercises/high-scores/.meta/generator/high_scores_case.rb b/exercises/practice/high-scores/.meta/generator/high_scores_case.rb similarity index 100% rename from exercises/high-scores/.meta/generator/high_scores_case.rb rename to exercises/practice/high-scores/.meta/generator/high_scores_case.rb diff --git a/exercises/high-scores/.meta/hints.md b/exercises/practice/high-scores/.meta/hints.md similarity index 100% rename from exercises/high-scores/.meta/hints.md rename to exercises/practice/high-scores/.meta/hints.md diff --git a/exercises/high-scores/.meta/solutions/high_scores.rb b/exercises/practice/high-scores/.meta/solutions/high_scores.rb similarity index 100% rename from exercises/high-scores/.meta/solutions/high_scores.rb rename to exercises/practice/high-scores/.meta/solutions/high_scores.rb diff --git a/exercises/high-scores/.meta/tests.toml b/exercises/practice/high-scores/.meta/tests.toml similarity index 100% rename from exercises/high-scores/.meta/tests.toml rename to exercises/practice/high-scores/.meta/tests.toml diff --git a/exercises/high-scores/README.md b/exercises/practice/high-scores/README.md similarity index 100% rename from exercises/high-scores/README.md rename to exercises/practice/high-scores/README.md diff --git a/exercises/high-scores/high_scores.rb b/exercises/practice/high-scores/high_scores.rb similarity index 100% rename from exercises/high-scores/high_scores.rb rename to exercises/practice/high-scores/high_scores.rb diff --git a/exercises/high-scores/high_scores_test.rb b/exercises/practice/high-scores/high_scores_test.rb similarity index 100% rename from exercises/high-scores/high_scores_test.rb rename to exercises/practice/high-scores/high_scores_test.rb diff --git a/exercises/house/.meta/solutions/house.rb b/exercises/practice/house/.meta/solutions/house.rb similarity index 100% rename from exercises/house/.meta/solutions/house.rb rename to exercises/practice/house/.meta/solutions/house.rb diff --git a/exercises/house/.meta/tests.toml b/exercises/practice/house/.meta/tests.toml similarity index 100% rename from exercises/house/.meta/tests.toml rename to exercises/practice/house/.meta/tests.toml diff --git a/exercises/house/README.md b/exercises/practice/house/README.md similarity index 100% rename from exercises/house/README.md rename to exercises/practice/house/README.md diff --git a/exercises/house/house.rb b/exercises/practice/house/house.rb similarity index 100% rename from exercises/house/house.rb rename to exercises/practice/house/house.rb diff --git a/exercises/house/house_test.rb b/exercises/practice/house/house_test.rb similarity index 100% rename from exercises/house/house_test.rb rename to exercises/practice/house/house_test.rb diff --git a/exercises/isbn-verifier/.meta/generator/isbn_verifier_case.rb b/exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb similarity index 100% rename from exercises/isbn-verifier/.meta/generator/isbn_verifier_case.rb rename to exercises/practice/isbn-verifier/.meta/generator/isbn_verifier_case.rb diff --git a/exercises/isbn-verifier/.meta/solutions/isbn_verifier.rb b/exercises/practice/isbn-verifier/.meta/solutions/isbn_verifier.rb similarity index 100% rename from exercises/isbn-verifier/.meta/solutions/isbn_verifier.rb rename to exercises/practice/isbn-verifier/.meta/solutions/isbn_verifier.rb diff --git a/exercises/isbn-verifier/.meta/tests.toml b/exercises/practice/isbn-verifier/.meta/tests.toml similarity index 100% rename from exercises/isbn-verifier/.meta/tests.toml rename to exercises/practice/isbn-verifier/.meta/tests.toml diff --git a/exercises/isbn-verifier/README.md b/exercises/practice/isbn-verifier/README.md similarity index 100% rename from exercises/isbn-verifier/README.md rename to exercises/practice/isbn-verifier/README.md diff --git a/exercises/isbn-verifier/isbn_verifier.rb b/exercises/practice/isbn-verifier/isbn_verifier.rb similarity index 100% rename from exercises/isbn-verifier/isbn_verifier.rb rename to exercises/practice/isbn-verifier/isbn_verifier.rb diff --git a/exercises/isbn-verifier/isbn_verifier_test.rb b/exercises/practice/isbn-verifier/isbn_verifier_test.rb similarity index 100% rename from exercises/isbn-verifier/isbn_verifier_test.rb rename to exercises/practice/isbn-verifier/isbn_verifier_test.rb diff --git a/exercises/isogram/.meta/generator/isogram_case.rb b/exercises/practice/isogram/.meta/generator/isogram_case.rb similarity index 100% rename from exercises/isogram/.meta/generator/isogram_case.rb rename to exercises/practice/isogram/.meta/generator/isogram_case.rb diff --git a/exercises/isogram/.meta/solutions/isogram.rb b/exercises/practice/isogram/.meta/solutions/isogram.rb similarity index 100% rename from exercises/isogram/.meta/solutions/isogram.rb rename to exercises/practice/isogram/.meta/solutions/isogram.rb diff --git a/exercises/isogram/.meta/tests.toml b/exercises/practice/isogram/.meta/tests.toml similarity index 100% rename from exercises/isogram/.meta/tests.toml rename to exercises/practice/isogram/.meta/tests.toml diff --git a/exercises/isogram/README.md b/exercises/practice/isogram/README.md similarity index 100% rename from exercises/isogram/README.md rename to exercises/practice/isogram/README.md diff --git a/exercises/isogram/isogram.rb b/exercises/practice/isogram/isogram.rb similarity index 100% rename from exercises/isogram/isogram.rb rename to exercises/practice/isogram/isogram.rb diff --git a/exercises/isogram/isogram_test.rb b/exercises/practice/isogram/isogram_test.rb similarity index 100% rename from exercises/isogram/isogram_test.rb rename to exercises/practice/isogram/isogram_test.rb diff --git a/exercises/kindergarten-garden/.meta/solutions/kindergarten_garden.rb b/exercises/practice/kindergarten-garden/.meta/solutions/kindergarten_garden.rb similarity index 100% rename from exercises/kindergarten-garden/.meta/solutions/kindergarten_garden.rb rename to exercises/practice/kindergarten-garden/.meta/solutions/kindergarten_garden.rb diff --git a/exercises/kindergarten-garden/.meta/tests.toml b/exercises/practice/kindergarten-garden/.meta/tests.toml similarity index 100% rename from exercises/kindergarten-garden/.meta/tests.toml rename to exercises/practice/kindergarten-garden/.meta/tests.toml diff --git a/exercises/kindergarten-garden/README.md b/exercises/practice/kindergarten-garden/README.md similarity index 100% rename from exercises/kindergarten-garden/README.md rename to exercises/practice/kindergarten-garden/README.md diff --git a/exercises/kindergarten-garden/kindergarten_garden.rb b/exercises/practice/kindergarten-garden/kindergarten_garden.rb similarity index 100% rename from exercises/kindergarten-garden/kindergarten_garden.rb rename to exercises/practice/kindergarten-garden/kindergarten_garden.rb diff --git a/exercises/kindergarten-garden/kindergarten_garden_test.rb b/exercises/practice/kindergarten-garden/kindergarten_garden_test.rb similarity index 100% rename from exercises/kindergarten-garden/kindergarten_garden_test.rb rename to exercises/practice/kindergarten-garden/kindergarten_garden_test.rb diff --git a/exercises/largest-series-product/.meta/generator/largest_series_product_case.rb b/exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb similarity index 100% rename from exercises/largest-series-product/.meta/generator/largest_series_product_case.rb rename to exercises/practice/largest-series-product/.meta/generator/largest_series_product_case.rb diff --git a/exercises/largest-series-product/.meta/solutions/largest_series_product.rb b/exercises/practice/largest-series-product/.meta/solutions/largest_series_product.rb similarity index 100% rename from exercises/largest-series-product/.meta/solutions/largest_series_product.rb rename to exercises/practice/largest-series-product/.meta/solutions/largest_series_product.rb diff --git a/exercises/largest-series-product/.meta/tests.toml b/exercises/practice/largest-series-product/.meta/tests.toml similarity index 100% rename from exercises/largest-series-product/.meta/tests.toml rename to exercises/practice/largest-series-product/.meta/tests.toml diff --git a/exercises/largest-series-product/README.md b/exercises/practice/largest-series-product/README.md similarity index 100% rename from exercises/largest-series-product/README.md rename to exercises/practice/largest-series-product/README.md diff --git a/exercises/largest-series-product/largest_series_product.rb b/exercises/practice/largest-series-product/largest_series_product.rb similarity index 100% rename from exercises/largest-series-product/largest_series_product.rb rename to exercises/practice/largest-series-product/largest_series_product.rb diff --git a/exercises/largest-series-product/largest_series_product_test.rb b/exercises/practice/largest-series-product/largest_series_product_test.rb similarity index 100% rename from exercises/largest-series-product/largest_series_product_test.rb rename to exercises/practice/largest-series-product/largest_series_product_test.rb diff --git a/exercises/leap/.meta/generator/leap_case.rb b/exercises/practice/leap/.meta/generator/leap_case.rb similarity index 100% rename from exercises/leap/.meta/generator/leap_case.rb rename to exercises/practice/leap/.meta/generator/leap_case.rb diff --git a/exercises/leap/.meta/generator/test_template.erb b/exercises/practice/leap/.meta/generator/test_template.erb similarity index 100% rename from exercises/leap/.meta/generator/test_template.erb rename to exercises/practice/leap/.meta/generator/test_template.erb diff --git a/exercises/leap/.meta/solutions/leap.rb b/exercises/practice/leap/.meta/solutions/leap.rb similarity index 100% rename from exercises/leap/.meta/solutions/leap.rb rename to exercises/practice/leap/.meta/solutions/leap.rb diff --git a/exercises/leap/.meta/tests.toml b/exercises/practice/leap/.meta/tests.toml similarity index 100% rename from exercises/leap/.meta/tests.toml rename to exercises/practice/leap/.meta/tests.toml diff --git a/exercises/leap/README.md b/exercises/practice/leap/README.md similarity index 100% rename from exercises/leap/README.md rename to exercises/practice/leap/README.md diff --git a/exercises/leap/leap.rb b/exercises/practice/leap/leap.rb similarity index 100% rename from exercises/leap/leap.rb rename to exercises/practice/leap/leap.rb diff --git a/exercises/leap/leap_test.rb b/exercises/practice/leap/leap_test.rb similarity index 100% rename from exercises/leap/leap_test.rb rename to exercises/practice/leap/leap_test.rb diff --git a/exercises/linked-list/.meta/solutions/linked_list.rb b/exercises/practice/linked-list/.meta/solutions/linked_list.rb similarity index 100% rename from exercises/linked-list/.meta/solutions/linked_list.rb rename to exercises/practice/linked-list/.meta/solutions/linked_list.rb diff --git a/exercises/linked-list/README.md b/exercises/practice/linked-list/README.md similarity index 100% rename from exercises/linked-list/README.md rename to exercises/practice/linked-list/README.md diff --git a/exercises/linked-list/linked_list.rb b/exercises/practice/linked-list/linked_list.rb similarity index 100% rename from exercises/linked-list/linked_list.rb rename to exercises/practice/linked-list/linked_list.rb diff --git a/exercises/linked-list/linked_list_test.rb b/exercises/practice/linked-list/linked_list_test.rb similarity index 100% rename from exercises/linked-list/linked_list_test.rb rename to exercises/practice/linked-list/linked_list_test.rb diff --git a/exercises/list-ops/.meta/solutions/list_ops.rb b/exercises/practice/list-ops/.meta/solutions/list_ops.rb similarity index 100% rename from exercises/list-ops/.meta/solutions/list_ops.rb rename to exercises/practice/list-ops/.meta/solutions/list_ops.rb diff --git a/exercises/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml similarity index 100% rename from exercises/list-ops/.meta/tests.toml rename to exercises/practice/list-ops/.meta/tests.toml diff --git a/exercises/list-ops/README.md b/exercises/practice/list-ops/README.md similarity index 100% rename from exercises/list-ops/README.md rename to exercises/practice/list-ops/README.md diff --git a/exercises/list-ops/list_ops.rb b/exercises/practice/list-ops/list_ops.rb similarity index 100% rename from exercises/list-ops/list_ops.rb rename to exercises/practice/list-ops/list_ops.rb diff --git a/exercises/list-ops/list_ops_test.rb b/exercises/practice/list-ops/list_ops_test.rb similarity index 100% rename from exercises/list-ops/list_ops_test.rb rename to exercises/practice/list-ops/list_ops_test.rb diff --git a/exercises/luhn/.meta/generator/luhn_case.rb b/exercises/practice/luhn/.meta/generator/luhn_case.rb similarity index 100% rename from exercises/luhn/.meta/generator/luhn_case.rb rename to exercises/practice/luhn/.meta/generator/luhn_case.rb diff --git a/exercises/luhn/.meta/solutions/luhn.rb b/exercises/practice/luhn/.meta/solutions/luhn.rb similarity index 100% rename from exercises/luhn/.meta/solutions/luhn.rb rename to exercises/practice/luhn/.meta/solutions/luhn.rb diff --git a/exercises/luhn/.meta/tests.toml b/exercises/practice/luhn/.meta/tests.toml similarity index 100% rename from exercises/luhn/.meta/tests.toml rename to exercises/practice/luhn/.meta/tests.toml diff --git a/exercises/luhn/README.md b/exercises/practice/luhn/README.md similarity index 100% rename from exercises/luhn/README.md rename to exercises/practice/luhn/README.md diff --git a/exercises/luhn/luhn.rb b/exercises/practice/luhn/luhn.rb similarity index 100% rename from exercises/luhn/luhn.rb rename to exercises/practice/luhn/luhn.rb diff --git a/exercises/luhn/luhn_test.rb b/exercises/practice/luhn/luhn_test.rb similarity index 100% rename from exercises/luhn/luhn_test.rb rename to exercises/practice/luhn/luhn_test.rb diff --git a/exercises/matching-brackets/.meta/generator/matching_brackets_case.rb b/exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb similarity index 100% rename from exercises/matching-brackets/.meta/generator/matching_brackets_case.rb rename to exercises/practice/matching-brackets/.meta/generator/matching_brackets_case.rb diff --git a/exercises/matching-brackets/.meta/solutions/matching_brackets.rb b/exercises/practice/matching-brackets/.meta/solutions/matching_brackets.rb similarity index 100% rename from exercises/matching-brackets/.meta/solutions/matching_brackets.rb rename to exercises/practice/matching-brackets/.meta/solutions/matching_brackets.rb diff --git a/exercises/matching-brackets/.meta/tests.toml b/exercises/practice/matching-brackets/.meta/tests.toml similarity index 100% rename from exercises/matching-brackets/.meta/tests.toml rename to exercises/practice/matching-brackets/.meta/tests.toml diff --git a/exercises/matching-brackets/README.md b/exercises/practice/matching-brackets/README.md similarity index 100% rename from exercises/matching-brackets/README.md rename to exercises/practice/matching-brackets/README.md diff --git a/exercises/matching-brackets/matching_brackets.rb b/exercises/practice/matching-brackets/matching_brackets.rb similarity index 100% rename from exercises/matching-brackets/matching_brackets.rb rename to exercises/practice/matching-brackets/matching_brackets.rb diff --git a/exercises/matching-brackets/matching_brackets_test.rb b/exercises/practice/matching-brackets/matching_brackets_test.rb similarity index 100% rename from exercises/matching-brackets/matching_brackets_test.rb rename to exercises/practice/matching-brackets/matching_brackets_test.rb diff --git a/exercises/matrix/.meta/solutions/matrix.rb b/exercises/practice/matrix/.meta/solutions/matrix.rb similarity index 100% rename from exercises/matrix/.meta/solutions/matrix.rb rename to exercises/practice/matrix/.meta/solutions/matrix.rb diff --git a/exercises/matrix/.meta/tests.toml b/exercises/practice/matrix/.meta/tests.toml similarity index 100% rename from exercises/matrix/.meta/tests.toml rename to exercises/practice/matrix/.meta/tests.toml diff --git a/exercises/matrix/README.md b/exercises/practice/matrix/README.md similarity index 100% rename from exercises/matrix/README.md rename to exercises/practice/matrix/README.md diff --git a/exercises/matrix/matrix.rb b/exercises/practice/matrix/matrix.rb similarity index 100% rename from exercises/matrix/matrix.rb rename to exercises/practice/matrix/matrix.rb diff --git a/exercises/matrix/matrix_test.rb b/exercises/practice/matrix/matrix_test.rb similarity index 100% rename from exercises/matrix/matrix_test.rb rename to exercises/practice/matrix/matrix_test.rb diff --git a/exercises/meetup/.meta/generator/meetup_case.rb b/exercises/practice/meetup/.meta/generator/meetup_case.rb similarity index 100% rename from exercises/meetup/.meta/generator/meetup_case.rb rename to exercises/practice/meetup/.meta/generator/meetup_case.rb diff --git a/exercises/meetup/.meta/solutions/meetup.rb b/exercises/practice/meetup/.meta/solutions/meetup.rb similarity index 100% rename from exercises/meetup/.meta/solutions/meetup.rb rename to exercises/practice/meetup/.meta/solutions/meetup.rb diff --git a/exercises/meetup/.meta/tests.toml b/exercises/practice/meetup/.meta/tests.toml similarity index 100% rename from exercises/meetup/.meta/tests.toml rename to exercises/practice/meetup/.meta/tests.toml diff --git a/exercises/meetup/README.md b/exercises/practice/meetup/README.md similarity index 100% rename from exercises/meetup/README.md rename to exercises/practice/meetup/README.md diff --git a/exercises/meetup/meetup.rb b/exercises/practice/meetup/meetup.rb similarity index 100% rename from exercises/meetup/meetup.rb rename to exercises/practice/meetup/meetup.rb diff --git a/exercises/meetup/meetup_test.rb b/exercises/practice/meetup/meetup_test.rb similarity index 100% rename from exercises/meetup/meetup_test.rb rename to exercises/practice/meetup/meetup_test.rb diff --git a/exercises/microwave/.meta/solutions/microwave.rb b/exercises/practice/microwave/.meta/solutions/microwave.rb similarity index 100% rename from exercises/microwave/.meta/solutions/microwave.rb rename to exercises/practice/microwave/.meta/solutions/microwave.rb diff --git a/exercises/microwave/README.md b/exercises/practice/microwave/README.md similarity index 100% rename from exercises/microwave/README.md rename to exercises/practice/microwave/README.md diff --git a/exercises/microwave/microwave.rb b/exercises/practice/microwave/microwave.rb similarity index 100% rename from exercises/microwave/microwave.rb rename to exercises/practice/microwave/microwave.rb diff --git a/exercises/microwave/microwave_test.rb b/exercises/practice/microwave/microwave_test.rb similarity index 100% rename from exercises/microwave/microwave_test.rb rename to exercises/practice/microwave/microwave_test.rb diff --git a/exercises/minesweeper/.meta/solutions/minesweeper.rb b/exercises/practice/minesweeper/.meta/solutions/minesweeper.rb similarity index 100% rename from exercises/minesweeper/.meta/solutions/minesweeper.rb rename to exercises/practice/minesweeper/.meta/solutions/minesweeper.rb diff --git a/exercises/minesweeper/.meta/tests.toml b/exercises/practice/minesweeper/.meta/tests.toml similarity index 100% rename from exercises/minesweeper/.meta/tests.toml rename to exercises/practice/minesweeper/.meta/tests.toml diff --git a/exercises/minesweeper/README.md b/exercises/practice/minesweeper/README.md similarity index 100% rename from exercises/minesweeper/README.md rename to exercises/practice/minesweeper/README.md diff --git a/exercises/minesweeper/minesweeper.rb b/exercises/practice/minesweeper/minesweeper.rb similarity index 100% rename from exercises/minesweeper/minesweeper.rb rename to exercises/practice/minesweeper/minesweeper.rb diff --git a/exercises/minesweeper/minesweeper_test.rb b/exercises/practice/minesweeper/minesweeper_test.rb similarity index 100% rename from exercises/minesweeper/minesweeper_test.rb rename to exercises/practice/minesweeper/minesweeper_test.rb diff --git a/exercises/nth-prime/.meta/generator/nth_prime_case.rb b/exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb similarity index 100% rename from exercises/nth-prime/.meta/generator/nth_prime_case.rb rename to exercises/practice/nth-prime/.meta/generator/nth_prime_case.rb diff --git a/exercises/nth-prime/.meta/solutions/nth_prime.rb b/exercises/practice/nth-prime/.meta/solutions/nth_prime.rb similarity index 100% rename from exercises/nth-prime/.meta/solutions/nth_prime.rb rename to exercises/practice/nth-prime/.meta/solutions/nth_prime.rb diff --git a/exercises/nth-prime/.meta/tests.toml b/exercises/practice/nth-prime/.meta/tests.toml similarity index 100% rename from exercises/nth-prime/.meta/tests.toml rename to exercises/practice/nth-prime/.meta/tests.toml diff --git a/exercises/nth-prime/README.md b/exercises/practice/nth-prime/README.md similarity index 100% rename from exercises/nth-prime/README.md rename to exercises/practice/nth-prime/README.md diff --git a/exercises/nth-prime/nth_prime.rb b/exercises/practice/nth-prime/nth_prime.rb similarity index 100% rename from exercises/nth-prime/nth_prime.rb rename to exercises/practice/nth-prime/nth_prime.rb diff --git a/exercises/nth-prime/nth_prime_test.rb b/exercises/practice/nth-prime/nth_prime_test.rb similarity index 100% rename from exercises/nth-prime/nth_prime_test.rb rename to exercises/practice/nth-prime/nth_prime_test.rb diff --git a/exercises/nucleotide-count/.meta/solutions/nucleotide_count.rb b/exercises/practice/nucleotide-count/.meta/solutions/nucleotide_count.rb similarity index 100% rename from exercises/nucleotide-count/.meta/solutions/nucleotide_count.rb rename to exercises/practice/nucleotide-count/.meta/solutions/nucleotide_count.rb diff --git a/exercises/nucleotide-count/.meta/tests.toml b/exercises/practice/nucleotide-count/.meta/tests.toml similarity index 100% rename from exercises/nucleotide-count/.meta/tests.toml rename to exercises/practice/nucleotide-count/.meta/tests.toml diff --git a/exercises/nucleotide-count/README.md b/exercises/practice/nucleotide-count/README.md similarity index 100% rename from exercises/nucleotide-count/README.md rename to exercises/practice/nucleotide-count/README.md diff --git a/exercises/nucleotide-count/nucleotide_count.rb b/exercises/practice/nucleotide-count/nucleotide_count.rb similarity index 100% rename from exercises/nucleotide-count/nucleotide_count.rb rename to exercises/practice/nucleotide-count/nucleotide_count.rb diff --git a/exercises/nucleotide-count/nucleotide_count_test.rb b/exercises/practice/nucleotide-count/nucleotide_count_test.rb similarity index 100% rename from exercises/nucleotide-count/nucleotide_count_test.rb rename to exercises/practice/nucleotide-count/nucleotide_count_test.rb diff --git a/exercises/ocr-numbers/.meta/generator/ocr_numbers_case.rb b/exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb similarity index 100% rename from exercises/ocr-numbers/.meta/generator/ocr_numbers_case.rb rename to exercises/practice/ocr-numbers/.meta/generator/ocr_numbers_case.rb diff --git a/exercises/ocr-numbers/.meta/hints.md b/exercises/practice/ocr-numbers/.meta/hints.md similarity index 100% rename from exercises/ocr-numbers/.meta/hints.md rename to exercises/practice/ocr-numbers/.meta/hints.md diff --git a/exercises/ocr-numbers/.meta/solutions/ocr_numbers.rb b/exercises/practice/ocr-numbers/.meta/solutions/ocr_numbers.rb similarity index 100% rename from exercises/ocr-numbers/.meta/solutions/ocr_numbers.rb rename to exercises/practice/ocr-numbers/.meta/solutions/ocr_numbers.rb diff --git a/exercises/ocr-numbers/.meta/tests.toml b/exercises/practice/ocr-numbers/.meta/tests.toml similarity index 100% rename from exercises/ocr-numbers/.meta/tests.toml rename to exercises/practice/ocr-numbers/.meta/tests.toml diff --git a/exercises/ocr-numbers/README.md b/exercises/practice/ocr-numbers/README.md similarity index 100% rename from exercises/ocr-numbers/README.md rename to exercises/practice/ocr-numbers/README.md diff --git a/exercises/ocr-numbers/ocr_numbers.rb b/exercises/practice/ocr-numbers/ocr_numbers.rb similarity index 100% rename from exercises/ocr-numbers/ocr_numbers.rb rename to exercises/practice/ocr-numbers/ocr_numbers.rb diff --git a/exercises/ocr-numbers/ocr_numbers_test.rb b/exercises/practice/ocr-numbers/ocr_numbers_test.rb similarity index 100% rename from exercises/ocr-numbers/ocr_numbers_test.rb rename to exercises/practice/ocr-numbers/ocr_numbers_test.rb diff --git a/exercises/octal/.meta/solutions/octal.rb b/exercises/practice/octal/.meta/solutions/octal.rb similarity index 100% rename from exercises/octal/.meta/solutions/octal.rb rename to exercises/practice/octal/.meta/solutions/octal.rb diff --git a/exercises/octal/README.md b/exercises/practice/octal/README.md similarity index 100% rename from exercises/octal/README.md rename to exercises/practice/octal/README.md diff --git a/exercises/octal/octal.rb b/exercises/practice/octal/octal.rb similarity index 100% rename from exercises/octal/octal.rb rename to exercises/practice/octal/octal.rb diff --git a/exercises/octal/octal_test.rb b/exercises/practice/octal/octal_test.rb similarity index 100% rename from exercises/octal/octal_test.rb rename to exercises/practice/octal/octal_test.rb diff --git a/exercises/palindrome-products/.meta/solutions/palindrome_products.rb b/exercises/practice/palindrome-products/.meta/solutions/palindrome_products.rb similarity index 100% rename from exercises/palindrome-products/.meta/solutions/palindrome_products.rb rename to exercises/practice/palindrome-products/.meta/solutions/palindrome_products.rb diff --git a/exercises/palindrome-products/.meta/tests.toml b/exercises/practice/palindrome-products/.meta/tests.toml similarity index 100% rename from exercises/palindrome-products/.meta/tests.toml rename to exercises/practice/palindrome-products/.meta/tests.toml diff --git a/exercises/palindrome-products/README.md b/exercises/practice/palindrome-products/README.md similarity index 100% rename from exercises/palindrome-products/README.md rename to exercises/practice/palindrome-products/README.md diff --git a/exercises/palindrome-products/palindrome_products.rb b/exercises/practice/palindrome-products/palindrome_products.rb similarity index 100% rename from exercises/palindrome-products/palindrome_products.rb rename to exercises/practice/palindrome-products/palindrome_products.rb diff --git a/exercises/palindrome-products/palindrome_products_test.rb b/exercises/practice/palindrome-products/palindrome_products_test.rb similarity index 100% rename from exercises/palindrome-products/palindrome_products_test.rb rename to exercises/practice/palindrome-products/palindrome_products_test.rb diff --git a/exercises/pangram/.meta/generator/pangram_case.rb b/exercises/practice/pangram/.meta/generator/pangram_case.rb similarity index 100% rename from exercises/pangram/.meta/generator/pangram_case.rb rename to exercises/practice/pangram/.meta/generator/pangram_case.rb diff --git a/exercises/pangram/.meta/solutions/pangram.rb b/exercises/practice/pangram/.meta/solutions/pangram.rb similarity index 100% rename from exercises/pangram/.meta/solutions/pangram.rb rename to exercises/practice/pangram/.meta/solutions/pangram.rb diff --git a/exercises/pangram/.meta/tests.toml b/exercises/practice/pangram/.meta/tests.toml similarity index 100% rename from exercises/pangram/.meta/tests.toml rename to exercises/practice/pangram/.meta/tests.toml diff --git a/exercises/pangram/README.md b/exercises/practice/pangram/README.md similarity index 100% rename from exercises/pangram/README.md rename to exercises/practice/pangram/README.md diff --git a/exercises/pangram/pangram.rb b/exercises/practice/pangram/pangram.rb similarity index 100% rename from exercises/pangram/pangram.rb rename to exercises/practice/pangram/pangram.rb diff --git a/exercises/pangram/pangram_test.rb b/exercises/practice/pangram/pangram_test.rb similarity index 100% rename from exercises/pangram/pangram_test.rb rename to exercises/practice/pangram/pangram_test.rb diff --git a/exercises/pascals-triangle/.meta/solutions/pascals_triangle.rb b/exercises/practice/pascals-triangle/.meta/solutions/pascals_triangle.rb similarity index 100% rename from exercises/pascals-triangle/.meta/solutions/pascals_triangle.rb rename to exercises/practice/pascals-triangle/.meta/solutions/pascals_triangle.rb diff --git a/exercises/pascals-triangle/.meta/tests.toml b/exercises/practice/pascals-triangle/.meta/tests.toml similarity index 100% rename from exercises/pascals-triangle/.meta/tests.toml rename to exercises/practice/pascals-triangle/.meta/tests.toml diff --git a/exercises/pascals-triangle/README.md b/exercises/practice/pascals-triangle/README.md similarity index 100% rename from exercises/pascals-triangle/README.md rename to exercises/practice/pascals-triangle/README.md diff --git a/exercises/pascals-triangle/pascals_triangle.rb b/exercises/practice/pascals-triangle/pascals_triangle.rb similarity index 100% rename from exercises/pascals-triangle/pascals_triangle.rb rename to exercises/practice/pascals-triangle/pascals_triangle.rb diff --git a/exercises/pascals-triangle/pascals_triangle_test.rb b/exercises/practice/pascals-triangle/pascals_triangle_test.rb similarity index 100% rename from exercises/pascals-triangle/pascals_triangle_test.rb rename to exercises/practice/pascals-triangle/pascals_triangle_test.rb diff --git a/exercises/perfect-numbers/.meta/solutions/perfect_numbers.rb b/exercises/practice/perfect-numbers/.meta/solutions/perfect_numbers.rb old mode 100755 new mode 100644 similarity index 100% rename from exercises/perfect-numbers/.meta/solutions/perfect_numbers.rb rename to exercises/practice/perfect-numbers/.meta/solutions/perfect_numbers.rb diff --git a/exercises/perfect-numbers/.meta/tests.toml b/exercises/practice/perfect-numbers/.meta/tests.toml similarity index 100% rename from exercises/perfect-numbers/.meta/tests.toml rename to exercises/practice/perfect-numbers/.meta/tests.toml diff --git a/exercises/perfect-numbers/README.md b/exercises/practice/perfect-numbers/README.md similarity index 100% rename from exercises/perfect-numbers/README.md rename to exercises/practice/perfect-numbers/README.md diff --git a/exercises/perfect-numbers/perfect_numbers.rb b/exercises/practice/perfect-numbers/perfect_numbers.rb similarity index 100% rename from exercises/perfect-numbers/perfect_numbers.rb rename to exercises/practice/perfect-numbers/perfect_numbers.rb diff --git a/exercises/perfect-numbers/perfect_numbers_test.rb b/exercises/practice/perfect-numbers/perfect_numbers_test.rb similarity index 100% rename from exercises/perfect-numbers/perfect_numbers_test.rb rename to exercises/practice/perfect-numbers/perfect_numbers_test.rb diff --git a/exercises/phone-number/.meta/generator/phone_number_case.rb b/exercises/practice/phone-number/.meta/generator/phone_number_case.rb similarity index 100% rename from exercises/phone-number/.meta/generator/phone_number_case.rb rename to exercises/practice/phone-number/.meta/generator/phone_number_case.rb diff --git a/exercises/phone-number/.meta/solutions/phone_number.rb b/exercises/practice/phone-number/.meta/solutions/phone_number.rb similarity index 100% rename from exercises/phone-number/.meta/solutions/phone_number.rb rename to exercises/practice/phone-number/.meta/solutions/phone_number.rb diff --git a/exercises/phone-number/.meta/tests.toml b/exercises/practice/phone-number/.meta/tests.toml similarity index 100% rename from exercises/phone-number/.meta/tests.toml rename to exercises/practice/phone-number/.meta/tests.toml diff --git a/exercises/phone-number/README.md b/exercises/practice/phone-number/README.md similarity index 100% rename from exercises/phone-number/README.md rename to exercises/practice/phone-number/README.md diff --git a/exercises/phone-number/phone_number.rb b/exercises/practice/phone-number/phone_number.rb similarity index 100% rename from exercises/phone-number/phone_number.rb rename to exercises/practice/phone-number/phone_number.rb diff --git a/exercises/phone-number/phone_number_test.rb b/exercises/practice/phone-number/phone_number_test.rb similarity index 100% rename from exercises/phone-number/phone_number_test.rb rename to exercises/practice/phone-number/phone_number_test.rb diff --git a/exercises/pig-latin/.meta/generator/pig_latin_case.rb b/exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb similarity index 100% rename from exercises/pig-latin/.meta/generator/pig_latin_case.rb rename to exercises/practice/pig-latin/.meta/generator/pig_latin_case.rb diff --git a/exercises/pig-latin/.meta/solutions/pig_latin.rb b/exercises/practice/pig-latin/.meta/solutions/pig_latin.rb similarity index 100% rename from exercises/pig-latin/.meta/solutions/pig_latin.rb rename to exercises/practice/pig-latin/.meta/solutions/pig_latin.rb diff --git a/exercises/pig-latin/.meta/tests.toml b/exercises/practice/pig-latin/.meta/tests.toml similarity index 100% rename from exercises/pig-latin/.meta/tests.toml rename to exercises/practice/pig-latin/.meta/tests.toml diff --git a/exercises/pig-latin/README.md b/exercises/practice/pig-latin/README.md similarity index 100% rename from exercises/pig-latin/README.md rename to exercises/practice/pig-latin/README.md diff --git a/exercises/pig-latin/pig_latin.rb b/exercises/practice/pig-latin/pig_latin.rb similarity index 100% rename from exercises/pig-latin/pig_latin.rb rename to exercises/practice/pig-latin/pig_latin.rb diff --git a/exercises/pig-latin/pig_latin_test.rb b/exercises/practice/pig-latin/pig_latin_test.rb similarity index 100% rename from exercises/pig-latin/pig_latin_test.rb rename to exercises/practice/pig-latin/pig_latin_test.rb diff --git a/exercises/point-mutations/.meta/solutions/point_mutations.rb b/exercises/practice/point-mutations/.meta/solutions/point_mutations.rb similarity index 100% rename from exercises/point-mutations/.meta/solutions/point_mutations.rb rename to exercises/practice/point-mutations/.meta/solutions/point_mutations.rb diff --git a/exercises/point-mutations/README.md b/exercises/practice/point-mutations/README.md similarity index 100% rename from exercises/point-mutations/README.md rename to exercises/practice/point-mutations/README.md diff --git a/exercises/point-mutations/point_mutations.rb b/exercises/practice/point-mutations/point_mutations.rb similarity index 100% rename from exercises/point-mutations/point_mutations.rb rename to exercises/practice/point-mutations/point_mutations.rb diff --git a/exercises/point-mutations/point_mutations_test.rb b/exercises/practice/point-mutations/point_mutations_test.rb similarity index 100% rename from exercises/point-mutations/point_mutations_test.rb rename to exercises/practice/point-mutations/point_mutations_test.rb diff --git a/exercises/poker/.meta/solutions/poker.rb b/exercises/practice/poker/.meta/solutions/poker.rb similarity index 100% rename from exercises/poker/.meta/solutions/poker.rb rename to exercises/practice/poker/.meta/solutions/poker.rb diff --git a/exercises/poker/.meta/tests.toml b/exercises/practice/poker/.meta/tests.toml similarity index 100% rename from exercises/poker/.meta/tests.toml rename to exercises/practice/poker/.meta/tests.toml diff --git a/exercises/poker/README.md b/exercises/practice/poker/README.md similarity index 100% rename from exercises/poker/README.md rename to exercises/practice/poker/README.md diff --git a/exercises/poker/poker.rb b/exercises/practice/poker/poker.rb similarity index 100% rename from exercises/poker/poker.rb rename to exercises/practice/poker/poker.rb diff --git a/exercises/poker/poker_test.rb b/exercises/practice/poker/poker_test.rb similarity index 100% rename from exercises/poker/poker_test.rb rename to exercises/practice/poker/poker_test.rb diff --git a/exercises/prime-factors/.meta/solutions/prime_factors.rb b/exercises/practice/prime-factors/.meta/solutions/prime_factors.rb similarity index 100% rename from exercises/prime-factors/.meta/solutions/prime_factors.rb rename to exercises/practice/prime-factors/.meta/solutions/prime_factors.rb diff --git a/exercises/prime-factors/.meta/tests.toml b/exercises/practice/prime-factors/.meta/tests.toml similarity index 100% rename from exercises/prime-factors/.meta/tests.toml rename to exercises/practice/prime-factors/.meta/tests.toml diff --git a/exercises/prime-factors/README.md b/exercises/practice/prime-factors/README.md similarity index 100% rename from exercises/prime-factors/README.md rename to exercises/practice/prime-factors/README.md diff --git a/exercises/prime-factors/prime_factors.rb b/exercises/practice/prime-factors/prime_factors.rb similarity index 100% rename from exercises/prime-factors/prime_factors.rb rename to exercises/practice/prime-factors/prime_factors.rb diff --git a/exercises/prime-factors/prime_factors_test.rb b/exercises/practice/prime-factors/prime_factors_test.rb similarity index 100% rename from exercises/prime-factors/prime_factors_test.rb rename to exercises/practice/prime-factors/prime_factors_test.rb diff --git a/exercises/protein-translation/.meta/solutions/protein_translation.rb b/exercises/practice/protein-translation/.meta/solutions/protein_translation.rb similarity index 100% rename from exercises/protein-translation/.meta/solutions/protein_translation.rb rename to exercises/practice/protein-translation/.meta/solutions/protein_translation.rb diff --git a/exercises/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml similarity index 100% rename from exercises/protein-translation/.meta/tests.toml rename to exercises/practice/protein-translation/.meta/tests.toml diff --git a/exercises/protein-translation/README.md b/exercises/practice/protein-translation/README.md similarity index 100% rename from exercises/protein-translation/README.md rename to exercises/practice/protein-translation/README.md diff --git a/exercises/protein-translation/protein_translation.rb b/exercises/practice/protein-translation/protein_translation.rb similarity index 100% rename from exercises/protein-translation/protein_translation.rb rename to exercises/practice/protein-translation/protein_translation.rb diff --git a/exercises/protein-translation/protein_translation_test.rb b/exercises/practice/protein-translation/protein_translation_test.rb similarity index 100% rename from exercises/protein-translation/protein_translation_test.rb rename to exercises/practice/protein-translation/protein_translation_test.rb diff --git a/exercises/proverb/.meta/solutions/proverb.rb b/exercises/practice/proverb/.meta/solutions/proverb.rb similarity index 100% rename from exercises/proverb/.meta/solutions/proverb.rb rename to exercises/practice/proverb/.meta/solutions/proverb.rb diff --git a/exercises/proverb/.meta/tests.toml b/exercises/practice/proverb/.meta/tests.toml similarity index 100% rename from exercises/proverb/.meta/tests.toml rename to exercises/practice/proverb/.meta/tests.toml diff --git a/exercises/proverb/README.md b/exercises/practice/proverb/README.md similarity index 100% rename from exercises/proverb/README.md rename to exercises/practice/proverb/README.md diff --git a/exercises/proverb/proverb.rb b/exercises/practice/proverb/proverb.rb similarity index 100% rename from exercises/proverb/proverb.rb rename to exercises/practice/proverb/proverb.rb diff --git a/exercises/proverb/proverb_test.rb b/exercises/practice/proverb/proverb_test.rb similarity index 100% rename from exercises/proverb/proverb_test.rb rename to exercises/practice/proverb/proverb_test.rb diff --git a/exercises/pythagorean-triplet/.meta/solutions/pythagorean_triplet.rb b/exercises/practice/pythagorean-triplet/.meta/solutions/pythagorean_triplet.rb similarity index 100% rename from exercises/pythagorean-triplet/.meta/solutions/pythagorean_triplet.rb rename to exercises/practice/pythagorean-triplet/.meta/solutions/pythagorean_triplet.rb diff --git a/exercises/pythagorean-triplet/.meta/tests.toml b/exercises/practice/pythagorean-triplet/.meta/tests.toml similarity index 100% rename from exercises/pythagorean-triplet/.meta/tests.toml rename to exercises/practice/pythagorean-triplet/.meta/tests.toml diff --git a/exercises/pythagorean-triplet/README.md b/exercises/practice/pythagorean-triplet/README.md similarity index 100% rename from exercises/pythagorean-triplet/README.md rename to exercises/practice/pythagorean-triplet/README.md diff --git a/exercises/pythagorean-triplet/pythagorean_triplet.rb b/exercises/practice/pythagorean-triplet/pythagorean_triplet.rb similarity index 100% rename from exercises/pythagorean-triplet/pythagorean_triplet.rb rename to exercises/practice/pythagorean-triplet/pythagorean_triplet.rb diff --git a/exercises/pythagorean-triplet/pythagorean_triplet_test.rb b/exercises/practice/pythagorean-triplet/pythagorean_triplet_test.rb similarity index 100% rename from exercises/pythagorean-triplet/pythagorean_triplet_test.rb rename to exercises/practice/pythagorean-triplet/pythagorean_triplet_test.rb diff --git a/exercises/queen-attack/.meta/generator/queen_attack_case.rb b/exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb similarity index 100% rename from exercises/queen-attack/.meta/generator/queen_attack_case.rb rename to exercises/practice/queen-attack/.meta/generator/queen_attack_case.rb diff --git a/exercises/queen-attack/.meta/solutions/queen_attack.rb b/exercises/practice/queen-attack/.meta/solutions/queen_attack.rb similarity index 100% rename from exercises/queen-attack/.meta/solutions/queen_attack.rb rename to exercises/practice/queen-attack/.meta/solutions/queen_attack.rb diff --git a/exercises/queen-attack/.meta/tests.toml b/exercises/practice/queen-attack/.meta/tests.toml similarity index 100% rename from exercises/queen-attack/.meta/tests.toml rename to exercises/practice/queen-attack/.meta/tests.toml diff --git a/exercises/queen-attack/README.md b/exercises/practice/queen-attack/README.md similarity index 100% rename from exercises/queen-attack/README.md rename to exercises/practice/queen-attack/README.md diff --git a/exercises/queen-attack/queen_attack.rb b/exercises/practice/queen-attack/queen_attack.rb similarity index 100% rename from exercises/queen-attack/queen_attack.rb rename to exercises/practice/queen-attack/queen_attack.rb diff --git a/exercises/queen-attack/queen_attack_test.rb b/exercises/practice/queen-attack/queen_attack_test.rb similarity index 100% rename from exercises/queen-attack/queen_attack_test.rb rename to exercises/practice/queen-attack/queen_attack_test.rb diff --git a/exercises/rail-fence-cipher/.meta/solutions/rail_fence_cipher.rb b/exercises/practice/rail-fence-cipher/.meta/solutions/rail_fence_cipher.rb similarity index 100% rename from exercises/rail-fence-cipher/.meta/solutions/rail_fence_cipher.rb rename to exercises/practice/rail-fence-cipher/.meta/solutions/rail_fence_cipher.rb diff --git a/exercises/rail-fence-cipher/.meta/tests.toml b/exercises/practice/rail-fence-cipher/.meta/tests.toml similarity index 100% rename from exercises/rail-fence-cipher/.meta/tests.toml rename to exercises/practice/rail-fence-cipher/.meta/tests.toml diff --git a/exercises/rail-fence-cipher/README.md b/exercises/practice/rail-fence-cipher/README.md similarity index 100% rename from exercises/rail-fence-cipher/README.md rename to exercises/practice/rail-fence-cipher/README.md diff --git a/exercises/rail-fence-cipher/rail_fence_cipher.rb b/exercises/practice/rail-fence-cipher/rail_fence_cipher.rb similarity index 100% rename from exercises/rail-fence-cipher/rail_fence_cipher.rb rename to exercises/practice/rail-fence-cipher/rail_fence_cipher.rb diff --git a/exercises/rail-fence-cipher/rail_fence_cipher_test.rb b/exercises/practice/rail-fence-cipher/rail_fence_cipher_test.rb similarity index 100% rename from exercises/rail-fence-cipher/rail_fence_cipher_test.rb rename to exercises/practice/rail-fence-cipher/rail_fence_cipher_test.rb diff --git a/exercises/raindrops/.meta/generator/raindrops_case.rb b/exercises/practice/raindrops/.meta/generator/raindrops_case.rb similarity index 100% rename from exercises/raindrops/.meta/generator/raindrops_case.rb rename to exercises/practice/raindrops/.meta/generator/raindrops_case.rb diff --git a/exercises/raindrops/.meta/solutions/raindrops.rb b/exercises/practice/raindrops/.meta/solutions/raindrops.rb similarity index 100% rename from exercises/raindrops/.meta/solutions/raindrops.rb rename to exercises/practice/raindrops/.meta/solutions/raindrops.rb diff --git a/exercises/raindrops/.meta/tests.toml b/exercises/practice/raindrops/.meta/tests.toml similarity index 100% rename from exercises/raindrops/.meta/tests.toml rename to exercises/practice/raindrops/.meta/tests.toml diff --git a/exercises/raindrops/README.md b/exercises/practice/raindrops/README.md similarity index 100% rename from exercises/raindrops/README.md rename to exercises/practice/raindrops/README.md diff --git a/exercises/raindrops/raindrops.rb b/exercises/practice/raindrops/raindrops.rb similarity index 100% rename from exercises/raindrops/raindrops.rb rename to exercises/practice/raindrops/raindrops.rb diff --git a/exercises/raindrops/raindrops_test.rb b/exercises/practice/raindrops/raindrops_test.rb similarity index 100% rename from exercises/raindrops/raindrops_test.rb rename to exercises/practice/raindrops/raindrops_test.rb diff --git a/exercises/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb b/exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb similarity index 100% rename from exercises/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb rename to exercises/practice/resistor-color-duo/.meta/generator/resistor_color_duo_case.rb diff --git a/exercises/resistor-color-duo/.meta/solutions/resistor_color_duo.rb b/exercises/practice/resistor-color-duo/.meta/solutions/resistor_color_duo.rb similarity index 100% rename from exercises/resistor-color-duo/.meta/solutions/resistor_color_duo.rb rename to exercises/practice/resistor-color-duo/.meta/solutions/resistor_color_duo.rb diff --git a/exercises/resistor-color-duo/.meta/tests.toml b/exercises/practice/resistor-color-duo/.meta/tests.toml similarity index 100% rename from exercises/resistor-color-duo/.meta/tests.toml rename to exercises/practice/resistor-color-duo/.meta/tests.toml diff --git a/exercises/resistor-color-duo/README.md b/exercises/practice/resistor-color-duo/README.md similarity index 100% rename from exercises/resistor-color-duo/README.md rename to exercises/practice/resistor-color-duo/README.md diff --git a/exercises/resistor-color-duo/resistor_color_duo.rb b/exercises/practice/resistor-color-duo/resistor_color_duo.rb similarity index 100% rename from exercises/resistor-color-duo/resistor_color_duo.rb rename to exercises/practice/resistor-color-duo/resistor_color_duo.rb diff --git a/exercises/resistor-color-duo/resistor_color_duo_test.rb b/exercises/practice/resistor-color-duo/resistor_color_duo_test.rb similarity index 100% rename from exercises/resistor-color-duo/resistor_color_duo_test.rb rename to exercises/practice/resistor-color-duo/resistor_color_duo_test.rb diff --git a/exercises/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb b/exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb similarity index 100% rename from exercises/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb rename to exercises/practice/resistor-color-trio/.meta/generator/resistor_color_trio_case.rb diff --git a/exercises/resistor-color-trio/.meta/solutions/resistor_color_trio.rb b/exercises/practice/resistor-color-trio/.meta/solutions/resistor_color_trio.rb similarity index 100% rename from exercises/resistor-color-trio/.meta/solutions/resistor_color_trio.rb rename to exercises/practice/resistor-color-trio/.meta/solutions/resistor_color_trio.rb diff --git a/exercises/resistor-color-trio/.meta/tests.toml b/exercises/practice/resistor-color-trio/.meta/tests.toml similarity index 100% rename from exercises/resistor-color-trio/.meta/tests.toml rename to exercises/practice/resistor-color-trio/.meta/tests.toml diff --git a/exercises/resistor-color-trio/README.md b/exercises/practice/resistor-color-trio/README.md similarity index 100% rename from exercises/resistor-color-trio/README.md rename to exercises/practice/resistor-color-trio/README.md diff --git a/exercises/resistor-color-trio/resistor_color_trio.rb b/exercises/practice/resistor-color-trio/resistor_color_trio.rb similarity index 100% rename from exercises/resistor-color-trio/resistor_color_trio.rb rename to exercises/practice/resistor-color-trio/resistor_color_trio.rb diff --git a/exercises/resistor-color-trio/resistor_color_trio_test.rb b/exercises/practice/resistor-color-trio/resistor_color_trio_test.rb similarity index 100% rename from exercises/resistor-color-trio/resistor_color_trio_test.rb rename to exercises/practice/resistor-color-trio/resistor_color_trio_test.rb diff --git a/exercises/resistor-color/.meta/generator/resistor_color_case.rb b/exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb similarity index 100% rename from exercises/resistor-color/.meta/generator/resistor_color_case.rb rename to exercises/practice/resistor-color/.meta/generator/resistor_color_case.rb diff --git a/exercises/resistor-color/.meta/solutions/resistor_color.rb b/exercises/practice/resistor-color/.meta/solutions/resistor_color.rb similarity index 100% rename from exercises/resistor-color/.meta/solutions/resistor_color.rb rename to exercises/practice/resistor-color/.meta/solutions/resistor_color.rb diff --git a/exercises/resistor-color/.meta/tests.toml b/exercises/practice/resistor-color/.meta/tests.toml similarity index 100% rename from exercises/resistor-color/.meta/tests.toml rename to exercises/practice/resistor-color/.meta/tests.toml diff --git a/exercises/resistor-color/README.md b/exercises/practice/resistor-color/README.md similarity index 100% rename from exercises/resistor-color/README.md rename to exercises/practice/resistor-color/README.md diff --git a/exercises/resistor-color/resistor_color.rb b/exercises/practice/resistor-color/resistor_color.rb similarity index 100% rename from exercises/resistor-color/resistor_color.rb rename to exercises/practice/resistor-color/resistor_color.rb diff --git a/exercises/resistor-color/resistor_color_test.rb b/exercises/practice/resistor-color/resistor_color_test.rb similarity index 100% rename from exercises/resistor-color/resistor_color_test.rb rename to exercises/practice/resistor-color/resistor_color_test.rb diff --git a/exercises/rna-transcription/.meta/generator/rna_transcription_case.rb b/exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb similarity index 100% rename from exercises/rna-transcription/.meta/generator/rna_transcription_case.rb rename to exercises/practice/rna-transcription/.meta/generator/rna_transcription_case.rb diff --git a/exercises/rna-transcription/.meta/solutions/rna_transcription.rb b/exercises/practice/rna-transcription/.meta/solutions/rna_transcription.rb similarity index 100% rename from exercises/rna-transcription/.meta/solutions/rna_transcription.rb rename to exercises/practice/rna-transcription/.meta/solutions/rna_transcription.rb diff --git a/exercises/rna-transcription/.meta/tests.toml b/exercises/practice/rna-transcription/.meta/tests.toml similarity index 100% rename from exercises/rna-transcription/.meta/tests.toml rename to exercises/practice/rna-transcription/.meta/tests.toml diff --git a/exercises/rna-transcription/README.md b/exercises/practice/rna-transcription/README.md similarity index 100% rename from exercises/rna-transcription/README.md rename to exercises/practice/rna-transcription/README.md diff --git a/exercises/rna-transcription/rna_transcription.rb b/exercises/practice/rna-transcription/rna_transcription.rb similarity index 100% rename from exercises/rna-transcription/rna_transcription.rb rename to exercises/practice/rna-transcription/rna_transcription.rb diff --git a/exercises/rna-transcription/rna_transcription_test.rb b/exercises/practice/rna-transcription/rna_transcription_test.rb similarity index 100% rename from exercises/rna-transcription/rna_transcription_test.rb rename to exercises/practice/rna-transcription/rna_transcription_test.rb diff --git a/exercises/robot-name/.meta/hints.md b/exercises/practice/robot-name/.meta/hints.md similarity index 100% rename from exercises/robot-name/.meta/hints.md rename to exercises/practice/robot-name/.meta/hints.md diff --git a/exercises/robot-name/.meta/solutions/robot_name.rb b/exercises/practice/robot-name/.meta/solutions/robot_name.rb similarity index 100% rename from exercises/robot-name/.meta/solutions/robot_name.rb rename to exercises/practice/robot-name/.meta/solutions/robot_name.rb diff --git a/exercises/robot-name/README.md b/exercises/practice/robot-name/README.md similarity index 100% rename from exercises/robot-name/README.md rename to exercises/practice/robot-name/README.md diff --git a/exercises/robot-name/robot_name.rb b/exercises/practice/robot-name/robot_name.rb similarity index 100% rename from exercises/robot-name/robot_name.rb rename to exercises/practice/robot-name/robot_name.rb diff --git a/exercises/robot-name/robot_name_test.rb b/exercises/practice/robot-name/robot_name_test.rb similarity index 100% rename from exercises/robot-name/robot_name_test.rb rename to exercises/practice/robot-name/robot_name_test.rb diff --git a/exercises/robot-simulator/.meta/solutions/robot_simulator.rb b/exercises/practice/robot-simulator/.meta/solutions/robot_simulator.rb similarity index 100% rename from exercises/robot-simulator/.meta/solutions/robot_simulator.rb rename to exercises/practice/robot-simulator/.meta/solutions/robot_simulator.rb diff --git a/exercises/robot-simulator/.meta/tests.toml b/exercises/practice/robot-simulator/.meta/tests.toml similarity index 100% rename from exercises/robot-simulator/.meta/tests.toml rename to exercises/practice/robot-simulator/.meta/tests.toml diff --git a/exercises/robot-simulator/README.md b/exercises/practice/robot-simulator/README.md similarity index 100% rename from exercises/robot-simulator/README.md rename to exercises/practice/robot-simulator/README.md diff --git a/exercises/robot-simulator/robot_simulator.rb b/exercises/practice/robot-simulator/robot_simulator.rb similarity index 100% rename from exercises/robot-simulator/robot_simulator.rb rename to exercises/practice/robot-simulator/robot_simulator.rb diff --git a/exercises/robot-simulator/robot_simulator_test.rb b/exercises/practice/robot-simulator/robot_simulator_test.rb similarity index 100% rename from exercises/robot-simulator/robot_simulator_test.rb rename to exercises/practice/robot-simulator/robot_simulator_test.rb diff --git a/exercises/roman-numerals/.meta/generator/roman_numerals_case.rb b/exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb similarity index 100% rename from exercises/roman-numerals/.meta/generator/roman_numerals_case.rb rename to exercises/practice/roman-numerals/.meta/generator/roman_numerals_case.rb diff --git a/exercises/roman-numerals/.meta/solutions/roman_numerals.rb b/exercises/practice/roman-numerals/.meta/solutions/roman_numerals.rb similarity index 100% rename from exercises/roman-numerals/.meta/solutions/roman_numerals.rb rename to exercises/practice/roman-numerals/.meta/solutions/roman_numerals.rb diff --git a/exercises/roman-numerals/.meta/tests.toml b/exercises/practice/roman-numerals/.meta/tests.toml similarity index 100% rename from exercises/roman-numerals/.meta/tests.toml rename to exercises/practice/roman-numerals/.meta/tests.toml diff --git a/exercises/roman-numerals/README.md b/exercises/practice/roman-numerals/README.md similarity index 100% rename from exercises/roman-numerals/README.md rename to exercises/practice/roman-numerals/README.md diff --git a/exercises/roman-numerals/roman_numerals.rb b/exercises/practice/roman-numerals/roman_numerals.rb similarity index 100% rename from exercises/roman-numerals/roman_numerals.rb rename to exercises/practice/roman-numerals/roman_numerals.rb diff --git a/exercises/roman-numerals/roman_numerals_test.rb b/exercises/practice/roman-numerals/roman_numerals_test.rb similarity index 100% rename from exercises/roman-numerals/roman_numerals_test.rb rename to exercises/practice/roman-numerals/roman_numerals_test.rb diff --git a/exercises/rotational-cipher/.meta/generator/rotational_cipher_case.rb b/exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb similarity index 100% rename from exercises/rotational-cipher/.meta/generator/rotational_cipher_case.rb rename to exercises/practice/rotational-cipher/.meta/generator/rotational_cipher_case.rb diff --git a/exercises/rotational-cipher/.meta/solutions/rotational_cipher.rb b/exercises/practice/rotational-cipher/.meta/solutions/rotational_cipher.rb similarity index 100% rename from exercises/rotational-cipher/.meta/solutions/rotational_cipher.rb rename to exercises/practice/rotational-cipher/.meta/solutions/rotational_cipher.rb diff --git a/exercises/rotational-cipher/.meta/tests.toml b/exercises/practice/rotational-cipher/.meta/tests.toml similarity index 100% rename from exercises/rotational-cipher/.meta/tests.toml rename to exercises/practice/rotational-cipher/.meta/tests.toml diff --git a/exercises/rotational-cipher/README.md b/exercises/practice/rotational-cipher/README.md similarity index 100% rename from exercises/rotational-cipher/README.md rename to exercises/practice/rotational-cipher/README.md diff --git a/exercises/rotational-cipher/rotational_cipher.rb b/exercises/practice/rotational-cipher/rotational_cipher.rb similarity index 100% rename from exercises/rotational-cipher/rotational_cipher.rb rename to exercises/practice/rotational-cipher/rotational_cipher.rb diff --git a/exercises/rotational-cipher/rotational_cipher_test.rb b/exercises/practice/rotational-cipher/rotational_cipher_test.rb similarity index 100% rename from exercises/rotational-cipher/rotational_cipher_test.rb rename to exercises/practice/rotational-cipher/rotational_cipher_test.rb diff --git a/exercises/run-length-encoding/.meta/generator/run_length_encoding_case.rb b/exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb similarity index 100% rename from exercises/run-length-encoding/.meta/generator/run_length_encoding_case.rb rename to exercises/practice/run-length-encoding/.meta/generator/run_length_encoding_case.rb diff --git a/exercises/run-length-encoding/.meta/solutions/run_length_encoding.rb b/exercises/practice/run-length-encoding/.meta/solutions/run_length_encoding.rb similarity index 100% rename from exercises/run-length-encoding/.meta/solutions/run_length_encoding.rb rename to exercises/practice/run-length-encoding/.meta/solutions/run_length_encoding.rb diff --git a/exercises/run-length-encoding/.meta/tests.toml b/exercises/practice/run-length-encoding/.meta/tests.toml similarity index 100% rename from exercises/run-length-encoding/.meta/tests.toml rename to exercises/practice/run-length-encoding/.meta/tests.toml diff --git a/exercises/run-length-encoding/README.md b/exercises/practice/run-length-encoding/README.md similarity index 100% rename from exercises/run-length-encoding/README.md rename to exercises/practice/run-length-encoding/README.md diff --git a/exercises/run-length-encoding/run_length_encoding.rb b/exercises/practice/run-length-encoding/run_length_encoding.rb similarity index 100% rename from exercises/run-length-encoding/run_length_encoding.rb rename to exercises/practice/run-length-encoding/run_length_encoding.rb diff --git a/exercises/run-length-encoding/run_length_encoding_test.rb b/exercises/practice/run-length-encoding/run_length_encoding_test.rb similarity index 100% rename from exercises/run-length-encoding/run_length_encoding_test.rb rename to exercises/practice/run-length-encoding/run_length_encoding_test.rb diff --git a/exercises/saddle-points/.meta/solutions/saddle_points.rb b/exercises/practice/saddle-points/.meta/solutions/saddle_points.rb similarity index 100% rename from exercises/saddle-points/.meta/solutions/saddle_points.rb rename to exercises/practice/saddle-points/.meta/solutions/saddle_points.rb diff --git a/exercises/saddle-points/.meta/tests.toml b/exercises/practice/saddle-points/.meta/tests.toml similarity index 100% rename from exercises/saddle-points/.meta/tests.toml rename to exercises/practice/saddle-points/.meta/tests.toml diff --git a/exercises/saddle-points/README.md b/exercises/practice/saddle-points/README.md similarity index 100% rename from exercises/saddle-points/README.md rename to exercises/practice/saddle-points/README.md diff --git a/exercises/saddle-points/saddle_points.rb b/exercises/practice/saddle-points/saddle_points.rb similarity index 100% rename from exercises/saddle-points/saddle_points.rb rename to exercises/practice/saddle-points/saddle_points.rb diff --git a/exercises/saddle-points/saddle_points_test.rb b/exercises/practice/saddle-points/saddle_points_test.rb similarity index 100% rename from exercises/saddle-points/saddle_points_test.rb rename to exercises/practice/saddle-points/saddle_points_test.rb diff --git a/exercises/say/.meta/generator/say_case.rb b/exercises/practice/say/.meta/generator/say_case.rb similarity index 100% rename from exercises/say/.meta/generator/say_case.rb rename to exercises/practice/say/.meta/generator/say_case.rb diff --git a/exercises/say/.meta/solutions/say.rb b/exercises/practice/say/.meta/solutions/say.rb similarity index 100% rename from exercises/say/.meta/solutions/say.rb rename to exercises/practice/say/.meta/solutions/say.rb diff --git a/exercises/say/.meta/tests.toml b/exercises/practice/say/.meta/tests.toml similarity index 100% rename from exercises/say/.meta/tests.toml rename to exercises/practice/say/.meta/tests.toml diff --git a/exercises/say/README.md b/exercises/practice/say/README.md similarity index 100% rename from exercises/say/README.md rename to exercises/practice/say/README.md diff --git a/exercises/say/say.rb b/exercises/practice/say/say.rb similarity index 100% rename from exercises/say/say.rb rename to exercises/practice/say/say.rb diff --git a/exercises/say/say_test.rb b/exercises/practice/say/say_test.rb similarity index 100% rename from exercises/say/say_test.rb rename to exercises/practice/say/say_test.rb diff --git a/exercises/scale-generator/.meta/solutions/scale_generator.rb b/exercises/practice/scale-generator/.meta/solutions/scale_generator.rb similarity index 100% rename from exercises/scale-generator/.meta/solutions/scale_generator.rb rename to exercises/practice/scale-generator/.meta/solutions/scale_generator.rb diff --git a/exercises/scale-generator/.meta/tests.toml b/exercises/practice/scale-generator/.meta/tests.toml similarity index 100% rename from exercises/scale-generator/.meta/tests.toml rename to exercises/practice/scale-generator/.meta/tests.toml diff --git a/exercises/scale-generator/README.md b/exercises/practice/scale-generator/README.md similarity index 100% rename from exercises/scale-generator/README.md rename to exercises/practice/scale-generator/README.md diff --git a/exercises/scale-generator/scale_generator.rb b/exercises/practice/scale-generator/scale_generator.rb similarity index 100% rename from exercises/scale-generator/scale_generator.rb rename to exercises/practice/scale-generator/scale_generator.rb diff --git a/exercises/scale-generator/scale_generator_test.rb b/exercises/practice/scale-generator/scale_generator_test.rb similarity index 100% rename from exercises/scale-generator/scale_generator_test.rb rename to exercises/practice/scale-generator/scale_generator_test.rb diff --git a/exercises/scrabble-score/.meta/solutions/scrabble_score.rb b/exercises/practice/scrabble-score/.meta/solutions/scrabble_score.rb similarity index 100% rename from exercises/scrabble-score/.meta/solutions/scrabble_score.rb rename to exercises/practice/scrabble-score/.meta/solutions/scrabble_score.rb diff --git a/exercises/scrabble-score/.meta/tests.toml b/exercises/practice/scrabble-score/.meta/tests.toml similarity index 100% rename from exercises/scrabble-score/.meta/tests.toml rename to exercises/practice/scrabble-score/.meta/tests.toml diff --git a/exercises/scrabble-score/README.md b/exercises/practice/scrabble-score/README.md similarity index 100% rename from exercises/scrabble-score/README.md rename to exercises/practice/scrabble-score/README.md diff --git a/exercises/scrabble-score/scrabble_score.rb b/exercises/practice/scrabble-score/scrabble_score.rb similarity index 100% rename from exercises/scrabble-score/scrabble_score.rb rename to exercises/practice/scrabble-score/scrabble_score.rb diff --git a/exercises/scrabble-score/scrabble_score_test.rb b/exercises/practice/scrabble-score/scrabble_score_test.rb similarity index 100% rename from exercises/scrabble-score/scrabble_score_test.rb rename to exercises/practice/scrabble-score/scrabble_score_test.rb diff --git a/exercises/secret-handshake/.meta/solutions/secret_handshake.rb b/exercises/practice/secret-handshake/.meta/solutions/secret_handshake.rb similarity index 100% rename from exercises/secret-handshake/.meta/solutions/secret_handshake.rb rename to exercises/practice/secret-handshake/.meta/solutions/secret_handshake.rb diff --git a/exercises/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml similarity index 100% rename from exercises/secret-handshake/.meta/tests.toml rename to exercises/practice/secret-handshake/.meta/tests.toml diff --git a/exercises/secret-handshake/README.md b/exercises/practice/secret-handshake/README.md similarity index 100% rename from exercises/secret-handshake/README.md rename to exercises/practice/secret-handshake/README.md diff --git a/exercises/secret-handshake/secret_handshake.rb b/exercises/practice/secret-handshake/secret_handshake.rb similarity index 100% rename from exercises/secret-handshake/secret_handshake.rb rename to exercises/practice/secret-handshake/secret_handshake.rb diff --git a/exercises/secret-handshake/secret_handshake_test.rb b/exercises/practice/secret-handshake/secret_handshake_test.rb similarity index 100% rename from exercises/secret-handshake/secret_handshake_test.rb rename to exercises/practice/secret-handshake/secret_handshake_test.rb diff --git a/exercises/series/.meta/hints.md b/exercises/practice/series/.meta/hints.md similarity index 100% rename from exercises/series/.meta/hints.md rename to exercises/practice/series/.meta/hints.md diff --git a/exercises/series/.meta/solutions/series.rb b/exercises/practice/series/.meta/solutions/series.rb similarity index 100% rename from exercises/series/.meta/solutions/series.rb rename to exercises/practice/series/.meta/solutions/series.rb diff --git a/exercises/series/.meta/tests.toml b/exercises/practice/series/.meta/tests.toml similarity index 100% rename from exercises/series/.meta/tests.toml rename to exercises/practice/series/.meta/tests.toml diff --git a/exercises/series/README.md b/exercises/practice/series/README.md similarity index 100% rename from exercises/series/README.md rename to exercises/practice/series/README.md diff --git a/exercises/series/series.rb b/exercises/practice/series/series.rb similarity index 100% rename from exercises/series/series.rb rename to exercises/practice/series/series.rb diff --git a/exercises/series/series_test.rb b/exercises/practice/series/series_test.rb similarity index 100% rename from exercises/series/series_test.rb rename to exercises/practice/series/series_test.rb diff --git a/exercises/sieve/.meta/generator/sieve_case.rb b/exercises/practice/sieve/.meta/generator/sieve_case.rb similarity index 100% rename from exercises/sieve/.meta/generator/sieve_case.rb rename to exercises/practice/sieve/.meta/generator/sieve_case.rb diff --git a/exercises/sieve/.meta/solutions/sieve.rb b/exercises/practice/sieve/.meta/solutions/sieve.rb similarity index 100% rename from exercises/sieve/.meta/solutions/sieve.rb rename to exercises/practice/sieve/.meta/solutions/sieve.rb diff --git a/exercises/sieve/.meta/tests.toml b/exercises/practice/sieve/.meta/tests.toml similarity index 100% rename from exercises/sieve/.meta/tests.toml rename to exercises/practice/sieve/.meta/tests.toml diff --git a/exercises/sieve/README.md b/exercises/practice/sieve/README.md similarity index 100% rename from exercises/sieve/README.md rename to exercises/practice/sieve/README.md diff --git a/exercises/sieve/sieve.rb b/exercises/practice/sieve/sieve.rb similarity index 100% rename from exercises/sieve/sieve.rb rename to exercises/practice/sieve/sieve.rb diff --git a/exercises/sieve/sieve_test.rb b/exercises/practice/sieve/sieve_test.rb similarity index 100% rename from exercises/sieve/sieve_test.rb rename to exercises/practice/sieve/sieve_test.rb diff --git a/exercises/simple-cipher/.meta/solutions/simple_cipher.rb b/exercises/practice/simple-cipher/.meta/solutions/simple_cipher.rb similarity index 100% rename from exercises/simple-cipher/.meta/solutions/simple_cipher.rb rename to exercises/practice/simple-cipher/.meta/solutions/simple_cipher.rb diff --git a/exercises/simple-cipher/.meta/tests.toml b/exercises/practice/simple-cipher/.meta/tests.toml similarity index 100% rename from exercises/simple-cipher/.meta/tests.toml rename to exercises/practice/simple-cipher/.meta/tests.toml diff --git a/exercises/simple-cipher/README.md b/exercises/practice/simple-cipher/README.md similarity index 100% rename from exercises/simple-cipher/README.md rename to exercises/practice/simple-cipher/README.md diff --git a/exercises/simple-cipher/simple_cipher.rb b/exercises/practice/simple-cipher/simple_cipher.rb similarity index 100% rename from exercises/simple-cipher/simple_cipher.rb rename to exercises/practice/simple-cipher/simple_cipher.rb diff --git a/exercises/simple-cipher/simple_cipher_test.rb b/exercises/practice/simple-cipher/simple_cipher_test.rb similarity index 100% rename from exercises/simple-cipher/simple_cipher_test.rb rename to exercises/practice/simple-cipher/simple_cipher_test.rb diff --git a/exercises/simple-linked-list/.meta/solutions/simple_linked_list.rb b/exercises/practice/simple-linked-list/.meta/solutions/simple_linked_list.rb similarity index 100% rename from exercises/simple-linked-list/.meta/solutions/simple_linked_list.rb rename to exercises/practice/simple-linked-list/.meta/solutions/simple_linked_list.rb diff --git a/exercises/simple-linked-list/README.md b/exercises/practice/simple-linked-list/README.md similarity index 100% rename from exercises/simple-linked-list/README.md rename to exercises/practice/simple-linked-list/README.md diff --git a/exercises/simple-linked-list/simple_linked_list.rb b/exercises/practice/simple-linked-list/simple_linked_list.rb similarity index 100% rename from exercises/simple-linked-list/simple_linked_list.rb rename to exercises/practice/simple-linked-list/simple_linked_list.rb diff --git a/exercises/simple-linked-list/simple_linked_list_test.rb b/exercises/practice/simple-linked-list/simple_linked_list_test.rb similarity index 100% rename from exercises/simple-linked-list/simple_linked_list_test.rb rename to exercises/practice/simple-linked-list/simple_linked_list_test.rb diff --git a/exercises/space-age/.meta/generator/space_age_case.rb b/exercises/practice/space-age/.meta/generator/space_age_case.rb similarity index 100% rename from exercises/space-age/.meta/generator/space_age_case.rb rename to exercises/practice/space-age/.meta/generator/space_age_case.rb diff --git a/exercises/space-age/.meta/generator/test_template.erb b/exercises/practice/space-age/.meta/generator/test_template.erb similarity index 100% rename from exercises/space-age/.meta/generator/test_template.erb rename to exercises/practice/space-age/.meta/generator/test_template.erb diff --git a/exercises/space-age/.meta/solutions/space_age.rb b/exercises/practice/space-age/.meta/solutions/space_age.rb similarity index 100% rename from exercises/space-age/.meta/solutions/space_age.rb rename to exercises/practice/space-age/.meta/solutions/space_age.rb diff --git a/exercises/space-age/.meta/tests.toml b/exercises/practice/space-age/.meta/tests.toml similarity index 100% rename from exercises/space-age/.meta/tests.toml rename to exercises/practice/space-age/.meta/tests.toml diff --git a/exercises/space-age/README.md b/exercises/practice/space-age/README.md similarity index 100% rename from exercises/space-age/README.md rename to exercises/practice/space-age/README.md diff --git a/exercises/space-age/space_age.rb b/exercises/practice/space-age/space_age.rb similarity index 100% rename from exercises/space-age/space_age.rb rename to exercises/practice/space-age/space_age.rb diff --git a/exercises/space-age/space_age_test.rb b/exercises/practice/space-age/space_age_test.rb similarity index 100% rename from exercises/space-age/space_age_test.rb rename to exercises/practice/space-age/space_age_test.rb diff --git a/exercises/strain/.meta/solutions/strain.rb b/exercises/practice/strain/.meta/solutions/strain.rb similarity index 100% rename from exercises/strain/.meta/solutions/strain.rb rename to exercises/practice/strain/.meta/solutions/strain.rb diff --git a/exercises/strain/README.md b/exercises/practice/strain/README.md similarity index 100% rename from exercises/strain/README.md rename to exercises/practice/strain/README.md diff --git a/exercises/strain/strain.rb b/exercises/practice/strain/strain.rb similarity index 100% rename from exercises/strain/strain.rb rename to exercises/practice/strain/strain.rb diff --git a/exercises/strain/strain_test.rb b/exercises/practice/strain/strain_test.rb similarity index 100% rename from exercises/strain/strain_test.rb rename to exercises/practice/strain/strain_test.rb diff --git a/exercises/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb b/exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb similarity index 100% rename from exercises/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb rename to exercises/practice/sum-of-multiples/.meta/generator/sum_of_multiples_case.rb diff --git a/exercises/sum-of-multiples/.meta/solutions/sum_of_multiples.rb b/exercises/practice/sum-of-multiples/.meta/solutions/sum_of_multiples.rb similarity index 100% rename from exercises/sum-of-multiples/.meta/solutions/sum_of_multiples.rb rename to exercises/practice/sum-of-multiples/.meta/solutions/sum_of_multiples.rb diff --git a/exercises/sum-of-multiples/.meta/tests.toml b/exercises/practice/sum-of-multiples/.meta/tests.toml similarity index 100% rename from exercises/sum-of-multiples/.meta/tests.toml rename to exercises/practice/sum-of-multiples/.meta/tests.toml diff --git a/exercises/sum-of-multiples/README.md b/exercises/practice/sum-of-multiples/README.md similarity index 100% rename from exercises/sum-of-multiples/README.md rename to exercises/practice/sum-of-multiples/README.md diff --git a/exercises/sum-of-multiples/sum_of_multiples.rb b/exercises/practice/sum-of-multiples/sum_of_multiples.rb similarity index 100% rename from exercises/sum-of-multiples/sum_of_multiples.rb rename to exercises/practice/sum-of-multiples/sum_of_multiples.rb diff --git a/exercises/sum-of-multiples/sum_of_multiples_test.rb b/exercises/practice/sum-of-multiples/sum_of_multiples_test.rb similarity index 100% rename from exercises/sum-of-multiples/sum_of_multiples_test.rb rename to exercises/practice/sum-of-multiples/sum_of_multiples_test.rb diff --git a/exercises/tournament/.meta/generator/tournament_case.rb b/exercises/practice/tournament/.meta/generator/tournament_case.rb similarity index 100% rename from exercises/tournament/.meta/generator/tournament_case.rb rename to exercises/practice/tournament/.meta/generator/tournament_case.rb diff --git a/exercises/tournament/.meta/solutions/tournament.rb b/exercises/practice/tournament/.meta/solutions/tournament.rb similarity index 100% rename from exercises/tournament/.meta/solutions/tournament.rb rename to exercises/practice/tournament/.meta/solutions/tournament.rb diff --git a/exercises/tournament/.meta/tests.toml b/exercises/practice/tournament/.meta/tests.toml similarity index 100% rename from exercises/tournament/.meta/tests.toml rename to exercises/practice/tournament/.meta/tests.toml diff --git a/exercises/tournament/README.md b/exercises/practice/tournament/README.md similarity index 100% rename from exercises/tournament/README.md rename to exercises/practice/tournament/README.md diff --git a/exercises/tournament/tournament.rb b/exercises/practice/tournament/tournament.rb similarity index 100% rename from exercises/tournament/tournament.rb rename to exercises/practice/tournament/tournament.rb diff --git a/exercises/tournament/tournament_test.rb b/exercises/practice/tournament/tournament_test.rb similarity index 100% rename from exercises/tournament/tournament_test.rb rename to exercises/practice/tournament/tournament_test.rb diff --git a/exercises/transpose/.meta/generator/transpose_case.rb b/exercises/practice/transpose/.meta/generator/transpose_case.rb similarity index 100% rename from exercises/transpose/.meta/generator/transpose_case.rb rename to exercises/practice/transpose/.meta/generator/transpose_case.rb diff --git a/exercises/transpose/.meta/solutions/transpose.rb b/exercises/practice/transpose/.meta/solutions/transpose.rb similarity index 100% rename from exercises/transpose/.meta/solutions/transpose.rb rename to exercises/practice/transpose/.meta/solutions/transpose.rb diff --git a/exercises/transpose/.meta/tests.toml b/exercises/practice/transpose/.meta/tests.toml similarity index 100% rename from exercises/transpose/.meta/tests.toml rename to exercises/practice/transpose/.meta/tests.toml diff --git a/exercises/transpose/README.md b/exercises/practice/transpose/README.md similarity index 100% rename from exercises/transpose/README.md rename to exercises/practice/transpose/README.md diff --git a/exercises/transpose/transpose.rb b/exercises/practice/transpose/transpose.rb similarity index 100% rename from exercises/transpose/transpose.rb rename to exercises/practice/transpose/transpose.rb diff --git a/exercises/transpose/transpose_test.rb b/exercises/practice/transpose/transpose_test.rb similarity index 100% rename from exercises/transpose/transpose_test.rb rename to exercises/practice/transpose/transpose_test.rb diff --git a/exercises/triangle/.meta/generator/triangle_case.rb b/exercises/practice/triangle/.meta/generator/triangle_case.rb similarity index 100% rename from exercises/triangle/.meta/generator/triangle_case.rb rename to exercises/practice/triangle/.meta/generator/triangle_case.rb diff --git a/exercises/triangle/.meta/solutions/triangle.rb b/exercises/practice/triangle/.meta/solutions/triangle.rb similarity index 100% rename from exercises/triangle/.meta/solutions/triangle.rb rename to exercises/practice/triangle/.meta/solutions/triangle.rb diff --git a/exercises/triangle/.meta/tests.toml b/exercises/practice/triangle/.meta/tests.toml similarity index 100% rename from exercises/triangle/.meta/tests.toml rename to exercises/practice/triangle/.meta/tests.toml diff --git a/exercises/triangle/README.md b/exercises/practice/triangle/README.md similarity index 100% rename from exercises/triangle/README.md rename to exercises/practice/triangle/README.md diff --git a/exercises/triangle/triangle.rb b/exercises/practice/triangle/triangle.rb similarity index 100% rename from exercises/triangle/triangle.rb rename to exercises/practice/triangle/triangle.rb diff --git a/exercises/triangle/triangle_test.rb b/exercises/practice/triangle/triangle_test.rb similarity index 100% rename from exercises/triangle/triangle_test.rb rename to exercises/practice/triangle/triangle_test.rb diff --git a/exercises/trinary/.meta/solutions/trinary.rb b/exercises/practice/trinary/.meta/solutions/trinary.rb similarity index 100% rename from exercises/trinary/.meta/solutions/trinary.rb rename to exercises/practice/trinary/.meta/solutions/trinary.rb diff --git a/exercises/trinary/.meta/tests.toml b/exercises/practice/trinary/.meta/tests.toml similarity index 100% rename from exercises/trinary/.meta/tests.toml rename to exercises/practice/trinary/.meta/tests.toml diff --git a/exercises/trinary/README.md b/exercises/practice/trinary/README.md similarity index 100% rename from exercises/trinary/README.md rename to exercises/practice/trinary/README.md diff --git a/exercises/trinary/trinary.rb b/exercises/practice/trinary/trinary.rb similarity index 100% rename from exercises/trinary/trinary.rb rename to exercises/practice/trinary/trinary.rb diff --git a/exercises/trinary/trinary_test.rb b/exercises/practice/trinary/trinary_test.rb similarity index 100% rename from exercises/trinary/trinary_test.rb rename to exercises/practice/trinary/trinary_test.rb diff --git a/exercises/twelve-days/.meta/solutions/twelve_days.rb b/exercises/practice/twelve-days/.meta/solutions/twelve_days.rb similarity index 100% rename from exercises/twelve-days/.meta/solutions/twelve_days.rb rename to exercises/practice/twelve-days/.meta/solutions/twelve_days.rb diff --git a/exercises/twelve-days/.meta/tests.toml b/exercises/practice/twelve-days/.meta/tests.toml similarity index 100% rename from exercises/twelve-days/.meta/tests.toml rename to exercises/practice/twelve-days/.meta/tests.toml diff --git a/exercises/twelve-days/README.md b/exercises/practice/twelve-days/README.md similarity index 100% rename from exercises/twelve-days/README.md rename to exercises/practice/twelve-days/README.md diff --git a/exercises/twelve-days/song.txt b/exercises/practice/twelve-days/song.txt similarity index 100% rename from exercises/twelve-days/song.txt rename to exercises/practice/twelve-days/song.txt diff --git a/exercises/twelve-days/twelve_days.rb b/exercises/practice/twelve-days/twelve_days.rb similarity index 100% rename from exercises/twelve-days/twelve_days.rb rename to exercises/practice/twelve-days/twelve_days.rb diff --git a/exercises/twelve-days/twelve_days_test.rb b/exercises/practice/twelve-days/twelve_days_test.rb similarity index 100% rename from exercises/twelve-days/twelve_days_test.rb rename to exercises/practice/twelve-days/twelve_days_test.rb diff --git a/exercises/two-bucket/.meta/generator/two_bucket_case.rb b/exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb similarity index 100% rename from exercises/two-bucket/.meta/generator/two_bucket_case.rb rename to exercises/practice/two-bucket/.meta/generator/two_bucket_case.rb diff --git a/exercises/two-bucket/.meta/solutions/two_bucket.rb b/exercises/practice/two-bucket/.meta/solutions/two_bucket.rb similarity index 100% rename from exercises/two-bucket/.meta/solutions/two_bucket.rb rename to exercises/practice/two-bucket/.meta/solutions/two_bucket.rb diff --git a/exercises/two-bucket/.meta/tests.toml b/exercises/practice/two-bucket/.meta/tests.toml similarity index 100% rename from exercises/two-bucket/.meta/tests.toml rename to exercises/practice/two-bucket/.meta/tests.toml diff --git a/exercises/two-bucket/README.md b/exercises/practice/two-bucket/README.md similarity index 100% rename from exercises/two-bucket/README.md rename to exercises/practice/two-bucket/README.md diff --git a/exercises/two-bucket/two_bucket.rb b/exercises/practice/two-bucket/two_bucket.rb similarity index 100% rename from exercises/two-bucket/two_bucket.rb rename to exercises/practice/two-bucket/two_bucket.rb diff --git a/exercises/two-bucket/two_bucket_test.rb b/exercises/practice/two-bucket/two_bucket_test.rb similarity index 100% rename from exercises/two-bucket/two_bucket_test.rb rename to exercises/practice/two-bucket/two_bucket_test.rb diff --git a/exercises/two-fer/.meta/generator/two_fer_case.rb b/exercises/practice/two-fer/.meta/generator/two_fer_case.rb similarity index 100% rename from exercises/two-fer/.meta/generator/two_fer_case.rb rename to exercises/practice/two-fer/.meta/generator/two_fer_case.rb diff --git a/exercises/two-fer/.meta/solutions/two_fer.rb b/exercises/practice/two-fer/.meta/solutions/two_fer.rb similarity index 100% rename from exercises/two-fer/.meta/solutions/two_fer.rb rename to exercises/practice/two-fer/.meta/solutions/two_fer.rb diff --git a/exercises/two-fer/.meta/tests.toml b/exercises/practice/two-fer/.meta/tests.toml similarity index 100% rename from exercises/two-fer/.meta/tests.toml rename to exercises/practice/two-fer/.meta/tests.toml diff --git a/exercises/two-fer/README.md b/exercises/practice/two-fer/README.md similarity index 100% rename from exercises/two-fer/README.md rename to exercises/practice/two-fer/README.md diff --git a/exercises/two-fer/two_fer.rb b/exercises/practice/two-fer/two_fer.rb similarity index 100% rename from exercises/two-fer/two_fer.rb rename to exercises/practice/two-fer/two_fer.rb diff --git a/exercises/two-fer/two_fer_test.rb b/exercises/practice/two-fer/two_fer_test.rb similarity index 100% rename from exercises/two-fer/two_fer_test.rb rename to exercises/practice/two-fer/two_fer_test.rb diff --git a/exercises/word-count/.meta/generator/word_count_case.rb b/exercises/practice/word-count/.meta/generator/word_count_case.rb similarity index 100% rename from exercises/word-count/.meta/generator/word_count_case.rb rename to exercises/practice/word-count/.meta/generator/word_count_case.rb diff --git a/exercises/word-count/.meta/solutions/word_count.rb b/exercises/practice/word-count/.meta/solutions/word_count.rb similarity index 100% rename from exercises/word-count/.meta/solutions/word_count.rb rename to exercises/practice/word-count/.meta/solutions/word_count.rb diff --git a/exercises/word-count/.meta/tests.toml b/exercises/practice/word-count/.meta/tests.toml similarity index 100% rename from exercises/word-count/.meta/tests.toml rename to exercises/practice/word-count/.meta/tests.toml diff --git a/exercises/word-count/README.md b/exercises/practice/word-count/README.md similarity index 100% rename from exercises/word-count/README.md rename to exercises/practice/word-count/README.md diff --git a/exercises/word-count/word_count.rb b/exercises/practice/word-count/word_count.rb similarity index 100% rename from exercises/word-count/word_count.rb rename to exercises/practice/word-count/word_count.rb diff --git a/exercises/word-count/word_count_test.rb b/exercises/practice/word-count/word_count_test.rb similarity index 100% rename from exercises/word-count/word_count_test.rb rename to exercises/practice/word-count/word_count_test.rb diff --git a/exercises/wordy/.meta/generator/wordy_case.rb b/exercises/practice/wordy/.meta/generator/wordy_case.rb similarity index 100% rename from exercises/wordy/.meta/generator/wordy_case.rb rename to exercises/practice/wordy/.meta/generator/wordy_case.rb diff --git a/exercises/wordy/.meta/solutions/wordy.rb b/exercises/practice/wordy/.meta/solutions/wordy.rb similarity index 100% rename from exercises/wordy/.meta/solutions/wordy.rb rename to exercises/practice/wordy/.meta/solutions/wordy.rb diff --git a/exercises/wordy/.meta/tests.toml b/exercises/practice/wordy/.meta/tests.toml similarity index 100% rename from exercises/wordy/.meta/tests.toml rename to exercises/practice/wordy/.meta/tests.toml diff --git a/exercises/wordy/README.md b/exercises/practice/wordy/README.md similarity index 100% rename from exercises/wordy/README.md rename to exercises/practice/wordy/README.md diff --git a/exercises/wordy/wordy.rb b/exercises/practice/wordy/wordy.rb similarity index 100% rename from exercises/wordy/wordy.rb rename to exercises/practice/wordy/wordy.rb diff --git a/exercises/wordy/wordy_test.rb b/exercises/practice/wordy/wordy_test.rb similarity index 100% rename from exercises/wordy/wordy_test.rb rename to exercises/practice/wordy/wordy_test.rb diff --git a/exercises/zipper/.meta/generator/zipper_case.rb b/exercises/practice/zipper/.meta/generator/zipper_case.rb similarity index 100% rename from exercises/zipper/.meta/generator/zipper_case.rb rename to exercises/practice/zipper/.meta/generator/zipper_case.rb diff --git a/exercises/zipper/.meta/solutions/zipper.rb b/exercises/practice/zipper/.meta/solutions/zipper.rb similarity index 100% rename from exercises/zipper/.meta/solutions/zipper.rb rename to exercises/practice/zipper/.meta/solutions/zipper.rb diff --git a/exercises/zipper/.meta/tests.toml b/exercises/practice/zipper/.meta/tests.toml similarity index 100% rename from exercises/zipper/.meta/tests.toml rename to exercises/practice/zipper/.meta/tests.toml diff --git a/exercises/zipper/README.md b/exercises/practice/zipper/README.md similarity index 100% rename from exercises/zipper/README.md rename to exercises/practice/zipper/README.md diff --git a/exercises/zipper/zipper.rb b/exercises/practice/zipper/zipper.rb similarity index 100% rename from exercises/zipper/zipper.rb rename to exercises/practice/zipper/zipper.rb diff --git a/exercises/zipper/zipper_test.rb b/exercises/practice/zipper/zipper_test.rb similarity index 100% rename from exercises/zipper/zipper_test.rb rename to exercises/practice/zipper/zipper_test.rb diff --git a/reference/exercise-concepts/nucleotide-count.md b/reference/exercise-concepts/nucleotide-count.md new file mode 100644 index 0000000000..2b98ea2305 --- /dev/null +++ b/reference/exercise-concepts/nucleotide-count.md @@ -0,0 +1,48 @@ +# Concepts of nucleotide-count + +## General + +- class level methods: used as the starting point of the exercise. They may be named with `self.method_name` notation or with a `self` block. Another way of creating class methods is extending a module. +- module methods: depending on the approach, they may be used instead of the class methods. +- factory pattern and object creation: the method `from_dna` may be used to create instances of the main class. +- instance variables: store the common value/state for the instance. +- accessors: `att_reader` may be used to access instance variables. +- access modifiers: `private` may be used to restrict access to the readers. +- method definition: the `histogram` method needs to be defined. +- method arguments: the method `from_dna` needs an argument. +- strings: one string is passed as the input so it may be necessary to know about strings and string manipulation. +- mixins: one way of solving this exercise is including the `Enumerable` module so it may be necessary to know about Ruby mixins like `Enumerable` or `Comparable`. +- loops: it may be necessary to iterate over the input data using loops and indexes. +- collections: may be used to iterate or transform the input data. Some collections' methods that may be used: `inject, each, each_with_object, count` +- exceptions: necessary to raise an exception if the input is not valid. +- return values: methods need to return values either implicitly or explicitly. +- constants: constants may be used to store static information like DNA values. +- namespaces: namespaces may be used along with constants. +- conditional statements: conditional statements may be used to check if the input is valid. +- blocks: they are used in any of the `Enumerable` methods. +- regular expressions: may be used to validate the input. + +## Approach: use `Enumerable` mixin + +- Make the class that represents the nucleotides strand to include `Enumerable` so that all `Enumerable` methods are available. +- Requires implementation of `each` method. See [Enumerable mixin documentation](https://ruby-doc.org/core-2.7.0/Enumerable.html) + +## Approach: Use collections + `Enumerable` methods. + +- Use `Enumerable#count` to count nucleotide occurrences. +- Use `String#chars` and `Enumerable#each_with_object` to create the histogram + +## Approach: Use indexes to loop over the chars. + +- Similar to the previous approach but using indexes and loops to iterate over an `Array` of characters. + +## Approach: Use collections + String#count and Regex. + +- Use `String#count` to count nucleotide occurrences. +- Initialize a hash for the histogram then use `Enumerable#each` and `String#count` to fill it. +- Use Regex to validate the input. + +## Approach: Use collections + String#count. + +- Similar to the previous approach but using `String#count` and `String#size` to validate the input. +- For the input validation part it's also possible to use array difference to remove nucleotides from the input resulting in an empty collection for the valid inputs. diff --git a/reference/exercise-concepts/resistor-color-duo.md b/reference/exercise-concepts/resistor-color-duo.md new file mode 100644 index 0000000000..bb59092d44 --- /dev/null +++ b/reference/exercise-concepts/resistor-color-duo.md @@ -0,0 +1,54 @@ +# Concepts of Resistor Color Duo + +## General + +[Example solution](https://github.com/exercism/ruby/blob/master/exercises/resistor-color-duo/.meta/solutions/resistor_color_duo.rb) + +- Classes: + - Defining classes +- Methods: + - Defining methods + - Arguments + - Return values +- Strings: + - What is a `String` +- Class methods: + - How to define a class method + +Depending on the approach either: + +- Hashes: + - How to initialize/create a hash + - How to access it's values + +or + +- Arrays: + - How to create an `Array` + - What are indexes and how can they be useful + - How to get the index of a value that's stored in an `Array` + +### Approach: use string interpolation (positional approach) + +- `String` interpolation +- How to get the `Integer` representation of a `String` + +### Approach: Using `Enumerable` methods + +- Loops: + - What it is + - How it works + - `Enumerable` methods and finding the appropriate one + - Return value of `Enumerable` methods +- Blocks: + - What blocks are + - How to use them with `Enumerable` methods + - How to chain method calls to blocks +- Arrays: + - How to take the first `n` elements form an `Array` +- Strings: + - How to get the `Integer` representation of a `String` + +### Approach: `first_value * 10 + second_value` + +- No special requirements other than the requirements mentioned in the general section diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md new file mode 100644 index 0000000000..8cb6712479 --- /dev/null +++ b/reference/implementing-a-concept-exercise.md @@ -0,0 +1,90 @@ +# How to implement a Ruby concept exercise + +This document describes how to implement a concept exercise for the Ruby track. + +**Please please please read the docs before starting.** Posting PRs without reading these docs will be a lot more frustrating for you during the review cycle, and exhaust Exercism's maintainers' time. So, before diving into the implementation, please read the following documents: + +- [The features of v3][docs-features-of-v3]. +- [Rationale for v3][docs-rationale-for-v3]. +- [What are concept exercise and how they are structured?][docs-concept-exercises] + +Please also watch the following video: + +- [The Anatomy of a Concept Exercise][anatomy-of-a-concept-exercise]. + +As this document is generic, `` will be used as the placeholder for the name of the exercise in underscore-case (e.g. `calculator_conundrum`) and `` will be used as the placeholder for the name of a concept. + +Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what not). This information can be found in the exercise's GitHub issue. Having done this, please read the [Ruby concept exercises introduction][concept-exercises]. + +To implement a concept exercise, the following files must be added: + +
+languages
+└── ruby
+    ├── concepts
+    |   └── <CONCEPT>
+    |       ├── about.md
+    |       └── links.json
+    └── exercises
+        └── concept
+            └── 
+                ├── .docs
+                |   ├── instructions.md
+                |   ├── introduction.md
+                |   ├── hints.md
+                |   └── source.md (required if there are third-party sources)
+                ├── .meta
+                |   |── config.json
+                |   |── design.md
+                |   └── exemplar.rb
+                ├── .rb
+                └── _test.rb
+
+ +## Step 1: Add code files + +The code files are track-specific and should be designed to help the student learn the exercise's concepts. The following Ruby code files must be added (not necessarily in this order): + +- `.rb`. the stub implementation file, which is the starting point for students to work on the exercise. +- `_test.rb`: the test suite. +- `.meta/exemplar.rb`: an exemplar implementation that passes all the tests. + +## Step 2: Add documentation files + +How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. + +## Step 3: Update list of implemented exercises + +- Add the exercise to the [list of implemented exercises][implemented-exercises]. + +## Step 4: Add analyzer (optional) + +Some exercises could benefit from having an exercise-specific [analyzer][analyzer]. If so, specify what analysis rules should be applied to this exercise and why. + +_Skip this step if you're not sure what to do._ + +## Step 5: Add representation (optional) + +Some exercises could benefit from having an custom representation as generated by the [Ruby representer][representer]. If so, specify what changes to the representation should be applied and why. + +_Skip this step if you're not sure what to do._ + +## Inspiration + +When implementing an exercise, it can be very useful to look at already implemented Ruby exercises like the [strings exercise][concept-exercise-strings]. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. + +## Help + +If you have any questions regarding implementing the exercise, please post them as comments in the exercise's GitHub issue. + +[analyzer]: https://github.com/exercism/ruby-analyzer +[representer]: https://github.com/exercism/ruby-representer +[concept-exercises]: ../exercises/concept/README.md +[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/main/docs/maintainers/generic-how-to-implement-a-concept-exercise.md +[docs-concept-exercises]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md +[docs-rationale-for-v3]: https://github.com/exercism/v3/blob/main/docs/rationale-for-v3.md +[docs-features-of-v3]: https://github.com/exercism/v3/blob/main/docs/features-of-v3.md +[anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA +[concept-exercise-strings]: ../exercises/concept/strings +[reference]: https://github.com/exercism/v3/blob/main/reference +[implemented-exercises]: ../exercises/concept/README.md#implemented-exercises