thefox-wallet 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,117 +2,117 @@
2
2
  require 'date'
3
3
 
4
4
  module TheFox::Wallet
5
-
6
- # Add a new Entry.
7
- class AddCommand < Command
8
-
9
- NAME = 'add'
10
-
11
- def run
12
- if @options[:entry_category].nil?
13
- @options[:entry_category] = 'default'
14
- end
15
-
16
- if @options[:is_interactively]
17
- # Interactive User Input
18
-
19
- print "title: [#{@options[:entry_title]}] "
20
- title_t = STDIN.gets.strip
21
- if title_t.length > 0
22
- # Search for '%d' in title.
23
- if @options[:entry_title] =~ /%d/
24
- # Like sprintf.
25
- @options[:entry_title] = @options[:entry_title] % title_t.split(',').map{ |s| s.strip }
26
- else
27
- @options[:entry_title] = title_t
28
- end
29
- end
30
-
31
- print "date: [#{@options[:entry_date]}] "
32
- date_t = STDIN.gets.strip
33
- if date_t.length > 0
34
- @options[:entry_date] = date_t
35
- end
36
-
37
- print "revenue: [#{@options[:entry_revenue]}] "
38
- revenue_t = revenue(STDIN.gets.strip)
39
- if !revenue_t.nil?
40
- @options[:entry_revenue] = revenue_t
41
- end
42
-
43
- print "expense: [#{@options[:entry_expense]}] "
44
- expense_t = expense(STDIN.gets.strip)
45
- if !expense_t.nil?
46
- @options[:entry_expense] = expense_t
47
- end
48
-
49
- print "category: [#{@options[:entry_category]}] "
50
- category_t = STDIN.gets.strip
51
- if category_t.length > 0
52
- @options[:entry_category] = category_t
53
- end
54
-
55
- print "comment: [#{@options[:entry_comment]}] "
56
- comment_t = STDIN.gets.strip
57
- if comment_t.length > 0
58
- @options[:entry_comment] = comment_t
59
- end
60
-
61
- puts '-' * 20
62
- end
63
-
64
- if @options[:entry_title].nil?
65
- raise "Option --title is required for command '#{NAME}'"
66
- end
67
-
68
- # --force option
69
- # --id option
70
- is_unique = !@options[:force] && @options[:entry_id]
71
-
72
- puts "id: '#{@options[:entry_id]}'"
73
- puts "title: '#{@options[:entry_title]}'"
74
- puts "date: " << Date.parse(@options[:entry_date]).to_s
75
- puts "revenue: " << NUMBER_FORMAT % @options[:entry_revenue]
76
- puts "expense: " << NUMBER_FORMAT % @options[:entry_expense]
77
- puts "balance: " << NUMBER_FORMAT % [@options[:entry_revenue] + @options[:entry_expense]]
78
- puts "category: #{@options[:entry_category]}"
79
- puts "comment: '#{@options[:entry_comment]}'"
80
- puts "force: #{@options[:force] ? 'YES' : 'NO'}"
81
- puts "unique: #{is_unique ? 'YES' : 'NO'} (#{is_unique})"
82
-
83
- # Create new Entry.
84
- entry = Entry.new(@options[:entry_id], @options[:entry_title], @options[:entry_date], @options[:entry_revenue], @options[:entry_expense], @options[:entry_category], @options[:entry_comment])
85
-
86
- # Initialize Wallet.
87
- wallet = Wallet.new(@options[:wallet_path])
88
-
89
- # Add Entry to Wallet.
90
- added = wallet.add(entry, is_unique)
91
-
92
- puts "added: #{added ? 'YES' : 'NO'}"
93
-
94
- added
95
- end
96
-
97
- # @TODO replace with Wumber.
98
- def revenue(revenue_s)
99
- if !revenue_s.nil? && revenue_s.length > 0
100
- # Replace , with . in numbers. '1,23' means '1.23'.
101
- # eval the revenue so calculations are solved.
102
- eval(revenue_s.to_s.gsub(/,/, '.')).to_f.round(NUMBER_ROUND).abs
103
- end
104
- end
105
-
106
- # @TODO replace with Wumber.
107
- def expense(expense_s)
108
- if !expense_s.nil? && expense_s.length > 0
109
- # Replace , with . in numbers. '1,23' means '1.23'.
110
- # eval the revenue so calculations are solved.
111
- # Expenses are always minus.
112
- -eval(expense_s.to_s.gsub(/,/, '.')).to_f.round(NUMBER_ROUND).abs
113
- end
114
- end
115
-
116
- end
117
-
5
+
6
+ # Add a new Entry.
7
+ class AddCommand < Command
8
+
9
+ NAME = 'add'
10
+
11
+ def run
12
+ if @options[:entry_category].nil?
13
+ @options[:entry_category] = 'default'
14
+ end
15
+
16
+ if @options[:is_interactively]
17
+ # Interactive User Input
18
+
19
+ print "title: [#{@options[:entry_title]}] "
20
+ title_t = STDIN.gets.strip
21
+ if title_t.length > 0
22
+ # Search for '%d' in title.
23
+ if @options[:entry_title] =~ /%d/
24
+ # Like sprintf.
25
+ @options[:entry_title] = @options[:entry_title] % title_t.split(',').map{ |s| s.strip }
26
+ else
27
+ @options[:entry_title] = title_t
28
+ end
29
+ end
30
+
31
+ print "date: [#{@options[:entry_date]}] "
32
+ date_t = STDIN.gets.strip
33
+ if date_t.length > 0
34
+ @options[:entry_date] = date_t
35
+ end
36
+
37
+ print "revenue: [#{@options[:entry_revenue]}] "
38
+ revenue_t = revenue(STDIN.gets.strip)
39
+ if !revenue_t.nil?
40
+ @options[:entry_revenue] = revenue_t
41
+ end
42
+
43
+ print "expense: [#{@options[:entry_expense]}] "
44
+ expense_t = expense(STDIN.gets.strip)
45
+ if !expense_t.nil?
46
+ @options[:entry_expense] = expense_t
47
+ end
48
+
49
+ print "category: [#{@options[:entry_category]}] "
50
+ category_t = STDIN.gets.strip
51
+ if category_t.length > 0
52
+ @options[:entry_category] = category_t
53
+ end
54
+
55
+ print "comment: [#{@options[:entry_comment]}] "
56
+ comment_t = STDIN.gets.strip
57
+ if comment_t.length > 0
58
+ @options[:entry_comment] = comment_t
59
+ end
60
+
61
+ puts '-' * 20
62
+ end
63
+
64
+ if @options[:entry_title].nil?
65
+ raise "Option --title is required for command '#{NAME}'"
66
+ end
67
+
68
+ # --force option
69
+ # --id option
70
+ is_unique = !@options[:force] && @options[:entry_id]
71
+
72
+ puts "id: '#{@options[:entry_id]}'"
73
+ puts "title: '#{@options[:entry_title]}'"
74
+ puts "date: " << Date.parse(@options[:entry_date]).to_s
75
+ puts "revenue: " << NUMBER_FORMAT % @options[:entry_revenue]
76
+ puts "expense: " << NUMBER_FORMAT % @options[:entry_expense]
77
+ puts "balance: " << NUMBER_FORMAT % [@options[:entry_revenue] + @options[:entry_expense]]
78
+ puts "category: #{@options[:entry_category]}"
79
+ puts "comment: '#{@options[:entry_comment]}'"
80
+ puts "force: #{@options[:force] ? 'YES' : 'NO'}"
81
+ puts "unique: #{is_unique ? 'YES' : 'NO'} (#{is_unique})"
82
+
83
+ # Create new Entry.
84
+ entry = Entry.new(@options[:entry_id], @options[:entry_title], @options[:entry_date], @options[:entry_revenue], @options[:entry_expense], @options[:entry_category], @options[:entry_comment])
85
+
86
+ # Initialize Wallet.
87
+ wallet = Wallet.new(@options[:wallet_path])
88
+
89
+ # Add Entry to Wallet.
90
+ added = wallet.add(entry, is_unique)
91
+
92
+ puts "added: #{added ? 'YES' : 'NO'}"
93
+
94
+ added
95
+ end
96
+
97
+ # @TODO replace with Wumber.
98
+ def revenue(revenue_s)
99
+ if !revenue_s.nil? && revenue_s.length > 0
100
+ # Replace , with . in numbers. '1,23' means '1.23'.
101
+ # eval the revenue so calculations are solved.
102
+ eval(revenue_s.to_s.gsub(/,/, '.')).to_f.round(NUMBER_ROUND).abs
103
+ end
104
+ end
105
+
106
+ # @TODO replace with Wumber.
107
+ def expense(expense_s)
108
+ if !expense_s.nil? && expense_s.length > 0
109
+ # Replace , with . in numbers. '1,23' means '1.23'.
110
+ # eval the revenue so calculations are solved.
111
+ # Expenses are always minus.
112
+ -eval(expense_s.to_s.gsub(/,/, '.')).to_f.round(NUMBER_ROUND).abs
113
+ end
114
+ end
115
+
116
+ end
117
+
118
118
  end
