Created
December 24, 2012 06:01
-
-
Save tamouse/4367947 to your computer and use it in GitHub Desktop.
Simple ruby script to parse checking account history CSV file and print a summary of aggregated transactions
This file contains 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
#!/usr/bin/env ruby | |
=begin | |
spending.rb -- show how I'm spending my money | |
usage: | |
spending.rb history.csv | |
=end | |
require 'csv' | |
=begin | |
convert_time | |
*param:*:: timestring - string containing the time to convert | |
*return:*:: Time object constructed from the elements in the timestring | |
In the input file, the transaction date has the form: | |
"m/d/y h:m:s am" | |
How US-centric. None of the standard Time, DateTime or Date parsing functions | |
deal with this crazy US format. Luckily, scan easily extracts the necessary | |
numeric bits, and a match will extract the AM/PM part. | |
=end | |
def convert_time(timestring) | |
timeparts = timestring.scan(/\d+/) | |
timeparts.map! {|p| p.to_i} # this replaces all the stringy bits picked up in the scan | |
# with their integer interpretations. | |
am_pm = timestring.match(/[AP]M/).to_s # check the trailing AM/PM indicator in the timestring | |
# and set the matching value to a string. This lets me | |
# do the comparison in the following instruction | |
timeparts[3] += 12 if am_pm == "PM" | |
# getting the local time here instead of GMT/UTC. | |
# the transaction time might actually be America/Los_Angeles since | |
# the bank is in California, but close enough for my purposes. | |
Time.local(timeparts[2],timeparts[0],timeparts[1],timeparts[3],timeparts[4],timeparts[5]) | |
end | |
=begin | |
add_to (bucket) | |
Add the amount to the given bucket's who key. | |
*param:*:: bucket -- the hash that will contain the key who, which will get amount added to it | |
*param:*:: who -- key in bucket which gets the additional amount | |
*param:*:: amount -- dollar amount to add to bucket[key] | |
*side effect:*:: amount is converted to cents here | |
What's special here is that as bucket will be initialized to empty in the beginning, | |
there's no garantee that the who key will be in the hash yet. So you can't do += on a | |
nil value, I test for it, and if bucket[who] is nil, then just assign amount | |
rather than adding. | |
=end | |
def add_to(bucket,who,amount) | |
amount = (amount*100).floor | |
if bucket.has_key?(who) | |
bucket[who] += amount | |
else | |
bucket[who] = amount | |
end | |
end | |
=begin | |
print_summary -- does the nice formatting for the bucket | |
*param:*:: bucket -- hash to print out | |
=end | |
def print_summary(bucket) | |
bucket.keys.sort.each do |t| | |
puts "%-70s:\t %5d\n" % [ t, bucket[t]/100 ] | |
end | |
end | |
=begin | |
Will work on the first account history csv file only. | |
TODO: work with more files? | |
=end | |
if ARGV.empty? | |
errmsg = "ERROR: Missing history.csv file\nUsage: spending.rb history.csv" | |
STDERR.puts errmsg | |
raise errmsg | |
end | |
statement = CSV.table(ARGV.first) | |
spending = {} | |
deposits = {} | |
beginning = ending = convert_time(statement.first[:transaction_date]) | |
statement.each do |t| | |
transaction_time = convert_time(t[:transaction_date]) | |
beginning = transaction_time if transaction_time < beginning | |
ending = transaction_time if transaction_time > ending | |
who = t[:extdesc].empty? ? t[:description] : t[:extdesc] | |
if t[:amount] < 0 | |
add_to(spending,who,t[:amount].abs) | |
else | |
add_to(deposits,who,t[:amount]) | |
end | |
end | |
report_title = "Period beginning #{beginning.to_s} and ending #{ending.to_s}" | |
puts report_title | |
puts "=" * report_title.length | |
puts | |
puts "Deposits:" | |
puts "-" * "Deposits:".length | |
print_summary(deposits) | |
puts | |
puts "Spending:" | |
puts "-" * "Spending:".length | |
print_summary(spending) | |
puts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment