diff --git a/assignments/asgmt6.rb b/assignments/asgmt6.rb new file mode 100644 index 0000000..e3258e5 --- /dev/null +++ b/assignments/asgmt6.rb @@ -0,0 +1,86 @@ + require 'minitest/autorun' + + class PriorityQueue + + class SubQueue + attr :rank, :items + def initialize(rank) + @rank = rank + @items = [] + end + def enqueue(item) + @items< 0 + @high_sq.dequeue + elsif @medium_sq.length > 0 + @medium_sq.dequeue + else + @low_sq.dequeue + end + end + def empty? + ary = @high_sq.items + @medium_sq.items + @low_sq.items + ary.empty? + end + def peek + if @high_sq.length > 0 + @high_sq.peek + elsif @medium_sq.length > 0 + @medium_sq.peek + else + @low_sq.peek + end + end + def length + ary = @high_sq.items + @medium_sq.items + @low_sq.items + ary.length + end + end #PriorityQueue + + + class TestPriorityQueue < MiniTest::Test + def test_one + pq = PriorityQueue.new + assert pq.empty? + pq.enqueue "first" + refute pq.empty? + + pq.enqueue "top", :high + pq.enqueue "last", :low + pq.enqueue "second" + pq.enqueue "another top", :high + assert_equal 5, pq.length + + assert_equal "top", pq.dequeue + assert_equal "another top", pq.dequeue + assert_equal "first", pq.dequeue + assert_equal "second", pq.dequeue + assert_equal "last", pq.dequeue + end + end #class diff --git a/assignments/asgmt8.rb b/assignments/asgmt8.rb new file mode 100644 index 0000000..2166a95 --- /dev/null +++ b/assignments/asgmt8.rb @@ -0,0 +1,72 @@ + + +module Assignment08 + class RomanNumeral + attr :value, :arabic_digits + def initialize(i) + @value = i + @arabic_digits = [] + [0,1,2].each {|n| @arabic_digits[n] = @value.to_s[(n+1) *-1].to_i} + end + + def to_s + roman_chars = [] + roman_chars << %w{I IV V IX} + roman_chars << %w{X XL L XC} + roman_chars << %w{C CD D CM} + r_numeral = "" + r_digit = "" + @arabic_digits.each_with_index do |arabic_digit, i| + if arabic_digit <= 3 then + r_digit = roman_chars[i][0] * arabic_digit + elsif arabic_digit == 4 then + r_digit = roman_chars[i][1] + elsif arabic_digit <= 8 then + r_digit = roman_chars[i][2] + roman_chars[i][0] * (arabic_digit - 5) + else r_digit = roman_chars[i][3] + end + r_numeral.insert(0, r_digit) + end + r_numeral + end + + def to_i + @value + end + + # bonus: create from Roman Numeral + def self.from_string(rn) + # returns a new instance + rn == 'III' ? @value = 3 : @value = nil #MOREMORE method in process + end + end + +# bonus: +#RomanNumeral.from_string('III').to_i # => 3 +#RomanNumeral.from_string('IX').to_i # => 9 +#RomanNumeral.from_string('IX').to_i # => 9 + +#require Assignment08 + + require 'minitest/autorun' + + class RomanNumeralTest < MiniTest::Test + def test_one + assert_equal 'I', RomanNumeral.new(1).to_s + assert_equal 'II', RomanNumeral.new(2).to_s + assert_equal 'III', RomanNumeral.new(3).to_s + assert_equal 'IV', RomanNumeral.new(4).to_s + assert_equal 'V', RomanNumeral.new(5).to_s + assert_equal 'VI', RomanNumeral.new(6).to_s + assert_equal 'VII', RomanNumeral.new(7).to_s + assert_equal 'IX', RomanNumeral.new(9).to_s + assert_equal 'X', RomanNumeral.new(10).to_s + assert_equal 'XIX', RomanNumeral.new(19).to_s + assert_equal 'XXXII', RomanNumeral.new(32).to_s + assert_equal 'LI', RomanNumeral.new(51).to_s + assert_equal 'C', RomanNumeral.new(100).to_s + assert_equal 'CI', RomanNumeral.new(101).to_s + end + end +end + diff --git a/assignments/assignment01.rb b/assignments/assignment01.rb index cf3a605..26b6c44 100644 --- a/assignments/assignment01.rb +++ b/assignments/assignment01.rb @@ -38,18 +38,17 @@ def number_to_string(n, lang) # it accepts a string # and returns the same string with each word capitalized. def titleize(s) - words = s.split - caps = [] - words.each do |word| - caps << word.capitalize - end - caps.join " " + my_words = s.split(" ") + cap_sentence = "" + my_words.each {|w| cap_sentence << w.capitalize << " "} + cap_sentence.chop + end # Your method should generate the following results: -titleize "hEllo WORLD" #=> "Hello World" +puts titleize "hEllo WORLD" #=> "Hello World" -titleize "gooDbye CRUel wORLD" #=> "Goodbye Cruel World" +puts titleize "gooDbye CRUel wORLD" #=> "Goodbye Cruel World" # ======================================================================================== @@ -58,14 +57,13 @@ 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] + s_array = s.split("") + s_array_reverse = [] + s_array.each { |c| s_array_reverse.insert(0, c) end - output + s_reverse = s_array_reverse.join + + end # Your method should generate the following results: @@ -80,8 +78,15 @@ 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 + s1 = s.sub(' ', '').downcase + s2 = s1.reverse + + if s2 == s1 + true + else + false + end + end # Your method should generate the following results: diff --git a/assignments/assignment02-out.htm b/assignments/assignment02-out.htm new file mode 100644 index 0000000..93c6b4d --- /dev/null +++ b/assignments/assignment02-out.htm @@ -0,0 +1,465 @@ + +

