Solves for building a Vending Machine based on this problem statement
Please refer to the cli_flow_diagrams for Key workflows involving the Vending Machine usage including
- Happy path to purchase an item
- Load(new item) & Reload(existing item & coins) functionality
- Initial Partial payment and being prompted to pay more to complete transaction
- Auto cancel payment & issue refund when machine has insufficient balance to render change to complete purchase
┌─────────────────┐
│ CLI Layer │ (User Interface)
│ bin/ & lib/cli/│
└────────┬────────┘
│
┌────────▼────────┐
│ Business Logic │ (Core Domain)
│ lib/ │
└────────┬────────┘
│
┌────────▼────────┐
│ Data Layer │ (State Management)
│ Items, Balance │
└─────────────────┘
Core Components:
-
VendingMachine: Main orchestrator, delegates to specialized components
-
PurchaseSessionOrchestrator: CLI-specific coordinator that manages the interactive payment collection loop, handling user input and payment parsing until purchase completion
-
PaymentProcessor: Handles all payment transactions and change calculation
-
SessionManager: Manages multi-step purchase sessions
-
ChangeReloader: Handles change reloading
-
ItemLoader: Handles adding a new item & reloading existing items
-
Validators: Dedicated classes for each validation concern
- PaymentValidator: Validates denominations and amounts
- ReloadValidator: Validates reload operations
- ChangeValidator: Ensures change can be made
-
Formatters: Consistent formatting across the application
- CurrencyFormatter: Euro formatting
CLI-Specific Components:
-
PurchaseExecutor: Orchestrates the item selection phase of a CLI purchase
-
ItemSelector: Handles item selection by number with validation and display
-
UserInputHandler: Captures and sanitizes user keyboard input
-
VendingMachineDisplay: Renders all UI output (menus, status, messages)
-
PaymentInputParser: Parses string input like "{100 => 2}" into payment hashes
-
MenuRouter: Routes menu choices to appropriate actions
-
ItemLoadHandler: Handles CLI flow for loading items interactively
-
ChangeReloadHandler: Handles CLI flow for reloading change interactively
The session-based implementation provides a realistic vending machine experience:
1. START SESSION
↓
2. ACCUMULATE PAYMENTS (multiple insertions allowed)
↓
3. VALIDATE CHANGE AVAILABILITY
↓
4. COMPLETE or AUTO-CANCEL WITH REFUND- Default currency: Euro (€)
- Check machine status(of remaining items & balance) at anytime
- Check machine balance at any point in time
- Supports session-based purchase flow
- Add reload functionality for
- Existing and New Items
- To Add change
- Coin denominations supported: 1, 2, 5, 10, 20, 50 cents, €1, €2 coin
- Displays available change and coin breakdown in plain English
- O(1) Item Lookup using Hashes instead of using Array based Linear Search to find each matching item
- A user can purchase only one item at a time through the Vending Machine
- Ruby version 3.3.4
- From the project Root directory
ruby bin/vending_machine_cli.rb- 1. Display available items
- Shows all items with prices and quantities available
- 2. Purchase item with session
- Select item by number
- Enter payment as a hash, e.g.
{100 => 2, 50 => 1}for €2.50 - You can insert more coins until the price is met
- Type
cancelto cancel the session
- 3. Display current balance
- Shows available change in the machine with coin breakdown
- 4. Display machine status
- Shows complete machine status including balance and inventory
- 5. Reload or add new items
- Add quantity to existing items or add new items with prices
- 6. Reload change
- Add coins to the machine's balance
- q. Quit (also accepts
quitorexit)
{100 => 2, 50 => 1}means 2 €1 coins and 1 50-cent coin (total: €2.50)- Valid denominations: 1, 2, 5, 10, 20, 50, 100, 200 (all in cents)
The machine starts with the following coins:
{
50 => 6,
10 => 10,
20 => 10,
100 => 2,
200 => 1,
5 => 10,
2 => 10,
1 => 2
}
{ name: 'Coke', price: 150, quantity: 5 },
{ name: 'Chips', price: 100, quantity: 3 },
{ name: 'Candy', price: 75, quantity: 8 },
{ name: 'Water', price: 125, quantity: 2 }
- All currency is displayed as Euro (€) with two decimals (e.g.,
€1.50) - Only the session-based purchase flow is supported
- Coin breakdown is always shown in plain English
- Refactor specs further
- Refactor existing validation logic across different places/classes to remove duplication where applicable & feasible
- Current end to end specs have room for improvement to go through the complete session flow
- UI flow can be further improved to auto cancel
- Add a more cleaner ability to abort adding a new item(right now we have to give some invalid values while inserting a new item for the menu to reset)
- If there is no quantity available to purchase an item, it should not display it in the list of available items to purchase
- Add the ability to purchase multiple quantities of an item at a time