@@ -1,16 +1,16 @@
1
1
 
2
2
  module TheFox::Wallet
3
-
4
- # List all used categories.
5
- class CategoriesCommand < Command
6
-
7
- NAME = 'categories'
8
-
9
- def run
10
- wallet = Wallet.new(@options[:wallet_path])
11
- puts wallet.categories
12
- end
13
-
14
- end
15
-
3
+
4
+ # List all used categories.
5
+ class CategoriesCommand < Command
6
+
7
+ NAME = 'categories'
8
+
9
+ def run
10
+ wallet = Wallet.new(@options[:wallet_path])
11
+ puts wallet.categories
12
+ end
13
+
14
+ end
15
+
16
16
  end
@@ -2,17 +2,17 @@
2
2
  require 'pathname'
3
3
 
4
4
  module TheFox::Wallet
5
-
6
- # Clear temp and cache files.
7
- class ClearCommand < Command
8
-
9
- NAME = 'clear'
10
-
11
- def run
12
- wallet = Wallet.new(@options[:wallet_path])
13
- wallet.logger = @options[:logger]
14
- wallet.clear
15
- end
16
-
17
- end
5
+
6
+ # Clear temp and cache files.
7
+ class ClearCommand < Command
8
+
9
+ NAME = 'clear'
10
+
11
+ def run
12
+ wallet = Wallet.new(@options[:wallet_path])
13
+ wallet.logger = @options[:logger]
14
+ wallet.clear
15
+ end
16
+
17
+ end
18
18
  end