Summary

+

Total withdrawals: $2178.77

+

Total deposits: $3620.0

+

Final Balance: $5798.77

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateEnding Balance
12/1/2014-21.92
12/4/20141486.9
12/5/2014-145.0
12/6/2014544.7
12/7/2014-140.89
12/8/2014-5.3
12/9/2014-582.83
12/11/2014-60.04
12/12/2014-60.0
12/13/2014-83.93
12/14/2014-52.77
12/15/2014-15.299999999999997
12/16/2014-103.27
12/17/20141389.38
12/18/2014-150.42000000000002
12/19/2014-10.42
12/21/201420.0
12/22/2014-248.57999999999998
12/23/2014-5.3
12/26/2014-62.5
12/27/2014-19.86
12/28/2014-62.5
12/29/2014-5.3
12/30/2014-135.17000000000002
12/31/2014-28.45
+

Withdrawals

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DatePayeeAmount
12/1/2014Walgreens$-21.92
12/4/2014Starbucks$-5.3
12/4/2014Subway$-7.8
12/5/2014ATM$-60.0
12/5/2014Nike Town$-85.0
12/6/2014Starbucks$-5.3
12/7/2014Safeway$-23.89
12/7/2014Arco$-42.0
12/7/2014check #5132$-75.0
12/8/2014Starbucks$-5.3
12/9/2014Bartell's$-7.83
12/9/2014check #5128$-575.0
12/11/2014Home Depot$-17.89
12/11/2014Safeway$-42.15
12/12/2014ATM$-60.0
12/13/2014check #5126$-25.0
12/13/2014check #5134$-45.68
12/13/2014QFC$-13.25
12/14/2014Chipotle$-10.42
12/14/2014Office Depot$-24.85
12/14/2014check #5133$-17.5
12/15/2014ATM$-60.0
12/15/2014Starbucks$-5.3
12/16/2014Arco$-48.01
12/16/2014check #5127$-50.0
12/16/20147-Eleven$-5.26
12/17/2014Apple$-110.62
12/18/2014Bartell's$-14.82
12/18/2014check #5129$-125.0
12/18/2014Starbucks$-5.3
12/18/2014Starbucks$-5.3
12/19/2014Chipotle$-10.42
12/22/2014Shell$-52.0
12/22/2014QFC$-48.13
12/22/2014Safeway$-28.45
12/22/2014check #5130$-120.0
12/23/2014Starbucks$-5.3
12/26/2014check #5135$-62.5
12/27/2014Starbucks$-5.3
12/27/2014Walgreens$-14.56
12/28/2014check #5136$-62.5
12/29/2014Starbucks$-5.3
12/30/2014ATM$-100.0
12/30/2014Safeway$-35.17
12/31/2014Starbucks$-8.45
12/31/2014check #5131$-20.0
+ +

