Tracks
/
Ruby
Ruby
/
Exercises
/
Boutique Inventory
Boutique Inventory

Boutique Inventory

Learning Exercise

Introduction

More enumeration methods

In Bird Count, you were introduced to the count, any?, select, all? and map enumeration methods. Here's a recap of those, with a few extras added:

fibonacci = [0, 1, 1, 2, 3, 5, 8, 13]

fibonacci.count  { |number| number == 1 }   #=> 2
fibonacci.any?   { |number| number > 20 }   #=> false
fibonacci.none?  { |number| number > 20 }   #=> true
fibonacci.select { |number| number.odd? }   #=> [1, 1, 3, 5, 13]
fibonacci.all?   { |number| number < 20 }   #=> true
fibonacci.map    { |number| number * 2  }   #=> [0, 2, 2, 4, 6, 10, 16, 26]
fibonacci.select { |number| number >= 5}    #=> [5, 8, 13]
fibonacci.find   { |number| number >= 5}    #=> 5

# Some methods work with or without a block
fibonacci.sum  #=> 33
fibonacci.sum {| number | number * number }  #=> 273

# There are also methods to help with nested arrays:
animals = [ ['cat', 'bob'], ['horse', 'caris'], ['mouse', 'arya'] ]
animals.flatten  #=> ["cat", "bob", "horse", "caris", "mouse", "arya"]

Enumerating Hashes

Enumerating Hash objects is exactly the same as enumerating Array objects, except that the block receives two arguments: the key and the value:

pet_names = {cat: "bob", horse: "caris", mouse: "arya"}
pet_names.each { |animal, name| ... }

If you only need one of the values, you can use the special _ symbol to indicate that one value is not needed. This helps both in terms of developer clarity and also is a performance optimisation.

pet_names = {cat: "bob", horse: "caris", mouse: "arya"}
pet_names.map { |_, name| name }  #=> ["bob, "caris", "arya"]

Nested Enumerations

You can also enumerate in nested blocks, and daisy chain methods together. For example, if we have an array of hashes of animals, and we want to extract the animals with short names, we might want to do something like:

pets = [
  { animal: "cats", names: ["bob", "fred", "sandra"] },
  { animal: "horses", names: ["caris", "black beard", "speedy"] },
  { animal: "mice", names: ["arya", "jerry"] }
]

pets.map { |pet|
  pet[:names].select { |name| name.length <= 5 }
}.flatten.sort
#=> ["arya", "bob", "caris", "fred", "jerry"]

Instructions

You run an online fashion boutique. Your big annual sale is coming up, so you want to create some functionality to help you take stock of your inventory to make sure you're ready.

A single item in the inventory is represented by a hash, and the whole inventory is an array of these hashes.

[
  {
    name: "White Shirt",
    price: 40,
    quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}
  },
  { ... }
]

1. Return a list of the names of the items

Implement BoutiqueInventory.item_names, which should return a list of the item names ordered alphabetically.

BoutiqueInventory.new([
  {price: 65.00, name: "Maxi Brown Dress", quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}},
  {price: 50.00, name: "Red Short Skirt", quantity_by_size: {}},
  {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
  {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
]).item_names

#=> ["Bamboo Socks Cats", "Black Short Skirt", "Maxi Brown Dress", "Red Short Skirt"]

2. Return any items that are cheap

Implement BoutiqueInventory.cheap which should return any items that cost less than $30.

BoutiqueInventory.new([
  {price: 65.00, name: "Maxi Brown Dress", quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}},
  {price: 50.00, name: "Red Short Skirt", quantity_by_size: {}},
  {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
  {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
]).cheap

# => [
#      {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
#      {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
#    ]

3. Return any items that are out of stock

Implement BoutiqueInventory.out_of_stock which should return any items that have no stock (where quantity_by_size is empty).

BoutiqueInventory.new([
  {price: 65.00, name: "Maxi Brown Dress", quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}},
  {price: 50.00, name: "Red Short Skirt", quantity_by_size: {}},
  {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
  {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
]).out_of_stock

#=> [{price: 50.00, name: "Red Short Skirt", quantity_by_size: {}}]

4. Return a single item's stock

Implement BoutiqueInventory.stock_for_item(name) to return the stock of an item by its name:

BoutiqueInventory.new([
  {price: 65.00, name: "Maxi Brown Dress", quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}},
  {price: 50.00, name: "Red Short Skirt", quantity_by_size: {}},
  {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
  {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
]).stock_for_item("Black Short Skirt")

#=> {s: 1, xl: 4}

5. Return the total stock

Implement BoutiqueInventory.total_stock to calculate the total amount of items in your storeroom:

BoutiqueInventory.new([
  {price: 65.00, name: "Maxi Brown Dress", quantity_by_size: {s: 3, m: 7, l: 8, xl: 4}},
  {price: 50.00, name: "Red Short Skirt", quantity_by_size: {}},
  {price: 29.99, name: "Black Short Skirt", quantity_by_size: {s: 1, xl: 4}},
  {price: 20.00, name: "Bamboo Socks Cats", quantity_by_size: {s: 7, m: 2}}
]).total_stock

#=> 36
Edit via GitHub The link opens in a new window or tab
Ruby Exercism

Ready to start Boutique Inventory?

Sign up to Exercism to learn and master Ruby with 20 concepts, 120 exercises, and real human mentoring, all for free.