Today, after stressing myself out with thinking I would never be good enough at coding, I put on my big girl pants and got into Encapsulation. Now I hope you understand my tears after just reading that, because damn, was I lost. Encapsulation, however, is not that difficult! When you are encapsulating, you basically get your code into classes or private methods, where other pieces of code cannot just access it. Why would you do that? To prevent bugs when you write larger pieces of codes of course! You would not want to get loads of bugs when you are 1000 lines in, just because you used ‘x’ as a variable again. That being said, never use ‘x’ as a variable, as you want others to understand your code!
So, after cleaning up my tears and drinking a lovely cup of tea, I put together some code that uses Encapsulation. To make Encapsulation a bit easier for yourself, you can start putting together your ‘User stories’ and look at common themes in behaviour from the user stories. ‘User stories’ is the term I will be using to describe what you want from your code. Cohesion refers to the degree to which the elements that you will be using belong together.
The code that I wanted to write was that of a simple vending machine. The vending machine can do a few things that I will explain using user stories:
As a person,
So that I can buy candy,
I want to be able to see how much money I have in the machine.
As a person,
So that I can buy candy,
I want to put money into the machine.
As a person
So that I can buy candy,
I want to see how much candy is left in the machine.
As a person,
So that I can make sure the candy does not run out,
I want to be able to restock the machine.
As a person,
So that I can enjoy candy,
I want to vend candy from the machine.
That makes the whole idea of making a vending machine a LOT less scary, right? This is quite a simple one. I will keep adding new code I learn to this vending machine in future blogs. For now, this will do. Now we know that we have a few objects to look at and the messages that we want to send them:
We want the object ‘Funds’ to tell us about our balance and add money to our balance.
We want an object ‘Stock’ to tell us about our stock and allow us to restock.
We want an object ‘Vending Machine’ to vent candy.
Now, I already wrote the code that does all of this in this git repository: https://github.com/Emmapr123/Vending_Machine. But now I want to rewrite it to be more efficient, using Encapsulation. To do this, I will store every object, as stated above, in their own class, and even in their own file, with their own spec file.
To begin, I want to make my funds more efficient. To do that, I want my file ‘funds’, which stores my class ‘Funds’, to be able to tell me its status and to restock. The default status has to be 0.
require ‘funds’
describe Funds do
let(:candy) { Funds.new }
describe ‘status’ do
it ‘should return the status of the funds’ do
expect(candy.status).to eq “Your balance is 0 pounds”
end
end
describe ‘add_funds’ do
it ‘should add money to the funds’ do
expect(candy.add_funds(5)).to eq 5
end
end
end
Now that I have the specs for it, I can write the funds file.
class Funds
attr_accessor :balance
def initialize
@balance = 0
end
def status
“Your balance is #{balance} pounds”
end
def add_funds(money)
@balance += money
end
end
Still, not too hard, right? Next, I want to do the same for my stock!
require ‘stock’
describe Stock do
let(:candy) { Stock.new }
describe ‘status’ do
it ‘should show there is no more candy’ do
expect(candy.status).to eq “There is no candy left in the machine”
end
it ‘should show how many candy pieces are left’ do
candy.stock = 3
expect(candy.status).to eq “There are 3 pieces of candy left”
end
end
describe ‘restock’ do
it ‘should restock’ do
expect(candy.restock(5)).to eq 5
end
end
end
To make the machine friendly and grammatically correct, I wanted it to return different sentences when asked for their status. You do not have to do that per see.
class Stock
attr_accessor :stock
def initialize
@stock = 0
end
def status
if @stock == 0
“There is no candy left in the machine”
elsif @stock == 1
“There is 1 piece of candy left”
else
“There are #{@stock} pieces of candy left”
end
end
def restock(stock_amount)
@stock += stock_amount
end
end
All of that is still pretty readable, nothing too stressful, right? But how on earth will we put those separate files together and call for them in our vending machine?! That, my dear reader, looks a lot more stressful than it really is. To get our Vending machine to read those files and those classes, we just have to require them! Simple as that, we have done it before, in specs and gems, a walk in the park!
require_relative ‘stock’
require_relative ‘funds’
Now that we have our files put together, we can call these files inside of our code. And thus use them to write some specs. We want to know if we have enough funds and enough stock to vent candy, and if not, we want our user to know that.
require ‘vending_machine’
describe VendingMachine do
let(:candy) { VendingMachine.new ‘candy’, 10}
it ‘has a getter’ do
expect(candy.name).to eq ‘candy’
end
it ‘has a price getter/setter’ do
expect(candy.price).to eq 10
end
describe ‘vend’ do
it ‘does not vendy candy if not enough balance’ do
expect do
candy.balance = 1
candy.stock = 3
candy.vend
end.to output(“insufficient funds”).to_stdout
end
end
describe ‘vend’ do
it ‘vends candy as there is enough balance’ do
expect do
candy.stock = 3
candy.balance = 12
candy.vend
end.to output(“Enjoy your candy, your balance is now 2”).to_stdout
end
end
describe ‘vend’ do
it ‘cannot vend candy if the stock is too low’ do
expect do
candy.stock = 0
candy.vend
end.to output(“insufficient stock”).to_stdout
end
end
end
Now there is not much left for us to do. We just have to write the code for the vending machine, that uses both the ‘Funds’ class and the ‘Stock’ class!
class VendingMachine
attr_accessor :name, :price, :stock, :balance
def initialize(name, price)
@name = name
@price = price
@stock = Stock.new
@balance = Funds.new
end
def vend
if @stock == 0
print “insufficient stock”
elsif
@balance >= @price
@balance -= @price
@stock -= 1
print “Enjoy your #{name}, your balance is now #{balance}”
elsif @balance <= @price
print “insufficient funds”
end
end
end
Voila, those tears were clearly unnecessary. I hope this explains it alright. I would love to hear feedback on it or see how you did it if you try this yourself. Now it is time for a nice hot shower and some Mario cart for the rest of the night.