@@ -1,33 +1,33 @@
1
1
 
2
2
  module TheFox::Wallet
3
-
4
- # Import or export to/from CSV file format.
5
- class CsvCommand < Command
6
-
7
- NAME = 'csv'
8
-
9
- def run
10
- if @options[:path].nil?
11
- raise "Option --path is required for command '#{NAME}'"
12
- end
13
-
14
- wallet = Wallet.new(@options[:wallet_path])
15
- wallet.logger = @options[:logger]
16
-
17
- # Import by default.
18
- if @options[:is_import] || !@options[:is_export]
19
- # Import
20
- @options[:logger].info("import csv #{@options[:path]} ...") if @options[:logger]
21
- wallet.import_csv_file(@options[:path])
22
- @options[:logger].info("import csv #{@options[:path]} done") if @options[:logger]
23
- elsif @options[:is_export]
24
- # Export
25
- @options[:logger].info("export csv #{@options[:path]} ...") if @options[:logger]
26
- wallet.export_csv_file(@options[:path])
27
- @options[:logger].info("export csv #{@options[:path]} done") if @options[:logger]
28
- end
29
- end
30
-
31
- end
32
-
3
+
4
+ # Import or export to/from CSV file format.
5
+ class CsvCommand < Command
6
+
7
+ NAME = 'csv'
8
+
9
+ def run
10
+ if @options[:path].nil?
11
+ raise "Option --path is required for command '#{NAME}'"
12
+ end
13
+
14
+ wallet = Wallet.new(@options[:wallet_path])
15
+ wallet.logger = @options[:logger]
16
+
17
+ # Import by default.
18
+ if @options[:is_import] || !@options[:is_export]
19
+ # Import
20
+ @options[:logger].info("import csv #{@options[:path]} ...") if @options[:logger]
21
+ wallet.import_csv_file(@options[:path])
22
+ @options[:logger].info("import csv #{@options[:path]} done") if @options[:logger]
23
+ elsif @options[:is_export]
24
+ # Export
25
+ @options[:logger].info("export csv #{@options[:path]} ...") if @options[:logger]
26
+ wallet.export_csv_file(@options[:path])
27
+ @options[:logger].info("export csv #{@options[:path]} done") if @options[:logger]
28
+ end
29
+ end
30
+
31
+ end
32
+
33
33
  end
@@ -2,24 +2,24 @@
2
2
  require 'pathname'
