From 4d26aaf74fc67d39b1b008a4f836dd68a3a0ce0c Mon Sep 17 00:00:00 2001 From: meatball <69751659+meatball133@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:52:47 +0200 Subject: [PATCH] [New Concept]: Symbols (#1560) * Add symbols * Add design.md * Fixes * Fix prerequisites * Fix test file * Update exercises/concept/port-palermo/.docs/introduction.md Co-authored-by: Victor Goff * Update concepts/symbols/introduction.md Co-authored-by: Victor Goff * Update concepts/symbols/about.md Co-authored-by: Victor Goff * Update concepts/symbols/about.md Co-authored-by: Victor Goff * Update concepts/symbols/about.md Co-authored-by: Victor Goff * Update concepts/symbols/about.md Co-authored-by: Victor Goff * Update concepts/symbols/about.md Co-authored-by: Victor Goff * formulation improvements * Update blurb --------- Co-authored-by: Victor Goff --- concepts/symbols/.meta/config.json | 5 ++ concepts/symbols/about.md | 80 +++++++++++++++++++ concepts/symbols/introduction.md | 55 +++++++++++++ concepts/symbols/links.json | 10 +++ config.json | 17 ++++ exercises/concept/port-palermo/.docs/hints.md | 24 ++++++ .../port-palermo/.docs/instructions.md | 51 ++++++++++++ .../port-palermo/.docs/introduction.md | 55 +++++++++++++ .../concept/port-palermo/.meta/config.json | 18 +++++ .../concept/port-palermo/.meta/design.md | 34 ++++++++ .../concept/port-palermo/.meta/exemplar.rb | 12 +++ .../concept/port-palermo/port_palermo.rb | 11 +++ .../concept/port-palermo/port_palermo_test.rb | 36 +++++++++ 13 files changed, 408 insertions(+) create mode 100644 concepts/symbols/.meta/config.json create mode 100644 concepts/symbols/about.md create mode 100644 concepts/symbols/introduction.md create mode 100644 concepts/symbols/links.json create mode 100644 exercises/concept/port-palermo/.docs/hints.md create mode 100644 exercises/concept/port-palermo/.docs/instructions.md create mode 100644 exercises/concept/port-palermo/.docs/introduction.md create mode 100644 exercises/concept/port-palermo/.meta/config.json create mode 100644 exercises/concept/port-palermo/.meta/design.md create mode 100644 exercises/concept/port-palermo/.meta/exemplar.rb create mode 100644 exercises/concept/port-palermo/port_palermo.rb create mode 100644 exercises/concept/port-palermo/port_palermo_test.rb diff --git a/concepts/symbols/.meta/config.json b/concepts/symbols/.meta/config.json new file mode 100644 index 0000000000..ffa0034edb --- /dev/null +++ b/concepts/symbols/.meta/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Symbols are very important in Ruby. They are used as \"identity\". They are immutable, guaranteed to be a single item no matter where it is used or referenced. They are used internally as variable, method, constants, and keyword identifiers. They are also useful, and often used, as keys in a `Hash`.", + "authors": ["meatball133"], + "contributors": ["kotp"] +} diff --git a/concepts/symbols/about.md b/concepts/symbols/about.md new file mode 100644 index 0000000000..7b18028211 --- /dev/null +++ b/concepts/symbols/about.md @@ -0,0 +1,80 @@ +# About + +[Symbols][symbols] are named identifiers that can be used to refer to a value. +Symbols are created through a symbol literal, which is by prefixing a name with a `:` character, e.g. `:foo`. +They also allow for being written with quotes, e.g. `:"foo"`, which allows, for example, spaces in the name. + +```ruby +:foo # => :foo +:"foo boo" # => :"foo boo" +``` + +Symbols are used in many places in the language, including as keys in hashes, to represent method names and variable names. + +## Identifier + +What makes symbols different from strings is that they are identifiers, and do not represent data or text. +This means that two symbols with the same name are always the same object. + +```ruby +"foo".object_id # => 60 +"foo".object_id # => 80 +:foo.object_id # => 1086748 +:foo.object_id # => 1086748 +``` + +## Modifying Symbols + +Symbols are immutable, which means that they cannot be modified. +This means that when you "modify" a symbol, you are actually creating a new symbol. +There are a few methods that can be used to manipulate symbols, they all return new symbols. +All methods can be found in the [Symbol API][symbols-api]. + +```ruby +:foo.upcase # => :FOO + +:foo.object_id # => 1086748 +:foo.upcase.object_id # => 60 +``` + +The benefit of symbols being immutable is that they are more memory efficient than strings, but also safer to use as identifiers. + +## Conversion + +Symbols can be converted to strings and vice versa. +This can be useful when you want to modify a symbol, or when you want to use a symbol as a string. +To present a symbol as a string, you can use the `String#to_sym` method, and to do the opposite, you can use the `Symbol#to_s` method. +Due to symbols having a limited set of methods, it can be useful to convert a symbol to a string to use string methods on it, if a new symbol is needed. + +```ruby +:foo.to_s # => "foo" +"foo".to_sym # => :foo +``` + +## Getting names in scopes + +In Ruby you can get names in scopes by using various methods to get names of constants, methods, and variables. +These methods returns arrays of symbols. + +Some methods are `Module#constants`, `Module#instance_methods`, `Module#class_variables`, `global_variables` and `local_variables`. + +```ruby +module Foo + BAR = 1 + def self.baz; end +end + +a = 1 + +Foo.constants # => [:BAR] +Foo.instance_methods # => [:baz] + +local_variables # => [:a] +``` + +All methods can be found in the [Kernel API][kernal-api] and [Module API][module-api]. + +[symbols]: https://www.rubyguides.com/2018/02/ruby-symbols/ +[symbols-api]: https://rubyapi.org/o/symbol +[kernal-api]: https://rubyapi.org/o/kernel +[module-api]: https://rubyapi.org/o/module diff --git a/concepts/symbols/introduction.md b/concepts/symbols/introduction.md new file mode 100644 index 0000000000..9b09dd9eb8 --- /dev/null +++ b/concepts/symbols/introduction.md @@ -0,0 +1,55 @@ +# About + +[Symbols][symbols] are named identifiers that can be used to refer to a value. +Symbols are created through a symbol literal, which is by prefixing a name with a `:` character, e.g. `:foo`. +They also allow for being written with quotes, e.g. `:"foo"`, which allows, for example, spaces in the name. + +```ruby +:foo # => :foo +:"foo boo" # => :"foo boo" +``` + +Symbols are used in many places in the language, including as keys in hashes, to represent method names and variable names. + +## Identifier + +What makes symbols different from strings is that they are identifiers, and do not represent data or text. +This means that two symbols with the same name are always the same object. + +```ruby +"foo".object_id # => 60 +"foo".object_id # => 80 +:foo.object_id # => 1086748 +:foo.object_id # => 1086748 +``` + +## Modifying Symbols + +Symbols are immutable, which means that they cannot be modified. +This means that when you "modify" a symbol, you are actually creating a new symbol. +There are a few methods that can be used to manipulate symbols, they all return new symbols. +All methods can be found in the [Symbol API][symbols-api]. + +```ruby +:foo.upcase # => :FOO + +:foo.object_id # => 1086748 +:foo.upcase.object_id # => 60 +``` + +The benefit of symbols being immutable is that they are more memory efficient than strings, but also safer to use as identifiers. + +## Conversion + +Symbols can be converted to strings and vice versa. +This can be useful when you want to modify a symbol, or when you want to use a symbol as a string. +To present a symbol as a string, you can use the `String#to_sym` method, and to do the opposite, you can use the `Symbol#to_s` method. +Due to symbols having a limited set of methods, it can be useful to convert a symbol to a string to use string methods on it, if a new symbol is needed. + +```ruby +:foo.to_s # => "foo" +"foo".to_sym # => :foo +``` + +[symbols]: https://www.rubyguides.com/2018/02/ruby-symbols/ +[symbols-api]: https://rubyapi.org/o/symbol diff --git a/concepts/symbols/links.json b/concepts/symbols/links.json new file mode 100644 index 0000000000..51a834a212 --- /dev/null +++ b/concepts/symbols/links.json @@ -0,0 +1,10 @@ +[ + { + "url": "https://www.rubyguides.com/2018/02/ruby-symbols/", + "description": "Ruby Guides: Ruby Symbols" + }, + { + "url": "https://rubyapi.org/symbol/", + "description": "Ruby API: Symbol" + } +] diff --git a/config.json b/config.json index 5e5af51f95..5047efb28a 100644 --- a/config.json +++ b/config.json @@ -107,6 +107,17 @@ "conditionals" ] }, + { + "slug": "port-palermo", + "name": "Port Of Palermo", + "uuid": "d852aa08-f712-4c83-b19a-9adef4318b5e", + "concepts": [ + "symbols" + ], + "prerequisites": [ + "conditionals" + ] + }, { "slug": "bird-count", "name": "Bird Count", @@ -118,6 +129,7 @@ "prerequisites": [ "instance-variables", "booleans", + "symbols", "conditionals" ] }, @@ -1639,6 +1651,11 @@ "slug": "strings", "name": "Strings" }, + { + "uuid": "4b0f3718-cc06-4aa6-8b0f-7db3bbe6af5d", + "slug": "symbols", + "name": "Symbols" + }, { "uuid": "0189a402-ed46-47ee-9f5b-cfa5f557720d", "slug": "enumeration", diff --git a/exercises/concept/port-palermo/.docs/hints.md b/exercises/concept/port-palermo/.docs/hints.md new file mode 100644 index 0000000000..717f1de552 --- /dev/null +++ b/exercises/concept/port-palermo/.docs/hints.md @@ -0,0 +1,24 @@ +# Hints + +## 1. Create the ports identifier + +- You need to define a [constant][constants] that should contain the symbol value specified in the instructions. + +## 2. Get identifiers for other ports + +- A string can be [slice][slice] to get parts of it. +- `Strings` have a [method][upcase] to upcase the letters. +- `Strings` have a [method][to_sym] to convert a string to a symbol. + +## 3. Determine which terminal a ship should dock at + +- Symbol has a [method][to_s] to convert a symbol to a string. +- A string can be [slice][slice] to get parts of it. +- Use conditional [`if`][doc-if], to check if the ship is carrying `"OIL"` or `"GAS"`. + +[doc-if]: https://ruby-doc.org/core/syntax/control_expressions_rdoc.html#label-if+Expression +[constants]: https://www.rubyguides.com/2017/07/ruby-constants/ +[upcase]: https://ruby-doc.org/core/String.html#method-i-upcase +[slice]: https://ruby-doc.org/core/String.html#class-String-label-String+Slices +[to_s]: https://rubyapi.org/symbol#method-i-to_s +[to_sym]: https://rubyapi.org/string#method-i-to_sym diff --git a/exercises/concept/port-palermo/.docs/instructions.md b/exercises/concept/port-palermo/.docs/instructions.md new file mode 100644 index 0000000000..d86048b284 --- /dev/null +++ b/exercises/concept/port-palermo/.docs/instructions.md @@ -0,0 +1,51 @@ +# Instructions + +The port of Palermo is a busy harbor, with a lot of ships coming and going. +It has for a long time had a manual system for keeping track of the ships that are currently in the harbor. +This system is very error prone, and the harbor chief has decided to replace it with a computerized system. + +The harbor chief has hired you to implement the new system. +The system has to handle identifiers for ships, but also for destinations. + +## 1. Create the ports identifier + +The first thing you need to do is to create the identifier for the port of Palermo. +The identifier are the first four letters of the name of the port, in uppercase. + +Define the `Port.Identifier` constant to be a symbol with the value `:PALE`. + +```ruby +Port::Identifier +# => :PALE +``` + +## 2. Get identifiers for other ports + +The program will also have to handle other ports, so you need to create identifiers for them as well. +The port would like the system to be automated and since ports uses different naming conventions, the identifiers should be generated from the name of the port. +The identifier are the first four letters of the name of the port, in uppercase. + +Define the `Port.get_identifier` method to take a string as an argument, and returns the identifier as a symbol for that port. + +```ruby +Port.get_identifier("Hamburg") +# => :HAMB +``` + +## 3. Determine which terminal a ship should dock at + +The port has two terminals, and the system needs to determine which terminal a ship should dock at. +The terminal is determined by the identifier of the ship. + +The identifier is built of 2 parts, the first part is made of 3 uppercased letters which says which cargo the ship is carrying, and then 3 numbers which is the unique identifier of the ship. + +If the identifier of the ship is carrying: **OIL** or **GAS** the ship should dock at terminal **A**. +Else the ship should dock at terminal **B**. + +Define the `Port.get_terminal` method to take a symbol as an argument which is the identifier of the ship. +The method should return the terminal as a symbol. + +```ruby +Port.get_terminal(:OIL123) +# => :A +``` diff --git a/exercises/concept/port-palermo/.docs/introduction.md b/exercises/concept/port-palermo/.docs/introduction.md new file mode 100644 index 0000000000..9b09dd9eb8 --- /dev/null +++ b/exercises/concept/port-palermo/.docs/introduction.md @@ -0,0 +1,55 @@ +# About + +[Symbols][symbols] are named identifiers that can be used to refer to a value. +Symbols are created through a symbol literal, which is by prefixing a name with a `:` character, e.g. `:foo`. +They also allow for being written with quotes, e.g. `:"foo"`, which allows, for example, spaces in the name. + +```ruby +:foo # => :foo +:"foo boo" # => :"foo boo" +``` + +Symbols are used in many places in the language, including as keys in hashes, to represent method names and variable names. + +## Identifier + +What makes symbols different from strings is that they are identifiers, and do not represent data or text. +This means that two symbols with the same name are always the same object. + +```ruby +"foo".object_id # => 60 +"foo".object_id # => 80 +:foo.object_id # => 1086748 +:foo.object_id # => 1086748 +``` + +## Modifying Symbols + +Symbols are immutable, which means that they cannot be modified. +This means that when you "modify" a symbol, you are actually creating a new symbol. +There are a few methods that can be used to manipulate symbols, they all return new symbols. +All methods can be found in the [Symbol API][symbols-api]. + +```ruby +:foo.upcase # => :FOO + +:foo.object_id # => 1086748 +:foo.upcase.object_id # => 60 +``` + +The benefit of symbols being immutable is that they are more memory efficient than strings, but also safer to use as identifiers. + +## Conversion + +Symbols can be converted to strings and vice versa. +This can be useful when you want to modify a symbol, or when you want to use a symbol as a string. +To present a symbol as a string, you can use the `String#to_sym` method, and to do the opposite, you can use the `Symbol#to_s` method. +Due to symbols having a limited set of methods, it can be useful to convert a symbol to a string to use string methods on it, if a new symbol is needed. + +```ruby +:foo.to_s # => "foo" +"foo".to_sym # => :foo +``` + +[symbols]: https://www.rubyguides.com/2018/02/ruby-symbols/ +[symbols-api]: https://rubyapi.org/o/symbol diff --git a/exercises/concept/port-palermo/.meta/config.json b/exercises/concept/port-palermo/.meta/config.json new file mode 100644 index 0000000000..98681fb400 --- /dev/null +++ b/exercises/concept/port-palermo/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "meatball133" + ], + "files": { + "solution": [ + "port_palermo.rb" + ], + "test": [ + "port_palermo_test.rb" + ], + "exemplar": [ + ".meta/exemplar.rb" + ] + }, + "icon": "strings-package", + "blurb": "Learn about the symbols while helping out with modernize the ports of Palermo computer system." +} diff --git a/exercises/concept/port-palermo/.meta/design.md b/exercises/concept/port-palermo/.meta/design.md new file mode 100644 index 0000000000..59dbde4c71 --- /dev/null +++ b/exercises/concept/port-palermo/.meta/design.md @@ -0,0 +1,34 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Symbols in Ruby. + +## Learning objectives + +- Know of the existence of the `Symbol` object. +- Know how to create a symbol. +- Know of some basic symbol methods (mostly conversion methods). + +## Out of scope + +- Hashes. + +## Concepts + +- `Symbols` + +## Prerequisites + +- `Conditionals` + +## 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/port-palermo/.meta/exemplar.rb b/exercises/concept/port-palermo/.meta/exemplar.rb new file mode 100644 index 0000000000..f717c949d8 --- /dev/null +++ b/exercises/concept/port-palermo/.meta/exemplar.rb @@ -0,0 +1,12 @@ +module Port + Identifier = :PALE + + def self.get_identifier(city) + return city[0..3].upcase.to_sym + end + + def self.get_terminal(ship_identifier) + cargo = ship_identifier.to_s[0..2] + return cargo == "OIL" || cargo == "GAS" ? :A : :B + end +end diff --git a/exercises/concept/port-palermo/port_palermo.rb b/exercises/concept/port-palermo/port_palermo.rb new file mode 100644 index 0000000000..d4d4c3d587 --- /dev/null +++ b/exercises/concept/port-palermo/port_palermo.rb @@ -0,0 +1,11 @@ +module Port + # TODO: define the 'Identifier' constant + + def self.get_identifier(city) + raise 'Please implement the Port.get_identifier method' + end + + def self.get_terminal(ship_identifier) + raise 'Please implement the Port.get_terminal method' + end +end diff --git a/exercises/concept/port-palermo/port_palermo_test.rb b/exercises/concept/port-palermo/port_palermo_test.rb new file mode 100644 index 0000000000..0a6abd92cc --- /dev/null +++ b/exercises/concept/port-palermo/port_palermo_test.rb @@ -0,0 +1,36 @@ +require 'minitest/autorun' +require_relative 'port_palermo' + +class MoviegoerTest < Minitest::Test + def test_identifier + assert_equal :PALE, Port::Identifier + end + + def test_get_identifier_for_hamburg + assert_equal :HAMB, Port.get_identifier("Hamburg") + end + + def test_get_identifier_for_rome + assert_equal :ROME, Port.get_identifier("Rome") + end + + def test_get_identifier_for_kiel + assert_equal :KIEL, Port.get_identifier("Kiel") + end + + def test_get_terminal_for_oil + assert_equal :A, Port.get_terminal(:OIL123) + end + + def test_get_terminal_for_gas + assert_equal :A, Port.get_terminal(:GAS674) + end + + def test_get_terminal_for_cars + assert_equal :B, Port.get_terminal(:CAR942) + end + + def test_get_terminal_for_clothes + assert_equal :B, Port.get_terminal(:CLO315) + end +end