thefox-wallet 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c7c1ba3617a57f9c4291350ffb2b035cd41c5904
4
+ data.tar.gz: 2cb59e3a489b3ff322bb70a00986fac90f56027e
5
+ SHA512:
6
+ metadata.gz: 0d14831c7cc6199f946266b3b1908f715072c0f6694f430811f8fc12e50039925a6508d1e7cec26e5408b9551ebebb5986988e4823589e68f55d9ac0900170e9
7
+ data.tar.gz: 736ba6899807150cc510348e6a113a0f7ce22ba034a9c614a8fc4ebb03ed5f2960b1aa6c3713e999633ea77babc0422f9b6741a6632e2c3151c09d9fcf0e569d
@@ -0,0 +1,9 @@
1
+ .setup
2
+ CHANGELOG-*.txt
3
+ /bin/test
4
+ /releases/
5
+ /wallet/
6
+ /wallet_test/
7
+ *.csv
8
+ *.txt
9
+ *.yml
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+
2
+ source 'https://rubygems.org'
3
+ gemspec
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ thefox-wallet (0.8.0)
5
+ ArgsParser (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ArgsParser (1.0.0)
11
+ coderay (1.1.0)
12
+ method_source (0.8.2)
13
+ minitest (5.8.3)
14
+ pry (0.10.3)
15
+ coderay (~> 1.1.0)
16
+ method_source (~> 0.8.1)
17
+ slop (~> 3.4)
18
+ rake (10.4.2)
19
+ slop (3.6.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bundler (~> 1.10)
26
+ minitest (~> 5.7)
27
+ pry (~> 0.10)
28
+ rake (~> 10.0)
29
+ thefox-wallet!
30
+
31
+ BUNDLED WITH
32
+ 1.10.2
@@ -0,0 +1,4 @@
1
+
2
+ GEM_NAME = thefox-wallet
3
+
4
+ include Makefile.common
@@ -0,0 +1,50 @@
1
+
2
+ # Ruby Common Big
3
+ # 2015-12-07
4
+
5
+ MV = mv -nv
6
+ RM = rm -rf
7
+ MKDIR = mkdir -p
8
+ BUNDLER = bundle
9
+ GEMSPEC_FILE = $(GEM_NAME).gemspec
10
+
11
+ .PHONY: all
12
+ all: setup
13
+
14
+ .PHONY: setup
15
+ setup: .setup
16
+
17
+ .setup:
18
+ $(BUNDLER) install
19
+ touch $@
20
+
21
+ .PHONY: install
22
+ install:
23
+ gem_file=$$(gem build $(GEMSPEC_FILE) | grep 'File:' | tail -1 | awk '{ print $$2 }'); \
24
+ sudo gem install $$gem_file; \
25
+ $(RM) $$gem_file
26
+
27
+ .PHONY: uninstall
28
+ uninstall:
29
+ sudo gem uninstall $(GEM_NAME)
30
+
31
+ .PHONY: update
32
+ update:
33
+ $(BUNDLER) update
34
+
35
+ .PHONY: clean
36
+ clean:
37
+ $(RM) .setup
38
+
39
+ .PHONY: release
40
+ release: | releases
41
+ set -e; \
42
+ gem_file=$$(gem build $(GEMSPEC_FILE) | grep 'File:' | tail -1 | awk '{ print $$2 }'); \
43
+ dst="releases/$$gem_file"; \
44
+ [ ! -f $$dst ]; \
45
+ $(MV) $$gem_file releases; \
46
+ gem push $$dst; \
47
+ echo 'done'
48
+
49
+ releases:
50
+ $(MKDIR) $@
@@ -0,0 +1,38 @@
1
+ # Wallet
2
+
3
+ A spreadsheet likewise Ruby library to track your finances. Using the best data format ever, YAML. It's designed to host the data offline, e.g. in a Git repository.
4
+
5
+ ## Why this project?
6
+
7
+ While conventionally programs like Microsoft Excel or [LibreOffice](https://www.libreoffice.org/) uses [proprietary file formats](https://en.wikipedia.org/wiki/Proprietary_format) and [binary files](https://en.wikipedia.org/wiki/Binary_file) to save your data this script uses [YAML](https://en.wikipedia.org/wiki/YAML). YAML is a human-readable data serialization format. This means you can edit the YAML files on any [operating system](https://en.wikipedia.org/wiki/Operating_system) with any text editor.
8
+
9
+ ## Features
10
+
11
+ - Save revenues/expenses entries monthly.
12
+ - List saved entries.
13
+ - Import CSV files.
14
+ - Export data to CSV.
15
+ - Generate HTML summary.
16
+ - VI/editor import mode. (CSV)
17
+
18
+ ## Install
19
+
20
+ The preferred method of installation is via RubyGems.org:
21
+ <https://rubygems.org/gems/thefox-wallet>
22
+
23
+ gem install thefox-wallet
24
+
25
+ or via `Gemfile`:
26
+
27
+ gem 'thefox-wallet', '~>0.8'
28
+
29
+ Use it in your sources:
30
+
31
+ require 'thefox-wallet'
32
+
33
+ ## License
34
+ Copyright (C) 2015 Christian Mayer <http://fox21.at>
35
+
36
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
37
+
38
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,2 @@
1
+
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,328 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tempfile'
4
+ require 'bundler/setup'
5
+ require 'wallet'
6
+ require 'ArgsParser'
7
+
8
+
9
+ parser = ArgsParser.parser
10
+ parser.bind(:wallet, :w, 'Wallet', 'wallet')
11
+ parser.bind(:title, :t, 'Title')
12
+ parser.bind(:date, :d, 'Date', Date.today.to_s)
13
+ parser.bind(:revenue, :r, 'Revenue', 0)
14
+ parser.bind(:expense, :e, 'Expense', 0)
15
+ parser.bind(:category, :c, 'Category')
16
+ parser.bind(:comment, :o, 'Comment')
17
+ parser.bind(:path, :p, 'Path')
18
+
19
+ command, params = parser.parse(ARGV)
20
+ command = command.to_s
21
+
22
+ # puts 'command: ' + command.to_s
23
+ # puts 'params: ' + params.to_s
24
+ # puts
25
+
26
+ # Command Aliases
27
+ if command == 'i'
28
+ command = 'int'
29
+ elsif command == 'l'
30
+ command = 'list'
31
+ elsif command == 'lc'
32
+ command = 'cat'
33
+ end
34
+
35
+ wallet = params[:wallet].to_s
36
+ title = params[:title].to_s
37
+ date = params[:date].to_s
38
+ revenue = params[:revenue].to_s.gsub('.', '').sub(/,/, '.').to_f.round(3).abs
39
+ category = params[:category].to_s
40
+ comment = params[:comment].to_s
41
+ path = params[:path].to_s
42
+ import = params[:i]
43
+
44
+ path_is_temp = false
45
+
46
+ expense = 0.0
47
+ export = false
48
+ if params[:expense].is_a? TrueClass
49
+ export = true
50
+ else
51
+ expense = -params[:expense].to_s.gsub('.', '').sub(/,/, '.').to_f.round(3).abs
52
+ end
53
+
54
+ # puts 'argv len: ' + ARGV.length.to_s
55
+ # puts 'command: ' + '%-10s' % command.class.to_s + ' "' + command.to_s + '"'
56
+ # puts 'wallet: ' + '%-10s' % wallet.class.to_s + ' "' + wallet.to_s + '"'
57
+ # puts 'title: ' + '%-10s' % title.class.to_s + ' "' + title + '"'
58
+ # puts 'date: ' + '%-10s' % date.class.to_s + ' "' + date + '"'
59
+ # puts 'revenue: ' + '%-10s' % revenue.class.to_s + ' "' + revenue.to_s + '"'
60
+ # puts 'expense: ' + '%-10s' % expense.class.to_s + ' "' + expense.to_s + '"'
61
+ # puts 'category: ' + '%-10s' % category.class.to_s + ' "' + category + '"'
62
+ # puts 'comment: ' + '%-10s' % comment.class.to_s + ' "' + comment.to_s + '"'
63
+ # puts 'path: ' + '%-10s' % path.class.to_s + ' "' + path.to_s + '"'
64
+ # puts
65
+
66
+ if command == 'help' || command.length == 0
67
+ script_name = File.basename(__FILE__)
68
+ padding = ' ' * (script_name.length + 8)
69
+
70
+ puts "#{::TheFox::Wallet::NAME} #{::TheFox::Wallet::VERSION} (#{::TheFox::Wallet::DATE})"
71
+ puts 'Usage: ' + script_name + ' COMMAND OPTIONS'
72
+ puts
73
+ puts 'Commands:'
74
+ puts padding + 'help Show this help'
75
+ puts padding + 'add Add a new entry'
76
+ puts padding + 'i|int Add a new entry interactively'
77
+ puts padding + 'l|list List entries'
78
+ puts padding + 'lc|cat List categories'
79
+ puts padding + 'html Generate HTML files'
80
+ puts padding + 'csv Import/Export CSV file'
81
+ puts padding + 'vi Import per VIM editor'
82
+ puts
83
+ puts 'Options:'
84
+ puts padding + '-w|--wallet PATH Optional'
85
+ puts padding + '-t|--title TITLE Required for command "add"'
86
+ puts padding + '-d|--date Optional'
87
+ puts padding + '-r|--revenue Optional. Default: 0'
88
+ puts padding + '-e|--expense Optional. Default: 0'
89
+ puts padding + '-c|--category Optional. Default: default'
90
+ puts padding + '-o|--comment Optional'
91
+ puts padding + '-i|-e Import or Export. Default: -i'
92
+ puts padding + '-p|--path PATH Required for command "csv"'
93
+
94
+ exit 3
95
+ end
96
+
97
+ if command == 'int'
98
+ command = 'add'
99
+
100
+ print 'title: [' + title + '] '
101
+ title_t = STDIN.gets.strip
102
+ if title_t.length > 0
103
+ title = title_t
104
+ end
105
+
106
+ print 'date: [' + date + '] '
107
+ date_t = STDIN.gets.strip
108
+ if date_t.length > 0
109
+ date = date_t
110
+ end
111
+
112
+ print 'revenue: [' + revenue.to_s + '] '
113
+ revenue_t = STDIN.gets.strip
114
+ if revenue_t.length > 0
115
+ revenue = revenue_t.to_s.gsub('.', '').sub(/,/, '.').to_f.round(3).abs
116
+ end
117
+
118
+ print 'expense: [' + expense.to_s + '] '
119
+ expense_t = STDIN.gets.strip
120
+ if expense_t.length > 0
121
+ expense = -expense_t.to_s.gsub('.', '').sub(/,/, '.').to_f.round(3).abs
122
+ end
123
+
124
+ if category.to_s.length == 0
125
+ category = 'default'
126
+ end
127
+ print 'category: [' + category + '] '
128
+ category_t = STDIN.gets.strip
129
+ if category_t.length > 0
130
+ category = category_t
131
+ end
132
+
133
+ print 'comment: [' + comment + '] '
134
+ comment_t = STDIN.gets.strip
135
+ if comment_t.length > 0
136
+ comment = comment_t
137
+ end
138
+
139
+ puts '-' * 20
140
+ elsif command == 'vi'
141
+ vi_file = Tempfile.create('wallet-vi-import', '/tmp')
142
+ vi_file.puts('# This is a comment line.')
143
+ vi_file.puts('# Date,Title,Revenue,Expense,Category,Comment')
144
+ vi_file.puts('# Date,Title,Expense')
145
+ vi_file.close
146
+
147
+ puts 'cwd: ' + Dir.pwd
148
+ puts 'editor: ' + ENV['EDITOR']
149
+ puts 'file: ' + vi_file.path
150
+ sleep 1
151
+
152
+ system(ENV['EDITOR'] + ' ' + vi_file.path)
153
+ system('grep -v "#" ' + vi_file.path + ' | grep -v ^$ > ' + vi_file.path + '.ok')
154
+
155
+ command = 'csv'
156
+ path = vi_file.path + '.ok'
157
+ path_is_temp = true
158
+ import = true
159
+
160
+ File.unlink vi_file.path
161
+ end
162
+
163
+ wallet = TheFox::Wallet::Wallet.new(wallet)
164
+
165
+ if command == 'add'
166
+ if category.to_s.length == 0
167
+ category = 'default'
168
+ end
169
+
170
+ if title == ''
171
+ puts 'ERROR: Option --title is required for command "' + command + '"'
172
+ exit 1
173
+ end
174
+
175
+ puts 'title: ' + title
176
+ puts 'date: ' + Date.parse(date).to_s
177
+ puts 'revenue: ' + revenue.to_s
178
+ puts 'expense: ' + expense.to_s
179
+ puts 'balance: ' + (revenue + expense).to_f.round(3).to_s
180
+ puts 'category: ' + category.to_s
181
+ puts 'comment: ' + comment.to_s
182
+
183
+ wallet.add TheFox::Wallet::Entry.new(title, date, revenue, expense, category, comment)
184
+ elsif command == 'list'
185
+ puts
186
+
187
+ year, month, day = date.scan(/^(\d{2,4}).?(\d{0,2}).?(\d{0,2})/).shift.map{ |x|
188
+ y = x.to_i
189
+ y == 0 ? nil : y
190
+ }
191
+
192
+ entries = wallet.entries(year, month, day, category)
193
+
194
+ entries_l = entries.map{ |day_name, day_items| day_items.count }.inject{ |sum, n| sum + n }.to_s.length
195
+ title_l = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['title'].length } }.flatten.max.to_i
196
+ revenue_l = entries.map{ |month_item| month_item[1].map{ |day_item| (::TheFox::Wallet::NUMBER_FORMAT % day_item['revenue']).length } }.flatten.max.to_i
197
+ expense_l = entries.map{ |month_item| month_item[1].map{ |day_item| (::TheFox::Wallet::NUMBER_FORMAT % day_item['expense']).length } }.flatten.max.to_i
198
+ balance_l = entries.map{ |month_item| month_item[1].map{ |day_item| (::TheFox::Wallet::NUMBER_FORMAT % day_item['balance']).length } }.flatten.max.to_i
199
+ category_l = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['category'].length } }.flatten.max.to_i
200
+ comment_l = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['comment'].length } }.flatten.max.to_i
201
+
202
+ has_category_col = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['category'] } }.flatten.select{ |i| i != 'default' }.count > 0
203
+ has_comment_col = entries.map{ |month_item| month_item[1].map{ |day_item| day_item['comment'] } }.flatten.select{ |i| i != '' }.count > 0
204
+
205
+ if title_l < 6
206
+ title_l = 6
207
+ end
208
+ if title_l > 25
209
+ title_l = 25
210
+ end
211
+
212
+ if revenue_l < 7
213
+ revenue_l = 7
214
+ end
215
+ if expense_l < 7
216
+ expense_l = 7
217
+ end
218
+ if balance_l < 7
219
+ balance_l = 7
220
+ end
221
+ if category_l < 8
222
+ category_l = 8
223
+ end
224
+ if comment_l > 25
225
+ comment_l = 25
226
+ end
227
+
228
+ entries_f = '%' + entries_l.to_s + 's'
229
+ title_f = '%-' + title_l.to_s + 's'
230
+ revenue_f = '%' + revenue_l.to_s + 's'
231
+ expense_f = '%' + expense_l.to_s + 's'
232
+ balance_f = '%' + balance_l.to_s + 's'
233
+ category_f = '%-' + category_l.to_s + 's'
234
+ comment_f = '%-' + comment_l.to_s + 's'
235
+
236
+ header = ''
237
+ header += '#' * entries_l + ' '
238
+ header += 'Date ' + ' ' * 7
239
+ header += title_f % 'Title' + ' '
240
+ header += revenue_f % 'Revenue' + ' '
241
+ header += expense_f % 'Expense' + ' '
242
+ header += balance_f % 'Balance'
243
+ header += ' ' + category_f % 'Category' if has_category_col
244
+ header += ' ' + comment_f % 'Comment' if has_comment_col
245
+
246
+ header_l = header.length
247
+ header.sub!(/ +$/, '')
248
+ puts header
249
+ puts '-' * header_l
250
+
251
+ revenue_total = 0.0
252
+ expense_total = 0.0
253
+ balance_total = 0.0
254
+ previous_date = ''
255
+ entry_no = 0
256
+ entries.sort.each do |day_name, day_items|
257
+ day_items.each do |entry|
258
+ entry_no += 1
259
+
260
+ title = entry['title']
261
+ title = title[0, 22] + '...' if title.length >= 25
262
+
263
+ revenue_total += entry['revenue']
264
+ expense_total += entry['expense']
265
+ balance_total += entry['balance']
266
+
267
+ category = entry['category'] == 'default' ? '' : entry['category']
268
+ has_category = category != ''
269
+
270
+ comment = entry['comment']
271
+ comment = comment[0, 22] + '...' if comment.length >= 25
272
+
273
+ out = ''
274
+ out += entries_f % entry_no
275
+ out += ' ' + '%10s' % (entry['date'] == previous_date ? '' : entry['date'])
276
+ out += ' ' + title_f % title
277
+ out += ' ' + revenue_f % (::TheFox::Wallet::NUMBER_FORMAT % entry['revenue'])
278
+ out += ' ' + expense_f % (::TheFox::Wallet::NUMBER_FORMAT % entry['expense'])
279
+ out += ' ' + balance_f % (::TheFox::Wallet::NUMBER_FORMAT % entry['balance'])
280
+ out += ' ' + category_f % category if has_category_col
281
+ out += ' ' + comment_f % comment if has_comment_col
282
+
283
+ out.sub!(/ +$/, '')
284
+ puts out
285
+
286
+ previous_date = entry['date']
287
+ end
288
+ end
289
+ puts
290
+
291
+ out = ''
292
+ out += ' ' * (12 + entries_l)
293
+ out += ' ' + title_f % 'TOTAL'
294
+ out += ' ' + revenue_f % (::TheFox::Wallet::NUMBER_FORMAT % revenue_total)
295
+ out += ' ' + expense_f % (::TheFox::Wallet::NUMBER_FORMAT % expense_total)
296
+ out += ' ' + balance_f % (::TheFox::Wallet::NUMBER_FORMAT % balance_total)
297
+ puts out
298
+ elsif command == 'cat'
299
+ categories = wallet.categories
300
+ puts 'categories(' + categories.count.to_s + '):'
301
+ categories.each do |category_item|
302
+ puts "\t" + category_item
303
+ end
304
+ elsif command == 'html'
305
+ puts 'generate html to ' + wallet.html_path + ' ...'
306
+ wallet.gen_html
307
+ puts 'generate html done'
308
+ elsif command == 'csv'
309
+ if path == ''
310
+ puts 'ERROR: Option --path is required for command "' + command + '"'
311
+ exit 1
312
+ end
313
+
314
+ if import || !export
315
+ puts 'import csv ' + path + ' ...'
316
+ wallet.import_csv_file path
317
+ puts 'import csv ' + path + ' done'
318
+
319
+ if path_is_temp
320
+ puts 'delete ' + path
321
+ File.unlink(path)
322
+ end
323
+ elsif export
324
+ puts 'export csv ' + path + ' ...'
325
+ wallet.export_csv_file path
326
+ puts 'export csv ' + path + ' done'
327
+ end
328
+ end