3
3
 
4
4
  module TheFox::Wallet
5
-
6
- # Exports a wallet as HTML.
7
- # List all years in an index HTML file and all months for each year.
8
- # Generates a HTML file for each month based on entries.
9
- class HtmlCommand < Command
10
-
11
- NAME = 'html'
12
-
13
- def run
14
- if @options[:path]
15
- html_path = Pathname.new(@options[:path]).expand_path
16
- end
17
-
18
- wallet = Wallet.new(@options[:wallet_path])
19
- wallet.logger = @options[:logger]
20
- wallet.generate_html(html_path, @options[:entry_date_start], @options[:entry_date_end], @options[:entry_category])
21
- end
22
-
23
- end
24
-
5
+
6
+ # Exports a wallet as HTML.
7
+ # List all years in an index HTML file and all months for each year.
8
+ # Generates a HTML file for each month based on entries.
9
+ class HtmlCommand < Command
10
+
11
+ NAME = 'html'
12
+
13
+ def run
14
+ if @options[:path]
15
+ html_path = Pathname.new(@options[:path]).expand_path
16
+ end
17
+
18
+ wallet = Wallet.new(@options[:wallet_path])
19
+ wallet.logger = @options[:logger]
20
+ wallet.generate_html(html_path, @options[:entry_date_start], @options[:entry_date_end], @options[:entry_category])
21
+ end
22
+
23
+ end
24
+
25
25
  end
@@ -1,176 +1,171 @@
1
1
 
2
2
  module TheFox::Wallet