Deposits

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DatePayeeAmount
12/4/2014Univ Washington$1500.0
12/6/2014ATM$50.0
12/6/2014ATM$500.0
12/15/2014ATM$50.0
12/17/2014Univ Washington$1500.0
12/21/2014ATM$20.0
+ + diff --git a/assignments/assignment02-out.txt b/assignments/assignment02-out.txt new file mode 100644 index 0000000..2e62100 --- /dev/null +++ b/assignments/assignment02-out.txt @@ -0,0 +1,10 @@ + + + + + + + + +
12/4/2014Univ Washington
12/6/2014ATM
12/15/2014ATM
12/6/2014ATM
12/21/2014ATM
12/17/2014Univ Washington
+ diff --git a/assignments/assignment02.rb b/assignments/assignment02.rb index 532f55c..024033d 100644 --- a/assignments/assignment02.rb +++ b/assignments/assignment02.rb @@ -10,14 +10,11 @@ # 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 + str1 = ary[0...-1].reduce {|item, acc| item.to_s + ", #{acc}"} + a2 = [str1, ary[-1]] + a2.compact! + a2.join " and " end # Your method should generate the following results: @@ -32,20 +29,16 @@ 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 + tot = ary.reduce {|i, acc| i + acc } + avg = tot.to_f/ary.length end def median(ary) - sorted_ary = ary.sort - len = sorted_ary.length - mid_index = len/2 - if len.odd? - sorted_ary[mid_index] + alen = ary.length + if alen % 2 == 1 then + med = ary[alen/2] else - mid_lo = sorted_ary[mid_index] - mid_hi = sorted_ary[mid_index+1] - (mid_lo + mid_hi)/2.0 + mean([ary[alen/2],ary[(alen/2)+1]]) end end @@ -62,6 +55,7 @@ def median(ary) # implement method `pluck` on array of hashes def pluck(ary, key) + ary.map {|item| item[key]} end @@ -73,6 +67,7 @@ def pluck(ary, key) {name: "Ringo", instrument: "drums" } ] pluck records, :name #=> ["John", "Paul", "George", "Ringo"] + pluck records, :instrument #=> ["guitar", "bass", "guitar", "drums"] @@ -90,206 +85,164 @@ 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}" - 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 - end - - def render_body(statement) - <<-BODY - -

Bank Statement

- #{render_summary statement[:summary]} - #{render_txs statement[:withdrawals], "Withdrawals"} - #{render_txs statement[:deposits], "Deposits"} - #{render_daily_balances statement[:dates], statement[:daily_balances]} - - BODY - end - - def render_summary(summary) - <<-SUMMARY -

Summary

- - - - - -
Starting Balance #{format_currency summary[:starting_balance]}
Total Deposits #{format_currency summary[:sum_deposits]}
Total Withdrawals#{format_currency summary[:sum_withdrawals]}
Ending Balance #{format_currency summary[:ending_balance]}
- SUMMARY - end - - def render_tx(tx) - <<-TX - - #{tx[:formatted_date]} - #{tx[:payee]} - #{format_currency tx[:amount]} - - TX - end - - def render_txs(txs, label) - <<-TXS -

#{label}

- - #{txs.map {|tx| render_tx tx}.join "\n"} -
- TXS - end - - def render_daily_balance(date, balance) - <<-TXS - - #{date} - #{format_currency balance[:summary][:ending_balance]} - - TXS - end - - def render_daily_balances(dates, balances) - <<-BALANCES -

Daily Balances

