Skip to content

Instantly share code, notes, and snippets.

@ybur-yug
Created August 24, 2015 16:28
Show Gist options
  • Save ybur-yug/e09b266513e4e2793b81 to your computer and use it in GitHub Desktop.
Save ybur-yug/e09b266513e4e2793b81 to your computer and use it in GitHub Desktop.
"""
Episode 13, this code will get you to ~2:09 in the video
The test will run, you won't get a compile error, the test WILL FAIL as expected
---
Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
2 tests, 1 failures
"""
defmodule BankAccount do
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## now headed to next part of video STOP VIDEO at 2:35
"""
I always try to anticipate where Josh is headed to see if I can code out in front of the video, that's why you see these lines above
# assert(balance == 0)
I anticipated a very simple test and implemented it below, this code should run and pass:
Finished in 0.1 seconds (0.1s on load, 0.00s on tests)
2 tests, 0 failures
Now I will update it to match Josh's code (except for the deprecated syntax for sending messages)
"""
defmodule BankAccount do
def start do
await
end
def await do
receive do
{:check_balance, pid} -> send pid, {:balance, 0}
end
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## now headed to next part of video STOP VIDEO at 2:55
"""
I updated the code to match the video (with the syntax fix)
bank_account $ mix test
test/bank_account_test.exs:1: warning: redefining module BankAccount
..
Finished in 0.7 seconds (0.7s on load, 0.08s on tests)
2 tests, 0 failures
"""
defmodule BankAccount do
def start do
await
end
def await do
receive do
# {:check_balance, pid} -> send pid, {:balance, 0}
{:check_balance, pid} -> divulge_balance(pid)
end
await # <- recursive call to keep it running for multiple inquiries
end
def divulge_balance(pid) do
# pid <- {:balance, 0} <-- that's the deprecated syntax
send pid, {:balance, 0} # this is what the send function looks like now
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## STOP VIDEO at 6:15
"""
The initial balance test passes again, the deposit test fails as it should
Finished in 0.1 seconds (0.05s on load, 0.1s on tests)
3 tests, 1 failures
"""
defmodule BankAccount do
def start do
await([])
end
def await(events) do
receive do
# {:check_balance, pid} -> send pid, {:balance, 0}
{:check_balance, pid} -> divulge_balance(pid, events)
end
await(events) # <- recursive call to keep it running for multiple inquiries
end
defp divulge_balance(pid, events) do
send pid, {:balance, calculate_balance(events)}
end
defp calculate_balance(events) do
deposits = sum(events)
deposits
end
defp sum(events) do
# Enum.reduce(Events, 0, fn({_, amount}, acc) -> acc + amount end)
Enum.reduce(events, 0, fn({_, amount}, acc) -> acc + amount end) # Events vs events typo
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
test "balance is incremented by the amount deposited" do
account = spawn_link(BankAccount, :start, [])
# account <- {:deposit, 10} <- deprecated
send account, {:deposit, 10}
verify_balance_is 10, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## STOP VIDEO at 7:10
"""
This code will synch with the video at 7:10, all tests pass
next section will add a test to handle withdrawals, I wonder if we will
use a guard to prevent overdrawing the account?
"""
defmodule BankAccount do
def start do
await([])
end
def await(events) do
receive do
# {:check_balance, pid} -> send pid, {:balance, 0}
{:check_balance, pid} -> divulge_balance(pid, events)
{:deposit, amount} -> events = deposit(amount, events)
end
await(events) # <- recursive call to keep it running for multiple inquiries
end
defp deposit(amount, events) do
# return events with a new deposit
events ++ [{:deposit, amount}]
end
defp divulge_balance(pid, events) do
send pid, {:balance, calculate_balance(events)}
end
defp calculate_balance(events) do
deposits = sum(events)
deposits
end
defp sum(events) do
# Enum.reduce(Events, 0, fn({_, amount}, acc) -> acc + amount end)
Enum.reduce(events, 0, fn({_, amount}, acc) -> acc + amount end) # Events vs events typo
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
test "balance is incremented by the amount deposited" do
account = spawn_link(BankAccount, :start, [])
# account <- {:deposit, 10} <- deprecated
send account, {:deposit, 10}
verify_balance_is 10, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## STOP VIDEO at ~8:05
"""
Okay, I overshot. I guessed ahead and made an implementation that passed the tests. I added this code:
def await(events) do
receive do
{:check_balance, pid} -> divulge_balance(pid, events)
{:deposit, amount} -> events = deposit(amount, events)
{:withdraw, amount} -> events = withdraw(amount, events) # <-- new line
end
defp withdraw(amount, events) do
events ++ [{:withdraw, amount * -1}]
end
But now I want to see how Josh is going to do it, so I am glad that I saw a way to make it work
but now I will overwrite my approach to match his example.
"""
defmodule BankAccount do
def start do
await([])
end
def await(events) do
receive do
# {:check_balance, pid} -> send pid, {:balance, 0}
{:check_balance, pid} -> divulge_balance(pid, events)
{:deposit, amount} -> events = deposit(amount, events)
{:withdraw, amount} -> events = withdraw(amount, events)
end
await(events) # <- recursive call to keep it running for multiple inquiries
end
defp deposit(amount, events) do
# return events with a new deposit
events ++ [{:deposit, amount}]
end
defp withdraw(amount, events) do
amount = amount * -1
events ++ [{:withdraw, amount}]
end
defp divulge_balance(pid, events) do
send pid, {:balance, calculate_balance(events)}
end
defp calculate_balance(events) do
deposits = sum(events)
deposits
end
defp sum(events) do
# Enum.reduce(Events, 0, fn({_, amount}, acc) -> acc + amount end)
Enum.reduce(events, 0, fn({_, amount}, acc) -> acc + amount end) # Events vs events typo
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
test "balance is incremented by the amount deposited" do
account = spawn_link(BankAccount, :start, [])
# account <- {:deposit, 10} <- deprecated
send account, {:deposit, 10}
verify_balance_is 10, account
end
test "balance is decremented by the amount of a withdrawal" do
account = spawn_link(BankAccount, :start, [])
send account, {:deposit, 20}
send account, {:withdraw, 10}
verify_balance_is 10, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
########################## STOP VIDEO at ~9:50
"""
Josh's code doesn't pass the tests here, but this code does because the withdraw, :withdrawal terminology
is consistent throughout, not an issue.
"""
defmodule BankAccount do
def start do
await([])
end
def await(events) do
receive do
{:check_balance, pid} -> divulge_balance(pid, events)
{:deposit, amount} -> events = deposit(amount, events)
{:withdrawal, amount} -> events = withdraw(amount, events)
end
await(events) # <- recursive call to keep it running for multiple inquiries
end
defp deposit(amount, events) do
# return events with a new deposit
events ++ [{:deposit, amount}]
end
defp withdraw(amount, events) do
# events ++ [{:withdraw, amount * -1}]
events ++ [{:withdrawal, amount}]
end
defp divulge_balance(pid, events) do
send pid, {:balance, calculate_balance(events)}
end
defp calculate_balance(events) do
deposits = sum(just_deposits(events))
withdrawals = sum(just_withrawals(events))
deposits - withdrawals
end
defp just_deposits(events) do
just_type(events, :deposit)
end
defp just_withrawals(events) do
just_type(events, :withdrawal)
end
defp just_type(events, expected_type) do
Enum.filter(events, fn({type, _}) -> type == expected_type end)
end
defp sum(events) do
# Enum.reduce(Events, 0, fn({_, amount}, acc) -> acc + amount end)
Enum.reduce(events, 0, fn({_, amount}, acc) -> acc + amount end) # Events vs events typo
end
end
defmodule BankAccountTest do
use ExUnit.Case
test "the truth" do
assert(true)
end
test "starting balance is 0" do
# balance = 0
# assert(balance == 0)
account = spawn_link(BankAccount, :start, [])
verify_balance_is 0, account
end
test "balance is incremented by the amount deposited" do
account = spawn_link(BankAccount, :start, [])
# account <- {:deposit, 10} <- deprecated
send account, {:deposit, 10}
verify_balance_is 10, account
end
test "balance is decremented by the amount of a withdrawal" do
account = spawn_link(BankAccount, :start, [])
send account, {:deposit, 20}
send account, {:withdrawal, 10}
verify_balance_is 10, account
end
def verify_balance_is(expected_balance, account) do
send account, {:check_balance, self}
assert_receive {:balance, ^expected_balance} # the ^ is required when passing a variable to a function rather than a value
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment