Exercise 10 of 10 · A complete program
The Bike Rental Receipt
What you will make
A printed bike-rental receipt with a header, three rental rows in straight columns, a subtotal, a weekend surcharge the program works out itself, a total, and a couple of closing notes.
The one new idea: Assembling a complete program out of parts you already know
Nothing in this program introduces a new idea — that's deliberate. Real programs are almost never one clever trick; they're a handful of familiar pieces, stacked in the order the work happens. Once you can look at a finished program and name every piece, you can read someone else's code and keep building your own.
Go straight to the code ↓Nothing new, all at once
Every exercise so far handed you one new idea and somewhere small to try it. This one hands you no new idea at all — every line in the editor is something you've already met, arranged in the order a receipt actually gets built: values, then arithmetic on them, then the lines that print the result.
puts shows each line. Variables hold the parts that change: name, hours, rate. Arithmetic turns them into amounts: hours * rate for one row, subtotal / 10 for a tenth of the bill. An if decides whether the weekend fee applies at all. ljust and rjust are what keep the columns straight instead of drifting. An array and each print the closing notes without a separate puts for each one. And a running total collects the rental cost as it goes, exactly as it collected a week of rainfall a few exercises back.
A worked example
A laundromat ticket rather than a bike shop, so the receipt in the editor stays yours to finish:
total = 0
name = "Wash"
loads = 2
rate = 40
cost = loads * rate
total = total + cost
puts "#{name.ljust(8)}#{cost.to_s.rjust(5)}"
name = "Dry"
loads = 1
rate = 30
cost = loads * rate
total = total + cost
puts "#{name.ljust(8)}#{cost.to_s.rjust(5)}"
puts "-------------"
puts "TOTAL#{total.to_s.rjust(8)}"Wash 80
Dry 30
-------------
TOTAL 110Two blocks of the same six lines with different values in them, and a total nobody typed in. Change the 2 to a 3 and both the wash row and the total move with it, because both are worked out rather than written down.
Your turn
Press Run before changing anything. Most of the receipt already works correctly: the header, the first two rental rows, the weekend fee, the closing notes. Two lines are marked, and both of them already run — they're wrong, not missing.
- The kids' bike row still prints its four values with plain spaces between them, so the numbers land nowhere near the columns above them. Rewrite it the way the two rows above it are written, with the same
ljustandrjustcalls and the same widths. totalis set to0, so the bottom of the receipt disagrees with the rest of it. Work it out from the two values the program already has: the amount for the rentals, and the weekend fee.
If something goes wrong
The likeliest slip is the total showing 0, or a number that doesn't match the two lines above it — check that both names on the right of the = are spelled exactly as they're spelled further up the program.
If the kids' bike row prints #{name.ljust(12)} back at you word for word, an interpolation is missing its #. If it prints but sits out of line, count the widths against the two rows above rather than guessing — one number different is all it takes.
Write your code
Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.
Press Esc then Tab to move keyboard focus out of the code editor.
Output will appear here after you run your code.The runtime is starting in the background. You can type now — it will be ready before you are.
The answer appears here once you have run your code at least once.
Things that often go wrong here
- Typing the final total in by hand
- The number is correct this minute and wrong the moment anything changes. Rent the kids' bike for two hours instead of one and the row, the subtotal, and the surcharge all update themselves, while a typed-in total sits underneath contradicting them.
- Forgetting .to_s before rjust on the kids' bike row
- hours.rjust(3) raises NoMethodError: undefined method 'rjust' for an Integer — rjust and ljust only exist on strings, so a number has to be turned into one first with .to_s.
- Giving the kids' bike row different widths from the rows above it
- The rows line up only because every one of them gives the name twelve characters, the hours three, the rate five, and the cost six. Change one of those numbers on a single row and only that row drifts out of column while the others stay put.
- Writing total = cost + surcharge
- cost holds the price of the last bike rented only, since each block overwrites it with its own figure — so the receipt would total 22 instead of 133. The variable that has been collecting every rental is subtotal.
Want a blank editor instead? Open the Ruby playground.