- - #{dates.map {|date| render_daily_balance date, balances[date]}.join "\n"} -
- BALANCES +def create_transaction_hash( date, payee, amount, type ) + { date: date, payee: payee, amount: amount, type: type } +end + +records = [] +transactions = File.open('assignment02-input.csv', "r") do |infile| + records = infile.readlines.map do |inline| + f = inline.chomp.split(",") + create_transaction_hash(f[0], f[1], f[2], f[3]) end - - # ------------------------------------------------------------------------ - # read csv file, generate txs: - def read_txs - File.open("assignment02-input.csv") do |file| - lines = file.readlines - - keys = lines.shift.chomp.split(",").map {|key| key.to_sym} - - lines.map do |line| - tx = {} - line.chomp.split(",").each_with_index do |field, index| - key = keys[index] - tx[key] = field - end - tx - end.map do |tx| - tx[:amount] = (tx[:amount].to_f * 100).to_i - month, day, year = tx[:date].split "/" - date = {year: year.to_i, month: month.to_i, day: day.to_i} - tx[:date] = date - tx[:formatted_date] = format_date date - tx - end.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]} - end +end + +withdrawals = transactions.select {|h| h[:type] == 'withdrawal' } +withdrawals.sort_by! {|x| x[:date]} +deposits = transactions.select {|h| h[:type] == 'deposit' } +deposits.sort_by! {|x| x[:date]} + +def get_totals(records) + amounts = records.map {|r| r[:amount].to_f } + amounts.reduce(0) { |val, acc| val + acc }.round(2) +end + +def mean(ary) + tot = ary.reduce {|i, acc| i + acc } + avg = tot.to_f/ary.length +end + +def get_daily_balance(transactions) + days = transactions.map {|t| t[:date]}.uniq + days.sort_by! {|i| i.split("/")[1].to_i} + transactions_by_day = days.reduce({}) do |acc, day| + acc[day] = transactions.select { |t| t[:date] == day } + acc end - # ------------------------------------------------------------------------ - # calc totals for collection of txs: - def txs_totals(txs, starting_balance) - withdrawals = txs.select {|tx| tx[:type] == "withdrawal"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]} - sum_withdrawals = withdrawals.reduce(0) {|acc, tx| acc += tx[:amount]} - - deposits = txs.select {|tx| tx[:type] == "deposit"}.sort {|a,b| a[:formatted_date] <=> b[:formatted_date]} - sum_deposits = deposits.reduce(0) {|acc, tx| acc += tx[:amount]} - - ending_balance = starting_balance + sum_deposits - sum_withdrawals - - { - summary: { - starting_balance: starting_balance, - sum_deposits: sum_deposits, - sum_withdrawals: sum_withdrawals, - ending_balance: ending_balance - }, - withdrawals: withdrawals, - deposits: deposits - } + sum_transactions_by_day = days.reduce({}) do |acc, day| + amounts = transactions_by_day[day].map {|record| record[:amount]} + sum = amounts.reduce {|acc, amount| acc.to_f + amount.to_f } + acc[day] = sum.to_f + acc end - - # ------------------------------------------------------------------------ - # calc statement from txs: - def calc_statement(txs) - statement = txs_totals txs, 0 - - dates = txs.map {|tx| tx[:formatted_date]}.uniq.sort - - daily_balances = {} - dates.each_with_index do |date, index| - txs_for_date = txs.select {|tx| tx[:formatted_date] == date} - starting_balance = if index == 0 - # first day, so use starting balance: - statement[:summary][:starting_balance] - else - # use ending balance of previous date: - prev_date = dates[index-1] - daily_balances[prev_date][:summary][:ending_balance] - end - daily_balances[date] = txs_totals txs_for_date, starting_balance - end - statement[:dates] = dates - statement[:daily_balances] = daily_balances - statement + bal = 0 + balances_by_day = days.reduce([]) do |acc, day| + h = {} + h[:date] = day + h[:balance] = bal + sum_transactions_by_day[day] + acc << h + acc end - - # ------------------------------------------------------------------------ - # write html to file: - def write_html(html) - File.open("assignment02-output.html", "w") do |file| - file.write html + balances_by_day +end + +#balances = get_daily_balance(nt) + +def get_summable_transactions(transactions) + trans_vals = transactions.reject {|t| t[:date] == "date"} + out_trans = [] + out_trans = trans_vals.map do |t| + if t[:type] == "withdrawal" then + t[:amount] = t[:amount].to_f * -1.0 + else + t[:amount] = t[:amount].to_f end + t end + # puts out_trans +end + +#nt = get_summable_transactions(transactions) +puts nt +get_daily_balance(nt) + +def total_transactions_by_day() - # ------------------------------------------------------------------------ - txs = read_txs - statement = calc_statement txs - html = render_html statement - write_html html - nil + +end + +def render_record(rec) +< + #{rec[:date]} + #{rec[:payee]} + $#{rec[:amount]} + +RECORD +end + +def render_table_header() +<
+ Date + Payee + Amount + +HEADER +end + +def render_header(record) +end + +def render_records(records) +< + #{render_table_header} + #{records.map {|r| render_record(r)}.join "\n"} + +RECORDS +end + +def render_body(title, records) +<#{title} + #{render_records(records)} +BODY +end + +def render_balance_record(record) +< + #{record[:date]} + #{record[:balance]} + +RECORD +end + + +def render_daily_balances(transactions) +nt = get_summable_transactions(transactions) +db = get_daily_balance(nt) +puts db.class +<DateEnding Balance + #{db.map {|rec| render_balance_record(rec)}.join "\n"} + +BALANCES +end + + +def get_ending_balance(beginning_balance, tot_withdrawals, tot_deposits) + beginning_balance.to_f - tot_withdrawals.to_f + tot_deposits.to_f end + +total_deposits = get_totals(deposits) +total_withdrawals = get_totals(withdrawals) + +File.open('assignment02-out.htm', "w") do |outfile| + outfile.puts "" + outfile.puts "

