Created
August 24, 2015 16:28
-
-
Save ybur-yug/e09b266513e4e2793b81 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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