Fixed a typo in code.
[fin.git] / fin.rb
blobbf6c669052feed64f82a5ef7a0b32c71f9b9446b
1 #!/usr/bin/ruby -w
3 require 'ledger'
4 require 'optparse'
6 options = {}
7 OptionParser.new do |opts|
8   opts.banner = "Usage:  fin [options]"
10   options[:transactions_file] = "#{File.expand_path('~')}/.fin/transactions"  
11   opts.on("", "--transactions-file FILE",
12           "Use transactions file FILE") do |filename|
13     options[:transactions_file] = File.expand_path(filename)
14   end
16   options[:totals_filter] = 'true'
17   opts.on("", "--filter FILTER",
18           "Use Ruby predicate FILTER as filter on input.",
19           "Assume availability of Transaction object",
20           "parameter named \"transaction\"") do |filter|
21     options[:totals_filter] = filter
22   end
23 end.parse!
25 begin
26   ledger = Ledger.new(options[:transactions_file])
27 rescue Errno::ENOENT
28   STDERR.puts "Error:  Couldn't open file #{options[:transactions_file]}"
29   exit 1
30 end
32 STDERR.puts "#{ledger.length} transactions read."
34 def totals(ledger, options = {})
35   options = {:format => :humane }.merge options
36   # set up a few handy names for filtering by the --filter command-line option
37   yesterday, today, tomorrow = Date.today - 1, Date.today, Date.today + 1
38   last_month, this_month, next_month = today << 1, today, today >> 1
39   last_year, this_year, next_year = today << 12, today, today >> 12
40   last_month_start = Date.new(last_month.year, last_month.month, 1)
41   last_month_end = Date.new(last_month.year, last_month.month, -1)
42   this_month_start = Date.new(this_month.year, this_month.month, 1)
43   this_month_end = Date.new(this_month.year, this_month.month, -1)
44   next_month_start = Date.new(next_month.year, next_month.month, 1)
45   next_month_end = Date.new(next_month.year, next_month.month, -1)
46   last_year_start = Date.new(last_year.year, 1, 1)
47   last_year_end = Date.new(last_year.year, -1, -1)
48   this_year_start = Date.new(this_year.year, 1, 1)
49   this_year_end = Date.new(this_year.year, -1, -1)
50   next_year_start = Date.new(next_year.year, 1, 1)
51   next_year_end = Date.new(next_year.year, -1, -1)
52   # get filtered totals.
53   account_totals = ledger.accumulate do |transaction|
54     from, to = transaction.from, transaction.to
55     amount = transaction.amount
56     date = transaction.date
57     notes = transaction.description
58     eval(options[:totals_filter])
59   end
60   # sort totals
61   account_totals.sort! do |account1, account2|
62     account1.to_s <=> account2.to_s
63   end
65   # print totals out
66   STDERR.puts "#{account_totals.length} accounts defined.", "\n"
67   account_totals.each_index do |index|
68     if options[:format] == :humane
69       account_name = '  ' * (account_totals[index].depth) + account_totals[index].name
70       print account_name
71       print(("%.2f" % account_totals[index].balance).rjust(40 - account_name.length, '.'))
72     else
73       print account
74       print("\t", ("%.2f" % account_totals[index]))
75     end
76     puts
77   end
78 end
80 totals ledger, options.merge({:format => :humane})