Summary

" + outfile.puts "

Total withdrawals: $#{total_withdrawals}

" + outfile.puts "

Total deposits: $#{total_deposits}

" + outfile.puts "

Final Balance: $#{get_ending_balance(0, total_withdrawals, total_deposits)}

" + outfile.puts render_daily_balances(transactions) + outfile.puts render_body("Withdrawals", withdrawals) + outfile.puts render_body("Deposits", deposits) + outfile.puts "" +end + + + + + diff --git a/assignments/assignment03.rb b/assignments/assignment03.rb index ee5cd93..6b3f583 100644 --- a/assignments/assignment03.rb +++ b/assignments/assignment03.rb @@ -7,6 +7,22 @@ # re-implement titleize and palindrome? as methods on String + class String + def titleize + my_words = self.split(" ") + cap_sentence = "" + my_words.each {|w| cap_sentence << w.capitalize << " "} + cap_sentence.chop + end + + def palindrome? + s1 = self.gsub(' ', '').downcase + s1 = s1.gsub(',', '').downcase + s2 = s1.reverse + s2 == s1 + end + end + "hEllo WORLD".titleize #=> "Hello World" "gooDbye CRUel wORLD".titleize #=> "Goodbye Cruel World" @@ -23,6 +39,32 @@ # re-implement mean, median, to_sentence as methods on Array +class Array + def mean + tot = self.reduce {|i, acc| i + acc } + tot.to_f/self.length + end + + def median + alen = self.length + if alen % 2 == 1 then + med = self[alen/2] + else + mean([self[alen/2],self[(alen/2)+1]]) + end + end + + def to_sentence + str1 = self[0...-1].reduce {|item, acc| item.to_s + ", #{acc}"} + a2 = [str1, self[-1]] + a2.compact! + a2.join " and " + end +end + + + + # Your method should generate the following results: [1, 2, 3].mean #=> 2 [1, 1, 4].mean #=> 2 @@ -48,3 +90,189 @@ # - WithdrawalTransaction # use blocks for your HTML rendering code + +class Transaction + def initialize(date, payee, amount, type) + @date = date + @payee = payee + @amount = amount.to_f + @type = type + end + def date; @date; end + def payee; @payee; end + def amount; @amount; end + def type; @type; end + def puts + if @type == "Deposit" + print "date: #{date}, payee: #{payee}, amount: #{amount} \n" + elsif @type == "Withdrawal" + print "date: #{date}, payee: #{payee}, amount: #{amount} \n" + else print "\n" + end + end +end + +class DepositTransaction < Transaction + def initialize(date, payee, amount) + super date, payee, amount.to_f, "Deposit" + end +end + +class WithdrawalTransaction < Transaction + def initialize(date, payee, amount) + super date, payee, amount.to_f * -1.0, "Withdrawal" + end +end + +class BankAccount < Array + def initialize() + end + def add_transaction(transaction) + self.push transaction + end + def import_transactions(filename) + transactions = File.open(filename, "r") do |infile| + records = infile.readlines.map do |inline| + f = inline.chomp.split(",") + if f[3] == "deposit" then + t = DepositTransaction.new(f[0], f[1], f[2]) + self.add_transaction t + elsif f[3] == "withdrawal" then + t = WithdrawalTransaction.new(f[0], f[1], f[2]) + self.add_transaction t + end + end + end + end +end + +ba = BankAccount.new() +ba.import_transactions('assignment02-input.csv') +ba.each {|t| t.puts} + +withdrawals = ba.select {|h| h.type == 'Withdrawal' } +withdrawals.sort_by! {|x| x.date.split('/')[1].to_i} +deposits = ba.select {|h| h.type == 'Deposit' } +deposits.sort_by! {|x| x.date.split('/')[1].to_i} + +def get_totals(records) + amounts = records.map {|r| r.amount } + amounts.reduce(0) { |val, acc| val + acc }.round(2) +end + +def mean(ary) + tot = ary.reduce {|i, acc| i + acc } + avg = tot.to_f/ary.length +end + +def get_daily_balance(transactions) + days = transactions.map {|t| t.date}.uniq + days.sort_by! {|i| i.split("/")[1].to_i} + transactions_by_day = days.reduce({}) do |acc, day| + acc[day] = transactions.select { |t| t.date == day } + acc + end + sum_transactions_by_day = days.reduce({}) do |acc, day| + amounts = transactions_by_day[day].map {|record| record.amount} + sum = amounts.reduce {|acc, amount| acc.to_f + amount.to_f } + acc[day] = sum.to_f + acc + end + bal = 0 + balances_by_day = days.reduce([]) do |acc, day| + h = {} + h[:date] = day + h[:balance] = bal + sum_transactions_by_day[day] + acc << h + acc + end + balances_by_day +end + +#balances = get_daily_balance(ba) + + + +#nt = get_summable_transactions(transactions) +puts nt +get_daily_balance(nt) + + +def render_record(rec) +< + #{rec.date.to_s} + #{rec.payee} + $#{rec.amount} + +RECORD +end + +def render_table_header() +<
+ Date + Payee + Amount + +HEADER +end + +def render_header(record) +end + +def render_records(records) +< + #{render_table_header} + #{records.map {|r| render_record(r)}.join "\n"} + +RECORDS +end + +def render_body(title, records) +<#{title} + #{render_records(records)} +BODY +end + +def render_balance_record(record) +< + #{record[:date]} + #{record[:balance]} + +RECORD +end + + +def render_daily_balances(transactions) +nt = transactions +db = get_daily_balance(nt) +puts db.class +<DateEnding Balance + #{db.map {|rec| render_balance_record(rec)}.join "\n"} + +BALANCES +end + +def get_ending_balance(beginning_balance, tot_withdrawals, tot_deposits) + beginning_balance.to_f + tot_withdrawals.to_f + tot_deposits.to_f +end + +total_deposits = get_totals(deposits) +total_withdrawals = get_totals(withdrawals) * -1.0 + +File.open('assignment02-out.htm', "w") do |outfile| + outfile.puts "" + outfile.puts "

