Skip to content

Commit

Permalink
[gleam] complete boutique-inventory
Browse files Browse the repository at this point in the history
  • Loading branch information
joaofnds committed Apr 25, 2024
1 parent 6737e3f commit e3eefa5
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 0 deletions.
4 changes: 4 additions & 0 deletions gleam/boutique-inventory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.beam
*.ez
build
erl_crash.dump
32 changes: 32 additions & 0 deletions gleam/boutique-inventory/HELP.md
Original file line number Diff line number Diff line change
@@ -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.
21 changes: 21 additions & 0 deletions gleam/boutique-inventory/HINTS.md
Original file line number Diff line number Diff line change
@@ -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
143 changes: 143 additions & 0 deletions gleam/boutique-inventory/README.md
Original file line number Diff line number Diff line change
@@ -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
12 changes: 12 additions & 0 deletions gleam/boutique-inventory/gleam.toml
Original file line number Diff line number Diff line change
@@ -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"
27 changes: 27 additions & 0 deletions gleam/boutique-inventory/manifest.toml
Original file line number Diff line number Diff line change
@@ -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" }
21 changes: 21 additions & 0 deletions gleam/boutique-inventory/src/boutique_inventory.gleam
Original file line number Diff line number Diff line change
@@ -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 })
}
91 changes: 91 additions & 0 deletions gleam/boutique-inventory/test/boutique_inventory_test.gleam
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit e3eefa5

Please sign in to comment.