3
-
4
- # List entries. Per default this command lists all entries of today.
5
- # @TODO Use terminal-table for output? https://github.com/tj/terminal-table
6
- class ListCommand < Command
7
-
8
- NAME = 'list'
9
-
10
- def run
11
- puts
12
-
13
- wallet = Wallet.new(@options[:wallet_path])
14
- entries = wallet.entries(@options[:entry_date], @options[:entry_category].to_s)
15
-
16
- # Get max length of all columns.
17
- entries_l = entries
18
- .map{ |day_name, day_items| day_items.count }
19
- .inject{ |sum, n| sum + n }
20
- .to_s
21
- .length
22
- title_l = entries
23
- .map{ |month_item| month_item[1].map{ |day_item| day_item['title'].length }}
24
- .flatten
25
- .max
26
- .to_i
27
- revenue_l = entries
28
- .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['revenue']).length } }
29
- .flatten
30
- .max
31
- .to_i
32
- expense_l = entries
33
- .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['expense']).length } }
34
- .flatten
35
- .max
36
- .to_i
37
- balance_l = entries
38
- .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['balance']).length } }
39
- .flatten
40
- .max
41
- .to_i
42
- category_l = entries
43
- .map{ |month_item| month_item[1].map{ |day_item| day_item['category'].length } }
44
- .flatten
45
- .max
46
- .to_i
47
- comment_l = entries
48
- .map{ |month_item| month_item[1].map{ |day_item| day_item['comment'].length } }
49
- .flatten
50
- .max
51
- .to_i
52
-
53
- has_category_col = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['category'] } }.flatten.select{ |i| i != 'default' }.count > 0
54
- has_comment_col = entries
55
- .map{ |month_item| month_item[1].map{ |day_item| day_item['comment'] } }
56
- .flatten
57
- .select{ |i| i != '' }
58
- .count > 0
59
-
60
- # Limit some columns to a maximum length.
61
- if title_l < 6
62
- title_l = 6
63
- end
64
- if title_l > 25
65
- title_l = 25
66
- end
67
-
68
- if revenue_l < 7
69
- revenue_l = 7
70
- end
71
- if expense_l < 7
72
- expense_l = 7
73
- end
74
- if balance_l < 7
75
- balance_l = 7
76
- end
77
- if category_l < 8
78
- category_l = 8
79
- end
80
- if comment_l > 25
81
- comment_l = 25
82
- end
83
-
84
- # Format String for each column.
85
- entries_f = "%#{entries_l}s"
86
- title_f = "%-#{title_l}s"
87
- revenue_f = "%#{revenue_l}s"
88
- expense_f = "%#{expense_l}s"
89
- balance_f = "%#{balance_l}s"
90
- category_f = "%-#{category_l}s"
91
- comment_f = "%-#{comment_l}s"
92
-
93
- # Create a table header.
94
- header = ''
95
- header << '#' * entries_l << ' '
96
- header << 'Date ' << ' ' * 7
97
- header << title_f % 'Title' << ' '
98
- header << revenue_f % 'Revenue' << ' '
99
- header << expense_f % 'Expense' << ' '
100
- header << balance_f % 'Balance'
101
- if has_category_col
102
- header << ' ' << category_f % 'Category'
103
- end
104
- if has_comment_col
105
- header << ' ' << comment_f % 'Comment'
106
- end
107
-
108
- header_l = header.length
109
- header.sub!(/ +$/, '')
110
-
111
- # Print table header.
112
- puts header
113
- puts '-' * header_l
114
-
115
- # Sums
116
- revenue_total = 0.0
117
- expense_total = 0.0
118
- balance_total = 0.0
119
-
120
- # Do not repeat the same date over and over again.
121
- previous_date = ''
122
-
123
- entry_no = 0
124
-
125
- # Iterate all days.
126
- entries.sort.each do |day_name, day_items|
127
- # Iterate all entries of a day.
128
- day_items.each do |entry|
129
- entry_no += 1
130
-
131
- title = entry['title']
132
- if title.length >= 25
133
- title = title[0, 22] << '...'
134
- end
135
-
136
- revenue_total += entry['revenue']
137
- expense_total += entry['expense']
138
- balance_total += entry['balance']
139
-
140
- category = entry['category'] == 'default' ? '' : entry['category']
141
-
142
- comment = entry['comment']
143
- if comment.length >= 25
144
- comment = comment[0, 22] << '...'
145
- end
146
-
147
- out = ''
148
- out << entries_f % entry_no
149
- out << ' ' << '%10s' % (entry['date'] == previous_date ? '' : entry['date'])
150
- out << ' ' << title_f % title
151
- out << ' ' << revenue_f % (NUMBER_FORMAT % entry['revenue'])
152
- out << ' ' << expense_f % (NUMBER_FORMAT % entry['expense'])
153
- out << ' ' << balance_f % (NUMBER_FORMAT % entry['balance'])
154
- out << ' ' << category_f % category if has_category_col
155
- out << ' ' << comment_f % comment if has_comment_col
156
-
157
- out.sub!(/ +$/, '')
158
- puts out
159
-
160
- previous_date = entry['date']
161
- end
162
- end
163
- puts
164
-
165
- out = ''
166
- out << ' ' * (12 + entries_l)
167
- out << ' ' << title_f % 'TOTAL'
168
- out << ' ' << revenue_f % (NUMBER_FORMAT % revenue_total)
169
- out << ' ' << expense_f % (NUMBER_FORMAT % expense_total)
170
- out << ' ' << balance_f % (NUMBER_FORMAT % balance_total)
171
- puts out
172
- end
173
-
174
- end
175
-
3
+
4
+ # List entries. Per default this command lists all entries of today.
5
+ # @TODO Use terminal-table for output? https://github.com/tj/terminal-table
6
+ class ListCommand < Command
7
+
8
+ NAME = 'list'
9
+
10
+ def run
11
+ puts
12
+
13
+ wallet = Wallet.new(@options[:wallet_path])
14
+ entries = wallet.entries(@options[:entry_date], @options[:entry_category].to_s)
15
+
16
+ # Get max length of all columns.
17
+ entries_l = entries
18
+ .map{ |day_name, day_items| day_items.count }
19
+ .inject{ |sum, n| sum + n }
20
+ .to_s
21
+ .length
22
+ title_l = entries
23
+ .map{ |month_item| month_item[1].map{ |day_item| day_item['title'].length }}
24
+ .flatten
25
+ .max
26
+ .to_i
27
+ revenue_l = entries
28
+ .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['revenue']).length } }
29
+ .flatten
30
+ .max
31
+ .to_i
32
+ expense_l = entries
33
+ .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['expense']).length } }
34
+ .flatten
35
+ .max
36
+ .to_i
37
+ balance_l = entries
38
+ .map{ |month_item| month_item[1].map{ |day_item| (NUMBER_FORMAT % day_item['balance']).length } }
39
+ .flatten
40
+ .max
41
+ .to_i
42
+ category_l = entries
43
+ .map{ |month_item| month_item[1].map{ |day_item| day_item['category'].length } }
44
+ .flatten
45
+ .max
46
+ .to_i
47
+ comment_l = entries
48
+ .map{ |month_item| month_item[1].map{ |day_item| day_item['comment'].length } }
49
+ .flatten
50
+ .max
51
+ .to_i
52
+
53
+ has_category_col = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['category'] } }.flatten.select{ |i| i != 'default' }.count > 0
54
+ has_comment_col = entries
55
+ .map{ |month_item| month_item[1].map{ |day_item| day_item['comment'] } }
56
+ .flatten
57
+ .select{ |i| i != '' }
58
+ .count > 0
59
+
60
+ # Limit some columns to a maximum length.
61
+ if title_l < 6
62
+ title_l = 6
63
+ end
64
+ if title_l > 25
65
+ title_l = 25
66
+ end
67
+
68
+ if revenue_l < 7
69
+ revenue_l = 7
70
+ end
71
+ if expense_l < 7
72
+ expense_l = 7
73
+ end
74
+ if balance_l < 7
75
+ balance_l = 7
76
+ end
77
+ if category_l < 8
78
+ category_l = 8
79
+ end
80
+ if comment_l > 25
81
+ comment_l = 25
82
+ end
83
+
84
+ # Format String for each column.
85
+ entries_f = "%#{entries_l}s"
86
+ title_f = "%-#{title_l}s"
87
+ revenue_f = "%#{revenue_l}s"
88
+ expense_f = "%#{expense_l}s"
89
+ balance_f = "%#{balance_l}s"
90
+ category_f = "%-#{category_l}s"
91
+ comment_f = "%-#{comment_l}s"
92
+
93
+ # Create a table header.
94
+ header = ''
95
+ header << '#' * entries_l << ' '
96
+ header << 'Date ' << ' ' * 7
97
+ header << title_f % 'Title' << ' '
98
+ header << revenue_f % 'Revenue' << ' '
99
+ header << expense_f % 'Expense' << ' '
100
+ header << balance_f % 'Balance'
101
+ if has_category_col
102
+ header << ' ' << category_f % 'Category'
103
+ end
104
+ if has_comment_col
105
+ header << ' ' << comment_f % 'Comment'
106
+ end
107
+
108
+ header_l = header.length
109
+ header.sub!(/ +$/, '')
110
+
111
+ # Print table header.
112
+ puts header
113
+ puts '-' * header_l
114
+
115
+ # Sums
116
+ revenue_total = 0.0
117
+ expense_total = 0.0
118
+ balance_total = 0.0
119
+
120
+ entry_no = 0
121
+
122
+ # Iterate all days.
123
+ entries.sort.each do |day_name, day_items|
124
+ # Iterate all entries of a day.
125
+ day_items.each do |entry|
126
+ entry_no += 1
127
+
128
+ title = entry['title']
129
+ if title.length >= 25
130
+ title = title[0, 22] << '...'
131
+ end
132
+
133
+ revenue_total += entry['revenue']
134
+ expense_total += entry['expense']
135
+ balance_total += entry['balance']
136
+
137
+ category = entry['category'] == 'default' ? '' : entry['category']
138
+
139
+ comment = entry['comment']
140
+ if comment.length >= 25
141
+ comment = comment[0, 22] << '...'
142
+ end
143
+
144
+ out = ''
145
+ out << entries_f % entry_no
146
+ out << ' ' << '%10s' % entry['date']
147
+ out << ' ' << title_f % title
148
+ out << ' ' << revenue_f % (NUMBER_FORMAT % entry['revenue'])
149
+ out << ' ' << expense_f % (NUMBER_FORMAT % entry['expense'])
150
+ out << ' ' << balance_f % (NUMBER_FORMAT % entry['balance'])
151
+ out << ' ' << category_f % category if has_category_col
152
+ out << ' ' << comment_f % comment if has_comment_col
153
+
154
+ out.sub!(/ +$/, '')
155
+ puts out
156
+ end
157
+ end
158
+ puts
159
+
160
+ out = ''
161
+ out << ' ' * (12 + entries_l)
162
+ out << ' ' << title_f % 'TOTAL'
163
+ out << ' ' << revenue_f % (NUMBER_FORMAT % revenue_total)
164
+ out << ' ' << expense_f % (NUMBER_FORMAT % expense_total)
165
+ out << ' ' << balance_f % (NUMBER_FORMAT % balance_total)
166
+ puts out
167
+ end
168
+
169
+ end
170
+
176
171
  end