Summary

" + outfile.puts "

Total withdrawals: $#{total_withdrawals}

" + outfile.puts "

Total deposits: $#{total_deposits}

" + outfile.puts "

Final Balance: $#{get_ending_balance(0, total_withdrawals, total_deposits)}

" + outfile.puts render_daily_balances(ba) + outfile.puts render_body("Withdrawals", withdrawals) + outfile.puts render_body("Deposits", deposits) + outfile.puts "" +end diff --git a/assignments/assignment04.rb b/assignments/assignment04.rb index d2443a2..a165959 100644 --- a/assignments/assignment04.rb +++ b/assignments/assignment04.rb @@ -13,6 +13,13 @@ def fib(n) # your implementation here + if n==0 then + 1 + elsif n==1 then + 1 + else + fib(n-2) + fib(n-1) + end end # expected behavior: @@ -40,22 +47,22 @@ def fib(n) class Queue def initialize - # your implementation here + @items = [] end def enqueue(item) - # your implementation here + @items< prints out "first", "third" class LinkedList + # include Enumerable + + class Node + attr :item, :link + def initialize(item, link) + @item = item + @link = link + end + def item=(something) + @item == something + end + end + def initialize - # your implementation here + @nodes = nil end + def empty? - # your implementation here + @nodes.nil? end + def length - # your implementation here + count = 0 + node = @nodes + while node + count += 1 + node = node.link + end + count end + def <<(item) - # your implementation here + @nodes = Node.new item, @nodes end + def first - # your implementation here + node = @nodes + lastnode = @nodes + while node + lastnode = node + node = node.link + end + lastnode.item end def last - # your implementation here + @nodes.item end + def each(&block) - # your implementation here + node = @nodes + while node + yield node.item + node = node.link + end + end + + def reverse! + in_node = @nodes + out_nodes = nil + while in_node + out_nodes = Node.new in_node.item, out_nodes + in_node = in_node.link + end + @nodes = out_nodes + end + + def delete(myitem) + newnodes = nil + node = @nodes + while node + if node.item == myitem then + node = node.link + else + newnodes = Node.new node.item, newnodes + node = node.link + end + end + @nodes = newnodes + self.reverse! + myitem end end + +ll = LinkedList.new +ll << "first" +ll << "second" +ll << "third" +ll << "fourth" +ll << "fifth" +ll.length +ll.delete "third" +ll.length + +ll.each {|x| puts x } diff --git a/assignments/assignment05.rb b/assignments/assignment05.rb index 9e96ea4..df22cbc 100644 --- a/assignments/assignment05.rb +++ b/assignments/assignment05.rb @@ -5,15 +5,34 @@ # ======================================================================================== # Problem 1 - implement prop_reader, write MiniTest unit tests +class Class + def prop_reader(prop_name) + define_method (prop_name) { instance_variable_get "@#{prop_name}" } + end +end + # expected results: class PropReader - prop_reader :flavor - def initialize(flavor) - @flavor = flavor + prop_reader(:flavor) + def initialize(flavor) + @flavor = flavor + end +end + + + +require 'minitest/autorun' + +class TestPropReader < Minitest::Test + def test_check + pr = PropReader.new("aparameter") + assert_equal "aparameter", pr.flavor + assert pr.respond_to? :flavor + refute pr.respond_to? :"flavor=" end end -obj = PropReader.new "spicy" -obj.respond_to? :flavor #=> true -obj.respond_to? :"flavor=" #=> false -obj.flavor #=> "spicy" +#obj = PropReader.new("spicy" +#obj.respond_to? :flavor #=> true +#obj.respond_to? :"flavor=" #=> false +#obj.flavor #=> "spicy" diff --git a/assignments/assignment06.rb b/assignments/assignment06.rb index 9017e02..48d1104 100644 --- a/assignments/assignment06.rb +++ b/assignments/assignment06.rb @@ -6,47 +6,94 @@ # Problem 1 - PriorityQueue # implement a PriorityQueue, validate using MiniTest unit tests +module Assignment6 + require 'minitest/autorun' + + class PriorityQueue -class PriorityQueue - def initialize - # your implementation here - end - def enqueue(item, priority=:medium) - # your implementation here - end - def dequeue - # your implementation here - end - def empty? - # your implementation here - end - def peek - # your implementation here - end - def length - # your implementation here - end -end - -# expected results: -pq = PriorityQueue.new -pq.empty? #=> true - -pq.enqueue "first" -pq.empty? #=> false - -pq.enqueue "top", :high -pq.enqueue "last", :low -pq.enqueue "second" -pq.enqueue "another top", :high - -pq.length #=> 5 + class SubQueue + attr :rank, :items + def initialize(rank) + @rank = rank + @items = [] + end + def enqueue(item) + @items< 0 + @high_sq.dequeue + elsif @medium_sq.length > 0 + @medium_sq.dequeue + else + @low_sq.dequeue + end + end + def empty? + ary = @high_sq.items + @medium_sq.items + @low_sq.items + ary.empty? + end + def peek + if @high_sq.length > 0 + @high_sq.peek + elsif @medium_sq.length > 0 + @medium_sq.peek + else + @low_sq.peek + end + end + def length + ary = @high_sq.items + @medium_sq.items + @low_sq.items + ary.length + end + end #PriorityQueue -pq.dequeue #=> "top" -pq.dequeue #=> "another top" -pq.dequeue #=> "first" -pq.dequeue #=> "second" -pq.dequeue #=> "last" + + class TestPriorityQueue < MiniTest::Test + def test_one + pq = PriorityQueue.new + assert pq.empty? + pq.enqueue "first" + refute pq.empty? + + pq.enqueue "top", :high + pq.enqueue "last", :low + pq.enqueue "second" + pq.enqueue "another top", :high + assert_equal 5, pq.length + + assert_equal "top", pq.dequeue + assert_equal "another top", pq.dequeue + assert_equal "first", pq.dequeue + assert_equal "second", pq.dequeue + assert_equal "last", pq.dequeue + end + end #class + # ======================================================================================== @@ -54,54 +101,118 @@ def length # render a Recipe object to Recipe DSL -class Recipe - attr_accessor :steps, :ingredients, :name, :category, :prep_time, :rating - def initialize(name) - @name = name + class Recipe + attr_accessor :steps, :ingredients, :name, :category, :prep_time, :rating + def initialize(name) + @name = name + end + + def render_dsl + dsl = RecipeExport.new(self) + puts dsl.create_dsl + end end - def render_dsl - # your code here - end -end -class RecipeBuilder - def recipe(name, &block) - @recipe = Recipe.new(name) - self.instance_eval &block - @recipe - end - def category(value) - @recipe.category = value - end + class RecipeExport - def prep_time(value) - @recipe.prep_time = value - end - - def rating(value) - @recipe.rating = value - end + def initialize(recipe) + @ingredients = recipe.ingredients + @steps = recipe.steps + @name = recipe.name + end - def ingredients(&block) - @recipe.ingredients = [] - @items = @recipe.ingredients - self.instance_eval &block + def create_dsl + # is there a prettier way of dealing with indentation in heredocs + # that doesn't involve the weird tab alignments in the Ruby code, as below? + # I tried playing with gsub but it got quite confusing with all the embedded heredocs. + <<-DSL.gsub /\A {4}/, "" + recipe "#{@name}" do +#{ingredients} +#{steps}end + DSL + end + + def ingredients + <<-INGREDIENTS + ingredients do +#{@ingredients.map {|i| ingredient(i)}.join "" } end + INGREDIENTS + end + + def ingredient(ingredient) + <<-ING + x "#{ingredient}" + ING + end + + def step(step) + <<-STEP + x "#{step}" + STEP + end + + def steps + <<-STEPS + steps do +#{@steps.map {|s| step(s)}.join "" } end + STEPS + end end - def steps(&block) - @recipe.steps = [] - @items = @recipe.steps - self.instance_eval &block - end - - def x(item) - @items << item - end -end + class RecipeBuilder + def recipe(name, &block) + @recipe = Recipe.new(name) + self.instance_eval &block + @recipe + end + + def category(value) + @recipe.category = value + end + + def prep_time(value) + @recipe.prep_time = value + end + + def rating(value) + @recipe.rating = value + end + + def ingredients(&block) + @recipe.ingredients = [] + @items = @recipe.ingredients + self.instance_eval &block + end + + def steps(&block) + @recipe.steps = [] + @items = @recipe.steps + self.instance_eval &block + end + + def x(item) + @items << item + end + end #RecipeBuilder -def recipe(name, &block) - rb = RecipeBuilder.new - rb.recipe(name, &block) -end + def recipe(name, &block) + rb = RecipeBuilder.new + rb.recipe(name, &block) + end + + eggs = recipe "Scrambled Eggs" do + ingredients do + x "eggs" + x "salt" + x "pepper" + x "butter" + end + steps do + x "crack eggs" + x "cook eggs" + end + end + +end #module diff --git a/assignments/assignment07.rb b/assignments/assignment07.rb index 5d86f95..67bfba0 100644 --- a/assignments/assignment07.rb +++ b/assignments/assignment07.rb @@ -11,22 +11,63 @@ module Assignment07 module Observable def add_observer(obj) - # your implementation here + defined?(@observers)? @observers< 'I' -RomanNumeral.new(2).to_s # => 'II' -RomanNumeral.new(3).to_s # => 'III' -RomanNumeral.new(4).to_s # => 'IV' -RomanNumeral.new(5).to_s # => 'V' -RomanNumeral.new(6).to_s # => 'VI' -RomanNumeral.new(9).to_s # => 'IX' -RomanNumeral.new(10).to_s # => 'X' -RomanNumeral.new(19).to_s # => 'XIX' -RomanNumeral.new(32).to_s # => 'XXXII' -RomanNumeral.new(51).to_s # => 'LI' # bonus: -RomanNumeral.from_string('III').to_i # => 3 -RomanNumeral.from_string('IX').to_i # => 9 -RomanNumeral.from_string('IX').to_i # => 9 +#RomanNumeral.from_string('III').to_i # => 3 +#RomanNumeral.from_string('IX').to_i # => 9 +#RomanNumeral.from_string('IX').to_i # => 9 # given any arbitrary integer n: -n == RomanNumeral.from_string(RomanNumeral.new(n).to_s).to_i +#n == RomanNumeral.from_string(RomanNumeral.new(n).to_s).to_i @@ -60,13 +89,27 @@ def self.from_string # calculate the golden ratio up to specified precision # validate using MiniTest unit tests -module Assignment08 - def golden_ratio(precision) - # your implementation here +module Assignment08 + class GoldenRatioContainer + def golden_ratio(precision) + fib1= 61305790721611591 #fib(82) (a large fibonacci number) + fib2=37889062373143906 #fib(81) (another large fibonacci number) + (fib1.to_f/fib2.to_f).round(precision) + end + end + + require 'minitest/autorun' + + class GoldenRatioTest < MiniTest::Test + def setup + @my_gr = GoldenRatioContainer.new + end + + def test_one + assert_equal 1.62, @my_gr.golden_ratio(2) + assert_equal 1.61803, @my_gr.golden_ratio(5) + assert_equal 1.61803399, @my_gr.golden_ratio(8) + end end end -# expected results: -golden_ratio(2) # => 1.62 -golden_ratio(5) # => 1.61803 -golden_ratio(8) # => 1.61803399