diff --git a/.gitignore b/.gitignore
index 496ee2c..af56f61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-.DS_Store
\ No newline at end of file
+.DS_Store
+.idea/
diff --git a/assignments/assignment01.rb b/assignments/assignment01.rb
index cf3a605..15f198a 100644
--- a/assignments/assignment01.rb
+++ b/assignments/assignment01.rb
@@ -37,13 +37,11 @@ def number_to_string(n, lang)
# it accepts a string
# and returns the same string with each word capitalized.
+# assumes titleize does not need to preserve non-word characters in the original string, i.e.,
+# titleize "hEllo, WORLD" => "Hello World"
def titleize(s)
- words = s.split
- caps = []
- words.each do |word|
- caps << word.capitalize
- end
- caps.join " "
+ word_array = s.split(/\W+/)
+ (word_array.map { |w| w.capitalize }).join(" ")
end
# Your method should generate the following results:
@@ -58,14 +56,16 @@ def titleize(s)
# Write your own implementation of `reverse` called `my_reverse`
# You may *not* use the built-in `reverse` method
def my_reverse(s)
- output = ""
- letters = s.split ""
- n = letters.length
- while n > 0
- n -= 1
- output << letters[n]
+ reversed_array = []
+
+ string_array = s.split("")
+ while not string_array.empty? do
+ # take a character from the end of the original string and
+ # add it to the beginning of the reversed string
+ reversed_array.push string_array.pop
end
- output
+
+ reversed_array.join("")
end
# Your method should generate the following results:
@@ -80,8 +80,9 @@ def my_reverse(s)
# Write a method `palindrome?`
# that determines whether a string is a palindrome
def palindrome?(s)
- stripped = s.delete(" ").delete(",").downcase
- stripped == stripped.reverse
+ # remove all non-word characters, lowercase the string
+ canonical_string = s.gsub(/\W+/, '').downcase
+ canonical_string == canonical_string.reverse
end
# Your method should generate the following results:
diff --git a/assignments/assignment02-statement.html b/assignments/assignment02-statement.html
new file mode 100644
index 0000000..c1c7dde
--- /dev/null
+++ b/assignments/assignment02-statement.html
@@ -0,0 +1,537 @@
+
+
+
+
+
+ Monthly Bank Statement
+
+
+
+
Withdrawals
+
+
+
Date
+
Payee
+
Amount
+
+
+
+
12/01/2014
+
Walgreens
+
$21.92
+
+
+
+
12/04/2014
+
Subway
+
$7.80
+
+
+
+
12/04/2014
+
Starbucks
+
$5.30
+
+
+
+
12/05/2014
+
Nike Town
+
$85.00
+
+
+
+
12/05/2014
+
ATM
+
$60.00
+
+
+
+
12/06/2014
+
Starbucks
+
$5.30
+
+
+
+
12/07/2014
+
Safeway
+
$23.89
+
+
+
+
12/07/2014
+
Arco
+
$42.00
+
+
+
+
12/07/2014
+
check #5132
+
$75.00
+
+
+
+
12/08/2014
+
Starbucks
+
$5.30
+
+
+
+
12/09/2014
+
Bartell's
+
$7.83
+
+
+
+
12/09/2014
+
check #5128
+
$575.00
+
+
+
+
12/11/2014
+
Safeway
+
$42.15
+
+
+
+
12/11/2014
+
Home Depot
+
$17.89
+
+
+
+
12/12/2014
+
ATM
+
$60.00
+
+
+
+
12/13/2014
+
check #5134
+
$45.68
+
+
+
+
12/13/2014
+
check #5126
+
$25.00
+
+
+
+
12/13/2014
+
QFC
+
$13.25
+
+
+
+
12/14/2014
+
Office Depot
+
$24.85
+
+
+
+
12/14/2014
+
Chipotle
+
$10.42
+
+
+
+
12/14/2014
+
check #5133
+
$17.50
+
+
+
+
12/15/2014
+
Starbucks
+
$5.30
+
+
+
+
12/15/2014
+
ATM
+
$60.00
+
+
+
+
12/16/2014
+
7-Eleven
+
$5.26
+
+
+
+
12/16/2014
+
check #5127
+
$50.00
+
+
+
+
12/16/2014
+
Arco
+
$48.01
+
+
+
+
12/17/2014
+
Apple
+
$110.62
+
+
+
+
12/18/2014
+
Starbucks
+
$5.30
+
+
+
+
12/18/2014
+
Bartell's
+
$14.82
+
+
+
+
12/18/2014
+
Starbucks
+
$5.30
+
+
+
+
12/18/2014
+
check #5129
+
$125.00
+
+
+
+
12/19/2014
+
Chipotle
+
$10.42
+
+
+
+
12/22/2014
+
check #5130
+
$120.00
+
+
+
+
12/22/2014
+
Shell
+
$52.00
+
+
+
+
12/22/2014
+
Safeway
+
$28.45
+
+
+
+
12/22/2014
+
QFC
+
$48.13
+
+
+
+
12/23/2014
+
Starbucks
+
$5.30
+
+
+
+
12/26/2014
+
check #5135
+
$62.50
+
+
+
+
12/27/2014
+
Starbucks
+
$5.30
+
+
+
+
12/27/2014
+
Walgreens
+
$14.56
+
+
+
+
12/28/2014
+
check #5136
+
$62.50
+
+
+
+
12/29/2014
+
Starbucks
+
$5.30
+
+
+
+
12/30/2014
+
ATM
+
$100.00
+
+
+
+
12/30/2014
+
Safeway
+
$35.17
+
+
+
+
12/31/2014
+
Starbucks
+
$8.45
+
+
+
+
12/31/2014
+
check #5131
+
$20.00
+
+
+
+
+
+
Deposits
+
+
+
Date
+
Payee
+
Amount
+
+
+
+
12/04/2014
+
Univ Washington
+
$1500.00
+
+
+
+
12/06/2014
+
ATM
+
$50.00
+
+
+
+
12/06/2014
+
ATM
+
$500.00
+
+
+
+
12/15/2014
+
ATM
+
$50.00
+
+
+
+
12/17/2014
+
Univ Washington
+
$1500.00
+
+
+
+
12/21/2014
+
ATM
+
$20.00
+
+
+
+
+
+
Daily Balance
+
+
+
Date
+
Amount
+
+
+
+
12/01/2014
+
$-21.92
+
+
+
+
12/02/2014
+
$-21.92
+
+
+
+
12/03/2014
+
$-21.92
+
+
+
+
12/04/2014
+
$1464.98
+
+
+
+
12/05/2014
+
$1319.98
+
+
+
+
12/06/2014
+
$1864.68
+
+
+
+
12/07/2014
+
$1723.79
+
+
+
+
12/08/2014
+
$1718.49
+
+
+
+
12/09/2014
+
$1135.66
+
+
+
+
12/10/2014
+
$1135.66
+
+
+
+
12/11/2014
+
$1075.62
+
+
+
+
12/12/2014
+
$1015.62
+
+
+
+
12/13/2014
+
$931.69
+
+
+
+
12/14/2014
+
$878.92
+
+
+
+
12/15/2014
+
$863.62
+
+
+
+
12/16/2014
+
$760.35
+
+
+
+
12/17/2014
+
$2149.73
+
+
+
+
12/18/2014
+
$1999.31
+
+
+
+
12/19/2014
+
$1988.89
+
+
+
+
12/20/2014
+
$1988.89
+
+
+
+
12/21/2014
+
$2008.89
+
+
+
+
12/22/2014
+
$1760.31
+
+
+
+
12/23/2014
+
$1755.01
+
+
+
+
12/24/2014
+
$1755.01
+
+
+
+
12/25/2014
+
$1755.01
+
+
+
+
12/26/2014
+
$1692.51
+
+
+
+
12/27/2014
+
$1672.65
+
+
+
+
12/28/2014
+
$1610.15
+
+
+
+
12/29/2014
+
$1604.85
+
+
+
+
12/30/2014
+
$1469.68
+
+
+
+
12/31/2014
+
$1441.23
+
+
+
+
+
+
Summary
+
+
+
+
Starting balance
+
$0.00
+
+
+
+
Total deposits
+
$3620.00
+
+
+
+
Total withdrawals
+
$2178.77
+
+
+
+
Ending balance
+
$1441.23
+
+
+
+
+
+
+
+
diff --git a/assignments/assignment02.rb b/assignments/assignment02.rb
index 532f55c..7e68236 100644
--- a/assignments/assignment02.rb
+++ b/assignments/assignment02.rb
@@ -2,6 +2,9 @@
# Assignment 2
# ========================================================================================
+require 'bigdecimal'
+require 'date'
+
# ========================================================================================
# Problem 1 - `to_sentence`
@@ -10,14 +13,10 @@
# creates an english string from array
def to_sentence(ary)
- if ary.length == 0
- []
- elsif ary.length == 1
- ary[0]
- else
- last = ary.pop
- "#{ary.join(", ")} and #{last}"
- end
+ # your implementation here
+ return ary.join("") if ary.length < 2
+ last_element = ary.pop
+ "#{ary.join(", ")} and #{last_element}"
end
# Your method should generate the following results:
@@ -32,20 +31,21 @@ def to_sentence(ary)
# implement methods "mean", "median" on Array of numbers
def mean(ary)
- sum = ary.reduce(0) {|x, acc| acc + x}
- sum.to_f / ary.length
+ # your implementation here
+ ary.reduce(:+) / ary.length
end
def median(ary)
- sorted_ary = ary.sort
- len = sorted_ary.length
- mid_index = len/2
- if len.odd?
+ # your implementation here
+ # the array has to be sorted for the algorithm to work
+ sorted_ary = ary.sort()
+ mid_index = sorted_ary.length/2
+ if sorted_ary.length.odd?
+ # if the number of elements is odd, the median is just the number in the middle
sorted_ary[mid_index]
else
- mid_lo = sorted_ary[mid_index]
- mid_hi = sorted_ary[mid_index+1]
- (mid_lo + mid_hi)/2.0
+ # if the number of elements is even, the median is the average of the two numbers in the middle
+ (sorted_ary[mid_index] + sorted_ary[mid_index + 1])/2.0
end
end
@@ -62,7 +62,8 @@ def median(ary)
# implement method `pluck` on array of hashes
def pluck(ary, key)
- ary.map {|item| item[key]}
+ # your implementation here
+ ary.map {|m| m[key]}
end
# Your method should generate the following results:
@@ -90,206 +91,169 @@ def pluck(ary, key)
# - daily balance
# - summary:
# - starting balance, total deposits, total withdrawals, ending balance
-def bank_statement
-
- # ------------------------------------------------------------------------
- # formatting helpers:
- def format_currency(amount)
- prefix = if amount < 0
- amount = -amount
- "-"
- end
- s = amount.to_s
- if amount < 10
- cents = "0#{s}"
- dollars = "0"
- elsif amount < 100
- cents = s
- dollars = "0"
- else
- cents = s[-2, 2]
- dollars = s[0, s.length-2]
- if dollars.length > 3
- lower = dollars[-3, 3]
- upper = dollars[0, dollars.length-3]
- dollars = "#{upper},#{lower}"
+STARTING_BALANCE = BigDecimal.new("0")
+
+def generate_html_statement(csv_filename)
+ transactions = read_transactions(csv_filename)
+ withdrawals = transactions.select { |t| t[:type] == :withdrawal }
+ deposits = transactions.select { |t| t[:type] == :deposit }
+ daily_balances = compute_daily_balances(STARTING_BALANCE, transactions)
+ deposits_total = deposits.reduce(0) { |sum, t| sum += t[:amount] }
+ withdrawals_total = withdrawals.reduce(0) { |sum, t| sum += t[:amount] }
+ summary = []
+ summary << {label: "Starting balance", amount: STARTING_BALANCE}
+ summary << {label: "Total deposits", amount: deposits_total}
+ summary << {label: "Total withdrawals", amount: withdrawals_total}
+ summary << {label: "Ending balance", amount: STARTING_BALANCE + deposits_total - withdrawals_total}
+
+ html = render_html("Monthly Bank Statement", withdrawals, deposits, daily_balances, summary)
+
+ File.open("assignment02-statement.html", "w") do |output|
+ output.print html
+ end
+end
+
+# return an array of daily balance records, each record has two keys: :date and :amount.
+def compute_daily_balances(starting_balance, transactions)
+ # create a hash of date => transaction array
+ transactions_by_date = transactions.group_by { |t| t[:date] }
+ # create a hash of date => total amount of transactions for a given day
+ daily_changes = transactions_by_date.reduce(Hash.new(BigDecimal.new("0"))) do |h, (k, v)|
+ h[k] = v.reduce(0) do |total, t|
+ type = t[:type]
+ amount = t[:amount]
+ if type == :deposit
+ total += amount
+ elsif type == :withdrawal
+ total -= amount
end
end
- "$ #{prefix}#{dollars}.#{cents}"
- end
-
- def format_date(date)
- month_string = date[:month] < 10 ? "0#{date[:month]}" : date[:month].to_s
- day_string = date[:day] < 10 ? "0#{date[:day]}" : date[:day].to_s
- "#{month_string}/#{day_string}/#{date[:year]}"
- end
-
- # ------------------------------------------------------------------------
- # rendering:
- def render_html(statement)
- <<-HTML
-
-
- Bank Statement
-
-
- #{render_body statement}
-
- HTML
+ h
end
-
- def render_body(statement)
- <<-BODY
-
-
"}.join "\n"}
+
+ROW
+end
+
+def format_value(value, header)
+ case header
+ when :date
+ value.strftime("%m/%d/%Y")
+ when :amount
+ '$%.2f' % value
+ else
+ value
end
-
- # ------------------------------------------------------------------------
- txs = read_txs
- statement = calc_statement txs
- html = render_html statement
- write_html html
- nil
end
diff --git a/assignments/assignment03-statement.html b/assignments/assignment03-statement.html
new file mode 100644
index 0000000..361b171
--- /dev/null
+++ b/assignments/assignment03-statement.html
@@ -0,0 +1,525 @@
+
+
+
+
+
+ Monthly Bank Statement
+
+
+
Summary
+
+
+
Starting balance
+
$0.00
+
+
+
Total deposits
+
$3620.00
+
+
+
Total withdrawals
+
$2178.77
+
+
+
Ending balance
+
$1441.23
+
+
+
+
Withdrawals
+
+
+
Date
+
Payee
+
Amount
+
+
+
12/01/2014
+
Walgreens
+
$21.92
+
+
+
+
12/04/2014
+
Subway
+
$7.80
+
+
+
+
12/04/2014
+
Starbucks
+
$5.30
+
+
+
+
12/05/2014
+
Nike Town
+
$85.00
+
+
+
+
12/05/2014
+
ATM
+
$60.00
+
+
+
+
12/06/2014
+
Starbucks
+
$5.30
+
+
+
+
12/07/2014
+
Safeway
+
$23.89
+
+
+
+
12/07/2014
+
Arco
+
$42.00
+
+
+
+
12/07/2014
+
check #5132
+
$75.00
+
+
+
+
12/08/2014
+
Starbucks
+
$5.30
+
+
+
+
12/09/2014
+
Bartell's
+
$7.83
+
+
+
+
12/09/2014
+
check #5128
+
$575.00
+
+
+
+
12/11/2014
+
Safeway
+
$42.15
+
+
+
+
12/11/2014
+
Home Depot
+
$17.89
+
+
+
+
12/12/2014
+
ATM
+
$60.00
+
+
+
+
12/13/2014
+
check #5134
+
$45.68
+
+
+
+
12/13/2014
+
check #5126
+
$25.00
+
+
+
+
12/13/2014
+
QFC
+
$13.25
+
+
+
+
12/14/2014
+
Office Depot
+
$24.85
+
+
+
+
12/14/2014
+
Chipotle
+
$10.42
+
+
+
+
12/14/2014
+
check #5133
+
$17.50
+
+
+
+
12/15/2014
+
Starbucks
+
$5.30
+
+
+
+
12/15/2014
+
ATM
+
$60.00
+
+
+
+
12/16/2014
+
7-Eleven
+
$5.26
+
+
+
+
12/16/2014
+
check #5127
+
$50.00
+
+
+
+
12/16/2014
+
Arco
+
$48.01
+
+
+
+
12/17/2014
+
Apple
+
$110.62
+
+
+
+
12/18/2014
+
Starbucks
+
$5.30
+
+
+
+
12/18/2014
+
Bartell's
+
$14.82
+
+
+
+
12/18/2014
+
Starbucks
+
$5.30
+
+
+
+
12/18/2014
+
check #5129
+
$125.00
+
+
+
+
12/19/2014
+
Chipotle
+
$10.42
+
+
+
+
12/22/2014
+
check #5130
+
$120.00
+
+
+
+
12/22/2014
+
Shell
+
$52.00
+
+
+
+
12/22/2014
+
Safeway
+
$28.45
+
+
+
+
12/22/2014
+
QFC
+
$48.13
+
+
+
+
12/23/2014
+
Starbucks
+
$5.30
+
+
+
+
12/26/2014
+
check #5135
+
$62.50
+
+
+
+
12/27/2014
+
Starbucks
+
$5.30
+
+
+
+
12/27/2014
+
Walgreens
+
$14.56
+
+
+
+
12/28/2014
+
check #5136
+
$62.50
+
+
+
+
12/29/2014
+
Starbucks
+
$5.30
+
+
+
+
12/30/2014
+
ATM
+
$100.00
+
+
+
+
12/30/2014
+
Safeway
+
$35.17
+
+
+
+
12/31/2014
+
Starbucks
+
$8.45
+
+
+
+
12/31/2014
+
check #5131
+
$20.00
+
+
+
+
+
Deposits
+
+
+
Date
+
Payee
+
Amount
+
+
+
12/04/2014
+
Univ Washington
+
$1500.00
+
+
+
+
12/06/2014
+
ATM
+
$50.00
+
+
+
+
12/06/2014
+
ATM
+
$500.00
+
+
+
+
12/15/2014
+
ATM
+
$50.00
+
+
+
+
12/17/2014
+
Univ Washington
+
$1500.00
+
+
+
+
12/21/2014
+
ATM
+
$20.00
+
+
+
+
+
Daily Balance
+
+
+
Date
+
Amount
+
+
+
12/01/2014
+
$-21.92
+
+
+
+
12/02/2014
+
$-21.92
+
+
+
+
12/03/2014
+
$-21.92
+
+
+
+
12/04/2014
+
$1464.98
+
+
+
+
12/05/2014
+
$1319.98
+
+
+
+
12/06/2014
+
$1864.68
+
+
+
+
12/07/2014
+
$1723.79
+
+
+
+
12/08/2014
+
$1718.49
+
+
+
+
12/09/2014
+
$1135.66
+
+
+
+
12/10/2014
+
$1135.66
+
+
+
+
12/11/2014
+
$1075.62
+
+
+
+
12/12/2014
+
$1015.62
+
+
+
+
12/13/2014
+
$931.69
+
+
+
+
12/14/2014
+
$878.92
+
+
+
+
12/15/2014
+
$863.62
+
+
+
+
12/16/2014
+
$760.35
+
+
+
+
12/17/2014
+
$2149.73
+
+
+
+
12/18/2014
+
$1999.31
+
+
+
+
12/19/2014
+
$1988.89
+
+
+
+
12/20/2014
+
$1988.89
+
+
+
+
12/21/2014
+
$2008.89
+
+
+
+
12/22/2014
+
$1760.31
+
+
+
+
12/23/2014
+
$1755.01
+
+
+
+
12/24/2014
+
$1755.01
+
+
+
+
12/25/2014
+
$1755.01
+
+
+
+
12/26/2014
+
$1692.51
+
+
+
+
12/27/2014
+
$1672.65
+
+
+
+
12/28/2014
+
$1610.15
+
+
+
+
12/29/2014
+
$1604.85
+
+
+
+
12/30/2014
+
$1469.68
+
+
+
+
12/31/2014
+
$1441.23
+
+
+
+
+
+
+
+
diff --git a/assignments/assignment03.rb b/assignments/assignment03.rb
index ee5cd93..2e65a4e 100644
--- a/assignments/assignment03.rb
+++ b/assignments/assignment03.rb
@@ -2,11 +2,26 @@
# Assignment 3
# ========================================================================================
+require 'bigdecimal'
+require 'date'
+
# ========================================================================================
# Problem 1 - re-implement titleize, palindrome?
# re-implement titleize and palindrome? as methods on String
+class String
+ def titleize
+ word_array = self.split(/\W+/)
+ word_array.map { |w| w.capitalize }.join(" ")
+ end
+
+ def palindrome?
+ canonical_string = self.gsub(/\W+/, '').downcase
+ canonical_string == canonical_string.reverse
+ end
+end
+
"hEllo WORLD".titleize #=> "Hello World"
"gooDbye CRUel wORLD".titleize #=> "Goodbye Cruel World"
@@ -23,6 +38,33 @@
# re-implement mean, median, to_sentence as methods on Array
+class Array
+ def mean
+ self.reduce(:+).to_f / self.length
+ end
+
+ def median
+ # the array has to be sorted for the algorithm to work
+ sorted_ary = self.sort
+ mid_index = sorted_ary.length/2
+ if sorted_ary.length.odd?
+ # if the number of elements is odd, the median is just the number in the middle
+ sorted_ary[mid_index]
+ else
+ # if the number of elements is even, the median is the average of the two numbers in the middle
+ (sorted_ary[mid_index] + sorted_ary[mid_index + 1])/2.0
+ end
+ end
+
+ def to_sentence
+ return self.join("") if self.length < 2
+ # make a copy of the array since pop is destructive
+ array_copy = Array.new(self)
+ last_element = array_copy.pop
+ "#{array_copy.join(", ")} and #{last_element}"
+ end
+end
+
# Your method should generate the following results:
[1, 2, 3].mean #=> 2
[1, 1, 4].mean #=> 2
@@ -47,4 +89,281 @@
# - DepositTransaction
# - WithdrawalTransaction
+class BankAccount
+ attr_reader :transactions
+
+ def initialize(csv_filename)
+ @transactions = []
+
+ File.open(csv_filename, "r") do |f|
+ keys_array = nil
+
+ f.each_with_index do |line, line_num|
+ values = line.chomp().split(",")
+
+ if line_num == 0
+ keys_array = values.map { |value| value.to_sym }
+ else
+ # create a map as a record for each transaction
+ fields = {}
+
+ # convert string values to Ruby types as appropriate
+ values.each_with_index do |value, i|
+ key = keys_array[i]
+ case key
+ when :date
+ value = Date.strptime(value, "%m/%d/%Y")
+ when :amount
+ # use BigDecimal to represent currency values
+ value = BigDecimal.new(value)
+ when :type
+ value = value.to_sym
+ end
+ fields[key] = value
+ end
+
+ @transactions << Transaction.create(fields)
+ end
+ end
+ end
+
+ # return a sorted list of transactions by date
+ @transactions.sort! { |t1, t2| t1.date <=> t2.date }
+ end
+
+ def starting_balance
+ BigDecimal("0")
+ end
+
+ def ending_balance
+ starting_balance + total_deposits - total_withdrawals
+ end
+
+ def total_withdrawals
+ withdrawals.reduce(BigDecimal("0")) { |sum, t| sum += t.amount }
+ end
+
+ def total_deposits
+ deposits.reduce(BigDecimal("0")) { |sum, t| sum += t.amount }
+ end
+
+ def withdrawals
+ @transactions.select { |t| t.class == WithdrawalTransaction }
+ end
+
+ def deposits
+ @transactions.select { |t| t.class == DepositTransaction }
+ end
+
+ # return an array of daily balance records, each record has two keys: :date and :amount.
+ def daily_balances
+ # create a hash of date => transaction array
+ transactions_by_date = @transactions.group_by { |t| t.date }
+ # create a hash of date => total amount of transactions for a given day
+ daily_changes = transactions_by_date.reduce(Hash.new(BigDecimal.new("0"))) do |h, (k, v)|
+ h[k] = v.reduce(0) do |total, t|
+ total += t.signed_amount
+ end
+ h
+ end
+ daily_balances = {}
+ current_balance = starting_balance
+ (transactions_by_date.keys.min..transactions_by_date.keys.max).each do |d|
+ current_balance += daily_changes[d]
+ daily_balances[d] = current_balance
+ end
+ daily_balances.reduce([]) do |ary, (k, v)|
+ ary << {date: k, amount: v}
+ end
+ end
+end
+
+class Transaction
+ attr_reader :date, :payee, :amount
+
+ # factory method for creating a transaction from a hash
+ def self.create(fields)
+ date = fields[:date]
+ payee = fields[:payee]
+ amount = fields[:amount]
+ type = fields[:type]
+ if type == :deposit
+ DepositTransaction.new(date, payee, amount)
+ elsif type == :withdrawal
+ WithdrawalTransaction.new(date, payee, amount)
+ end
+ end
+
+ def initialize(date, payee, amount)
+ @date = date
+ @payee = payee
+ @amount = amount.abs
+ end
+
+ def signed_amount
+ @amount
+ end
+end
+
+class DepositTransaction < Transaction
+ def initialize(date, payee, amount)
+ super(date, payee, amount)
+ end
+end
+
+class WithdrawalTransaction < Transaction
+ def initialize(date, payee, amount)
+ super(date, payee, amount)
+ end
+
+ def signed_amount
+ -@amount
+ end
+end
+
# use blocks for your HTML rendering code
+
+def generate_html_statement(csv_filename)
+ account = BankAccount.new(csv_filename)
+
+ # invoke the render functions in a DSL-style-like structure
+
+ html = render_html("Monthly Bank Statement", account) do |title, account|
+ render_head(title) +
+ render_body(account) do |account|
+ render_section("Summary", account) do |account|
+ render_summary_table(account)
+ end +
+ render_section("Withdrawals", account.withdrawals) do |transactions|
+ render_transaction_table(transactions) do |transaction|
+ render_transaction_row(transaction)
+ end
+ end +
+ render_section("Deposits", account.deposits) do |transactions|
+ render_transaction_table(transactions) do |transaction|
+ render_transaction_row(transaction)
+ end
+ end +
+ render_section("Daily Balance", account.daily_balances) do |daily_balances|
+ render_daily_balance_table(daily_balances) do |balances|
+ render_daily_balance_row(balances)
+ end
+ end
+ end
+ end
+
+ # output the html
+
+ File.open("assignment03-statement.html", "w") do |output|
+ output.print html
+ end
+end
+
+def render_html(title, account, &block)
+<
+
+#{block.call(title, account)}
+
+HTML
+end
+
+def render_head(title)
+<
+
+
+ #{title}
+
+HEAD
+end
+
+def render_body(account, &block)
+<
+#{block.call(account)}
+
+BODY
+end
+
+def render_section(title, section_params, &block)
+<#{title}
+#{block.call(section_params)}
+SECTION
+end
+
+def render_transaction_table(transactions, &block)
+<