From e3eefa55d06f60e02366b17c4e4689017d5ca62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Fernandes?= Date: Thu, 25 Apr 2024 07:23:16 -0300 Subject: [PATCH] [gleam] complete boutique-inventory --- gleam/boutique-inventory/.gitignore | 4 + gleam/boutique-inventory/HELP.md | 32 ++++ gleam/boutique-inventory/HINTS.md | 21 +++ gleam/boutique-inventory/README.md | 143 ++++++++++++++++++ gleam/boutique-inventory/gleam.toml | 12 ++ gleam/boutique-inventory/manifest.toml | 27 ++++ .../src/boutique_inventory.gleam | 21 +++ .../test/boutique_inventory_test.gleam | 91 +++++++++++ 8 files changed, 351 insertions(+) create mode 100644 gleam/boutique-inventory/.gitignore create mode 100644 gleam/boutique-inventory/HELP.md create mode 100644 gleam/boutique-inventory/HINTS.md create mode 100644 gleam/boutique-inventory/README.md create mode 100644 gleam/boutique-inventory/gleam.toml create mode 100644 gleam/boutique-inventory/manifest.toml create mode 100644 gleam/boutique-inventory/src/boutique_inventory.gleam create mode 100644 gleam/boutique-inventory/test/boutique_inventory_test.gleam diff --git a/gleam/boutique-inventory/.gitignore b/gleam/boutique-inventory/.gitignore new file mode 100644 index 0000000..170cca9 --- /dev/null +++ b/gleam/boutique-inventory/.gitignore @@ -0,0 +1,4 @@ +*.beam +*.ez +build +erl_crash.dump diff --git a/gleam/boutique-inventory/HELP.md b/gleam/boutique-inventory/HELP.md new file mode 100644 index 0000000..7f708bf --- /dev/null +++ b/gleam/boutique-inventory/HELP.md @@ -0,0 +1,32 @@ +# Help + +## Running the tests + +To run the tests, run the command `gleam test` from within the exercise directory. + +## Submitting your solution + +You can submit your solution using the `exercism submit src/boutique_inventory.gleam` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Gleam track's documentation](https://exercism.org/docs/tracks/gleam) +- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +To get help if you're having trouble, you can use one of the following resources: + +- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation. +- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel. +- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. \ No newline at end of file diff --git a/gleam/boutique-inventory/HINTS.md b/gleam/boutique-inventory/HINTS.md new file mode 100644 index 0000000..de05c6b --- /dev/null +++ b/gleam/boutique-inventory/HINTS.md @@ -0,0 +1,21 @@ +# Hints + +## 1. Return a list of the names of the items + +- The [`iterator.map` function][map] can be used to transform the items in an iterator. + +## 2. Return any items that are cheap + +- The [`iterator.filter` function][filter] can be used to remove some items from an iterator. + +## 3. Return any items that are out of stock + +- The [`iterator.filter` function][filter] can be used to remove some items from an iterator. + +## 4. Return the total stock + +- The [`iterator.fold` function][fold] can be used to reduce an iterator to a single value. + +[map]: https://hexdocs.pm/gleam_stdlib/gleam/iterator.html#map +[filter]: https://hexdocs.pm/gleam_stdlib/gleam/iterator.html#filter +[fold]: https://hexdocs.pm/gleam_stdlib/gleam/iterator.html#fold \ No newline at end of file diff --git a/gleam/boutique-inventory/README.md b/gleam/boutique-inventory/README.md new file mode 100644 index 0000000..7571c7f --- /dev/null +++ b/gleam/boutique-inventory/README.md @@ -0,0 +1,143 @@ +# Boutique Inventory + +Welcome to Boutique Inventory on Exercism's Gleam Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +## Iterators + +An `Iterator` in Gleam is similar to a list in that it is an ordered collection of values, where all values are of the same type. It differs from a list in that it is lazy, meaning that it does not store all of its values in memory at once, but instead calculates them as they are needed. + +This is useful when working with sequences that are very large or even infinite in size, as it allows us to work with them when we do not have enough free memory to store them all at once. + +The `gleam/iterator` module defines the `Iterator` type as well as functions for working with iterators. + +Many of the functions for lists also exist for iterators, such as `map`, `filter`, and `take`. These functions return iterators, so the functions do not actually perform any work until the iterator is consumed. + +```gleam +let iter = + [1, 2, 3, 4, 5, 6] + |> iterator.from_list + |> iterator.filter(fn(x) { x > 2 }) + |> iterator.take(2) + +// No work has been done yet as the iterator has not been consumed + +// Consume the iterator and collect the values into a list +iterator.to_list(iter) +// -> [3, 4] +``` + +The `unfold` function can be used to create iterators from a function that is called repeatedly to produce the next value in the sequence. + +Here the `unfold` function is used to create an iterator that produces the Fibonacci sequence: + +```gleam +iterator.unfold(#(0, 1), fn(pair) { + let x = pair.0 + pair.1 + iterator.Next(element: x, accumulator: #(pair.1, x)) +}) +|> iterator.take(6) +|> iterator.to_list +// -> [1, 2, 3, 5, 8, 13] +``` + +The sequence here is infinite, so the `take` function is used to make it finite before collecting the values into a list. If `to_list` is called on an infinite iterator the program will run until the program runs out of memory and crashes. + +## Instructions + +Alizé runs an online fashion boutique. The big annual sale is coming up, so she wants to create some functionality to help take stock of the inventory. + +A single item in the inventory is represented using a custom type. + +```gleam +Item( + name: "White Shirt", + price: 40, + quantity: 6, +) +``` + +## 1. Return a list of the names of the items + +Implement `item_names` function, which takes an iterator of items and returns an iterator of their names in the same order. + +```gleam +[ + Item(price: 65, name: "Maxi Brown Dress", quantity: 8), + Item(price: 50, name: "Red Short Skirt", quantity: 0), + Item(price: 29, name: "Black Short Skirt", quantity: 4), + Item(price: 20, name: "Bamboo Socks Cats", quantity: 7), +] +|> iterator.from_list +|> item_names +|> iterator.to_list + +// -> ["Maxi Brown Dress", "Red Short Skirt", "Black Short Skirt", "Bamboo Socks Cats"] +``` + +## 2. Return any items that are cheap + +Implement the `cheap` function, which takes an iterator of items and returns an iterator of items that cost less than 30. + +```gleam +[ + Item(price: 65, name: "Maxi Brown Dress", quantity: 8), + Item(price: 50, name: "Red Short Skirt", quantity: 0), + Item(price: 29, name: "Black Short Skirt", quantity: 4), + Item(price: 20, name: "Bamboo Socks Cats", quantity: 7), +] +|> iterator.from_list +|> cheap +|> iterator.to_list + +// -> [ +// Item(price: 29, name: "Black Short Skirt", quantity: 4), +// Item(price: 20, name: "Bamboo Socks Cats", quantity: 7), +// ] +``` + +## 3. Return any items that are out of stock + +Implement the `out_of_stock` function which returns any items that have no stock. + +```gleam +[ + Item(price: 65, name: "Maxi Brown Dress", quantity: 8), + Item(price: 50, name: "Red Short Skirt", quantity: 0), + Item(price: 29, name: "Black Short Skirt", quantity: 4), + Item(price: 20, name: "Bamboo Socks Cats", quantity: 7), +] +|> iterator.from_list +|> out_of_stock +|> iterator.to_list + +// -> [ +// Item(price: 50, name: "Red Short Skirt", quantity: 0), +// ] +``` + +## 4. Return the total stock + +Implement the `total_stock` function which calculates the total amount of items in your storeroom: + +```gleam +[ + Item(price: 65, name: "Maxi Brown Dress", quantity: 8), + Item(price: 50, name: "Red Short Skirt", quantity: 0), + Item(price: 29, name: "Black Short Skirt", quantity: 4), + Item(price: 20, name: "Bamboo Socks Cats", quantity: 7), +] +|> iterator.from_list +|> total_stock + +// -> 19 +``` + +## Source + +### Created by + +- @lpil \ No newline at end of file diff --git a/gleam/boutique-inventory/gleam.toml b/gleam/boutique-inventory/gleam.toml new file mode 100644 index 0000000..c30eb37 --- /dev/null +++ b/gleam/boutique-inventory/gleam.toml @@ -0,0 +1,12 @@ +name = "boutique_inventory" +version = "0.1.0" + +[dependencies] +gleam_bitwise = "~> 1.2" +gleam_otp = "~> 0.7 or ~> 1.0" +gleam_stdlib = "~> 0.32 or ~> 1.0" +simplifile = "~> 1.0" +gleam_erlang = ">= 0.25.0 and < 1.0.0" + +[dev-dependencies] +exercism_test_runner = "~> 1.4" diff --git a/gleam/boutique-inventory/manifest.toml b/gleam/boutique-inventory/manifest.toml new file mode 100644 index 0000000..072155d --- /dev/null +++ b/gleam/boutique-inventory/manifest.toml @@ -0,0 +1,27 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" }, + { name = "exercism_test_runner", version = "1.7.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "2FC1BADB19BEC2AE77BFD2D3A606A014C85412A7B874CAFC4BA8CF04B0B257CD" }, + { name = "gap", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "2EE1B0A17E85CF73A0C1D29DA315A2699117A8F549C8E8D89FA8261BE41EDEB1" }, + { name = "glance", version = "0.8.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73" }, + { name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" }, + { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, + { name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" }, + { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, + { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, + { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, + { name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" }, + { name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" }, + { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, +] + +[requirements] +exercism_test_runner = { version = "~> 1.4" } +gleam_bitwise = { version = "~> 1.2" } +gleam_erlang = { version = ">= 0.25.0 and < 1.0.0"} +gleam_otp = { version = "~> 0.7 or ~> 1.0" } +gleam_stdlib = { version = "~> 0.32 or ~> 1.0" } +simplifile = { version = "~> 1.0" } diff --git a/gleam/boutique-inventory/src/boutique_inventory.gleam b/gleam/boutique-inventory/src/boutique_inventory.gleam new file mode 100644 index 0000000..83f9049 --- /dev/null +++ b/gleam/boutique-inventory/src/boutique_inventory.gleam @@ -0,0 +1,21 @@ +import gleam/iterator.{type Iterator} + +pub type Item { + Item(name: String, price: Int, quantity: Int) +} + +pub fn item_names(items: Iterator(Item)) -> Iterator(String) { + iterator.map(items, fn(i) { i.name }) +} + +pub fn cheap(items: Iterator(Item)) -> Iterator(Item) { + iterator.filter(items, fn(i) { i.price < 30 }) +} + +pub fn out_of_stock(items: Iterator(Item)) -> Iterator(Item) { + iterator.filter(items, fn(i) { i.quantity == 0 }) +} + +pub fn total_stock(items: Iterator(Item)) -> Int { + iterator.fold(items, 0, fn(acc, i) { acc + i.quantity }) +} diff --git a/gleam/boutique-inventory/test/boutique_inventory_test.gleam b/gleam/boutique-inventory/test/boutique_inventory_test.gleam new file mode 100644 index 0000000..4c268ba --- /dev/null +++ b/gleam/boutique-inventory/test/boutique_inventory_test.gleam @@ -0,0 +1,91 @@ +import boutique_inventory.{Item} +import exercism/should +import exercism/test_runner +import gleam/iterator + +pub fn main() { + test_runner.main() +} + +pub fn item_names_test() { + [ + Item("Red Brown Dress", 65, 3), + Item("Red Short Skirt", 50, 5), + Item("Black Short Skirt", 29, 1), + ] + |> iterator.from_list + |> boutique_inventory.item_names + |> iterator.to_list + |> should.equal(["Red Brown Dress", "Red Short Skirt", "Black Short Skirt"]) +} + +pub fn item_names_does_not_consume_iterator_test() { + iterator.repeatedly(fn() { + panic as "The iterator should not be consumed by item_names" + }) + |> boutique_inventory.item_names + |> iterator.take(0) + |> iterator.to_list + |> should.equal([]) +} + +pub fn cheap_test() { + [ + Item("Red Brown Dress", 65, 6), + Item("Black Short Skirt", 29, 8), + Item("Red Short Skirt", 50, 4), + Item("Pink Crop Top", 19, 13), + ] + |> iterator.from_list + |> boutique_inventory.cheap + |> iterator.to_list + |> should.equal([ + Item("Black Short Skirt", 29, 8), + Item("Pink Crop Top", 19, 13), + ]) +} + +pub fn cheap_does_not_consume_iterator_test() { + iterator.repeatedly(fn() { + panic as "The iterator should not be consumed by cheap" + }) + |> boutique_inventory.cheap + |> iterator.take(0) + |> iterator.to_list + |> should.equal([]) +} + +pub fn out_of_stock_terst() { + [ + Item("Red Brown Dress", 65, 0), + Item("Black Short Skirt", 29, 8), + Item("Red Short Skirt", 50, 4), + Item("Pink Crop Top", 19, 0), + ] + |> iterator.from_list + |> boutique_inventory.out_of_stock + |> iterator.to_list + |> should.equal([Item("Red Brown Dress", 65, 0), Item("Pink Crop Top", 19, 0)]) +} + +pub fn out_of_stock_does_not_consume_iterator_test() { + iterator.repeatedly(fn() { + panic as "The iterator should not be consumed by out_of_stock" + }) + |> boutique_inventory.out_of_stock + |> iterator.take(0) + |> iterator.to_list + |> should.equal([]) +} + +pub fn total_stock_test() { + [ + Item("Red Brown Dress", 65, 0), + Item("Black Short Skirt", 29, 8), + Item("Red Short Skirt", 50, 4), + Item("Pink Crop Top", 19, 16), + ] + |> iterator.from_list + |> boutique_inventory.total_stock + |> should.equal(28) +}