thefox-wallet 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/wallet +4 -3
- data/lib/wallet/command.rb +3 -2
- data/lib/wallet/command_add.rb +6 -1
- data/lib/wallet/command_clear.rb +17 -0
- data/lib/wallet/command_html.rb +5 -7
- data/lib/wallet/version.rb +2 -2
- data/lib/wallet/wallet.rb +83 -42
- data/lib/wallet.rb +3 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 371beb2557b5d4b13a93fa29ec2a4314d3988253
|
4
|
+
data.tar.gz: 557b1b3fd12d91150875cae58ca6a7226f2aaa1a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 626f9cc9eb31732942d00247bed4059b0652923a11b842e46b54803817c6abd7a3ca489ad0acc441d44f6d158910e0553c0afc2d9654ea51920287e29063f378
|
7
|
+
data.tar.gz: 7fe39b9adf2b48a9d95d1cc89e1e4b3f2c7152ff3159442c3191b36b2962bc4cae53f12787540df836ea26b005efd20fff1d0d2db45364dff18dccd8d4c3ad0d
|
data/bin/wallet
CHANGED
@@ -17,10 +17,11 @@ opts = OptionParser.new do |o|
|
|
17
17
|
o.separator('Commands:')
|
18
18
|
o.separator('')
|
19
19
|
o.separator(' add Add a new entry')
|
20
|
-
o.separator(' list List entries')
|
21
20
|
o.separator(' categories List categories')
|
22
|
-
o.separator('
|
21
|
+
o.separator(' clear Clear temp and cache files')
|
23
22
|
o.separator(' csv Import/Export CSV file')
|
23
|
+
o.separator(' html Generate HTML files')
|
24
|
+
o.separator(' list List entries')
|
24
25
|
o.separator(' vi Import per VIM editor')
|
25
26
|
o.separator('')
|
26
27
|
|
@@ -72,7 +73,7 @@ opts = OptionParser.new do |o|
|
|
72
73
|
@options[:is_export] = true
|
73
74
|
end
|
74
75
|
|
75
|
-
o.on('-p', '--path <path>', 'Path used for csv import/export.') do |path|
|
76
|
+
o.on('-p', '--path <path>', 'Path used for csv import/export and html directory path.') do |path|
|
76
77
|
@options[:path] = path
|
77
78
|
end
|
78
79
|
|
data/lib/wallet/command.rb
CHANGED
@@ -35,10 +35,11 @@ module TheFox::Wallet
|
|
35
35
|
def self.create_by_name(name, options = nil)
|
36
36
|
classes = [
|
37
37
|
AddCommand,
|
38
|
-
ListCommand,
|
39
38
|
CategoriesCommand,
|
40
|
-
|
39
|
+
ClearCommand,
|
41
40
|
CsvCommand,
|
41
|
+
HtmlCommand,
|
42
|
+
ListCommand,
|
42
43
|
]
|
43
44
|
|
44
45
|
classes.each do |cclass|
|
data/lib/wallet/command_add.rb
CHANGED
@@ -16,7 +16,12 @@ module TheFox::Wallet
|
|
16
16
|
print "title: [#{@options[:entry_title]}] "
|
17
17
|
title_t = STDIN.gets.strip
|
18
18
|
if title_t.length > 0
|
19
|
-
@options[:entry_title]
|
19
|
+
if @options[:entry_title] =~ /%d/
|
20
|
+
@options[:entry_title] = @options[:entry_title] % title_t.split(',').map{ |s| s.strip }
|
21
|
+
else
|
22
|
+
@options[:entry_title] = title_t
|
23
|
+
end
|
24
|
+
puts "title: #{@options[:entry_title]}"
|
20
25
|
end
|
21
26
|
|
22
27
|
print "date: [#{@options[:entry_date]}] "
|
data/lib/wallet/command_html.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
|
2
|
+
require 'pathname'
|
3
|
+
|
2
4
|
module TheFox::Wallet
|
3
5
|
|
4
6
|
class HtmlCommand < Command
|
@@ -6,17 +8,13 @@ module TheFox::Wallet
|
|
6
8
|
NAME = 'html'
|
7
9
|
|
8
10
|
def run
|
9
|
-
wallet = Wallet.new(@options[:wallet_path])
|
10
|
-
wallet.logger = @options[:logger]
|
11
|
-
|
12
|
-
html_path = Pathname.new('html').expand_path(wallet.dir_path)
|
13
11
|
if @options[:path]
|
14
12
|
html_path = Pathname.new(@options[:path]).expand_path
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
wallet.
|
19
|
-
@options[:
|
15
|
+
wallet = Wallet.new(@options[:wallet_path])
|
16
|
+
wallet.logger = @options[:logger]
|
17
|
+
wallet.generate_html(html_path, @options[:entry_date_start], @options[:entry_date_end], @options[:entry_category])
|
20
18
|
end
|
21
19
|
|
22
20
|
end
|
data/lib/wallet/version.rb
CHANGED
data/lib/wallet/wallet.rb
CHANGED
@@ -6,6 +6,7 @@ require 'yaml'
|
|
6
6
|
require 'yaml/store'
|
7
7
|
require 'csv'
|
8
8
|
require 'pathname'
|
9
|
+
require 'fileutils'
|
9
10
|
require 'ostruct' # OpenStruct use to generate HTML.
|
10
11
|
# require 'pp'
|
11
12
|
|
@@ -25,6 +26,7 @@ module TheFox
|
|
25
26
|
@dir_path_basename_s = @dir_path_basename.to_s
|
26
27
|
@data_path = Pathname.new('data').expand_path(@dir_path)
|
27
28
|
@tmp_path = Pathname.new('tmp').expand_path(@dir_path)
|
29
|
+
@html_path = Pathname.new('html').expand_path(@dir_path)
|
28
30
|
|
29
31
|
@has_transaction = false
|
30
32
|
@transaction_files = Hash.new
|
@@ -35,7 +37,7 @@ module TheFox
|
|
35
37
|
@entries_index_is_loaded = false
|
36
38
|
|
37
39
|
Signal.trap('SIGINT') do
|
38
|
-
|
40
|
+
#@logger.warn('received SIGINT. break ...') if @logger
|
39
41
|
@exit = true
|
40
42
|
end
|
41
43
|
end
|
@@ -302,7 +304,15 @@ module TheFox
|
|
302
304
|
categories_a
|
303
305
|
end
|
304
306
|
|
305
|
-
|
307
|
+
##
|
308
|
+
# Generate HTML files from date_start to date_end.
|
309
|
+
def generate_html(html_path = nil, date_start = nil, date_end = nil, category = nil)
|
310
|
+
# @FIXME use @exit on all loops in this function
|
311
|
+
|
312
|
+
html_path ||= @html_path
|
313
|
+
|
314
|
+
@logger.info("generate html to #{html_path} ...") if @logger
|
315
|
+
|
306
316
|
create_dirs
|
307
317
|
|
308
318
|
unless html_path.exist?
|
@@ -336,6 +346,7 @@ module TheFox
|
|
336
346
|
categories_total_balance = Hash.new
|
337
347
|
categories_available.map{ |item| categories_total_balance[item] = 0.0 }
|
338
348
|
|
349
|
+
# Ignore the html directory.
|
339
350
|
gitignore_file_path = Pathname.new('.gitignore').expand_path(html_path)
|
340
351
|
gitignore_file = File.open(gitignore_file_path, 'w')
|
341
352
|
gitignore_file.write('*')
|
@@ -366,21 +377,10 @@ module TheFox
|
|
366
377
|
')
|
367
378
|
css_file.close
|
368
379
|
|
369
|
-
|
370
|
-
index_file = File.open(index_file_path, 'w')
|
371
|
-
index_file.write('
|
372
|
-
<html>
|
373
|
-
<head>
|
374
|
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
375
|
-
<title>' << @dir_path_basename_s << '</title>
|
376
|
-
<link rel="stylesheet" href="style.css" type="text/css" />
|
377
|
-
</head>
|
378
|
-
<body>
|
379
|
-
<h1>' << @dir_path_basename_s << '</h1>
|
380
|
-
<p>Generated @ ' << DateTime.now.strftime('%F %T') << ' by <a href="' << HOMEPAGE << '">' << NAME << '</a> v' << VERSION << '</p>
|
381
|
-
')
|
382
|
-
|
380
|
+
# Use this for index.html.
|
383
381
|
years_total = Hash.new
|
382
|
+
|
383
|
+
# Iterate over all years.
|
384
384
|
years(date_start, date_end).each do |year|
|
385
385
|
year_s = year.to_s
|
386
386
|
year_file_name_s = "year_#{year}.html"
|
@@ -458,23 +458,24 @@ module TheFox
|
|
458
458
|
entry_n = 0
|
459
459
|
data = YAML.load_file(file_path)
|
460
460
|
|
461
|
-
|
461
|
+
# Determine if the html file should be updated.
|
462
|
+
write_html = false
|
462
463
|
if html_options['changes'][file_name_s]
|
463
464
|
if html_options['changes'][file_name_s]['updated_at'] != data['meta']['updated_at']
|
464
465
|
html_options['changes'][file_name_s]['updated_at'] = data['meta']['updated_at']
|
465
|
-
|
466
|
+
write_html = true
|
466
467
|
end
|
467
468
|
else
|
468
469
|
html_options['changes'][file_name_s] = {
|
469
470
|
'updated_at' => data['meta']['updated_at'],
|
470
471
|
}
|
471
|
-
|
472
|
+
write_html = true
|
472
473
|
end
|
473
474
|
unless month_file_path.exist?
|
474
|
-
|
475
|
+
write_html = true
|
475
476
|
end
|
476
477
|
|
477
|
-
if
|
478
|
+
if write_html
|
478
479
|
@logger.debug("file: #{month_file_name_s} (from #{file_name_s})") if @logger
|
479
480
|
|
480
481
|
month_file = File.open(month_file_path, 'w')
|
@@ -509,13 +510,7 @@ module TheFox
|
|
509
510
|
entry_date = Date.parse(entry['date'])
|
510
511
|
entry_date_s = entry_date.strftime('%d.%m.%y')
|
511
512
|
|
512
|
-
|
513
|
-
date_end_oor = date_end < entry_date
|
514
|
-
|
515
|
-
if category && !categories_available.include?(entry['category']) ||
|
516
|
-
date_start > entry_date ||
|
517
|
-
date_end < entry_date
|
518
|
-
|
513
|
+
if category && !categories_available.include?(entry['category'])
|
519
514
|
next
|
520
515
|
end
|
521
516
|
|
@@ -532,7 +527,7 @@ module TheFox
|
|
532
527
|
category_out = entry['category'] == 'default' ? ' ' : entry['category']
|
533
528
|
comment_out = entry['comment'] == '' ? ' ' : entry['comment']
|
534
529
|
|
535
|
-
if
|
530
|
+
if write_html
|
536
531
|
month_file.write('
|
537
532
|
<tr>
|
538
533
|
<td valign="top" class="left">' << entry_n.to_s << '</td>
|
@@ -569,7 +564,7 @@ module TheFox
|
|
569
564
|
if balance_month < 0
|
570
565
|
balance_class = 'red'
|
571
566
|
end
|
572
|
-
if
|
567
|
+
if write_html
|
573
568
|
month_file.write('
|
574
569
|
<tr>
|
575
570
|
<th> </th>
|
@@ -671,6 +666,21 @@ module TheFox
|
|
671
666
|
|
672
667
|
years_total.sort.inject(0.0){ |sum, item| item[1].balance_total = (sum + item[1].balance).round(NUMBER_ROUND) }
|
673
668
|
|
669
|
+
index_file_path = Pathname.new('index.html').expand_path(html_path)
|
670
|
+
index_file = File.open(index_file_path, 'w')
|
671
|
+
index_file.write('
|
672
|
+
<html>
|
673
|
+
<head>
|
674
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
675
|
+
<title>' << @dir_path_basename_s << '</title>
|
676
|
+
<link rel="stylesheet" href="style.css" type="text/css" />
|
677
|
+
</head>
|
678
|
+
<body>
|
679
|
+
<h1>' << @dir_path_basename_s << '</h1>
|
680
|
+
<p>Generated @ ' << DateTime.now.strftime('%F %T') << ' by <a href="' << HOMEPAGE << '">' << NAME << '</a> v' << VERSION << '</p>
|
681
|
+
')
|
682
|
+
|
683
|
+
# Write total to index.html file.
|
674
684
|
index_file.write('
|
675
685
|
<table class="list">
|
676
686
|
<tr>
|
@@ -680,6 +690,8 @@ module TheFox
|
|
680
690
|
<th class="right">Balance</th>
|
681
691
|
<th class="right">Balance ∑</th>
|
682
692
|
</tr>')
|
693
|
+
|
694
|
+
# Write years total to index.html file.
|
683
695
|
years_total.each do |year_name, year_data|
|
684
696
|
index_file.write('
|
685
697
|
<tr>
|
@@ -694,18 +706,16 @@ module TheFox
|
|
694
706
|
balance_total = years_total.inject(0.0){ |sum, item| sum + item[1].balance }
|
695
707
|
|
696
708
|
index_file.write('
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
')
|
708
|
-
index_file.write('
|
709
|
+
<tr>
|
710
|
+
<th class="left"><b>TOTAL</b></th>
|
711
|
+
<th class="right">' << NUMBER_FORMAT % years_total.inject(0.0){ |sum, item| sum + item[1].revenue } << '</th>
|
712
|
+
<th class="right red">' << NUMBER_FORMAT % years_total.inject(0.0){ |sum, item| sum + item[1].expense } << '</th>
|
713
|
+
<th class="right ' << (balance_total < 0 ? 'red' : '') << '">' << NUMBER_FORMAT % balance_total << '</th>
|
714
|
+
<th> </th>
|
715
|
+
</tr>
|
716
|
+
</table>
|
717
|
+
|
718
|
+
<p><img src="total.png"></p>
|
709
719
|
</body>
|
710
720
|
</html>
|
711
721
|
')
|
@@ -723,11 +733,13 @@ module TheFox
|
|
723
733
|
end
|
724
734
|
totaldat_file_c = totaldat_file_c.join("\n")
|
725
735
|
|
736
|
+
# DAT file for GNUPlot.
|
726
737
|
totaldat_file_path = Pathname.new('total.dat').expand_path(@tmp_path)
|
727
738
|
totaldat_file = File.new(totaldat_file_path, 'w')
|
728
739
|
totaldat_file.write(totaldat_file_c)
|
729
740
|
totaldat_file.close
|
730
741
|
|
742
|
+
# Generate image with GNUPlot.
|
731
743
|
png_file_path = Pathname.new('total.png').expand_path(html_path)
|
732
744
|
|
733
745
|
gnuplot_file_path = Pathname.new('total.gp').expand_path(@tmp_path)
|
@@ -755,6 +767,8 @@ module TheFox
|
|
755
767
|
gnuplot_file.close
|
756
768
|
|
757
769
|
system("gnuplot #{gnuplot_file_path} &> /dev/null")
|
770
|
+
|
771
|
+
@logger.info('generate html done') if @logger
|
758
772
|
end
|
759
773
|
|
760
774
|
def import_csv_file(file_path)
|
@@ -864,6 +878,33 @@ module TheFox
|
|
864
878
|
@entries_by_ids[id]
|
865
879
|
end
|
866
880
|
|
881
|
+
def clear
|
882
|
+
c = 0
|
883
|
+
|
884
|
+
# Take the standard html path instead of --path option.
|
885
|
+
# Do not provide the functionality to delete files from --path.
|
886
|
+
# If a user uses --path to generate html files outside of the
|
887
|
+
# wallet path the user needs to manual remove these files.
|
888
|
+
children = @tmp_path.children + @html_path.children
|
889
|
+
|
890
|
+
children.each do |child|
|
891
|
+
|
892
|
+
if child.basename.to_s[0] == '.'
|
893
|
+
# Ignore 'hidden' files like .gitignore.
|
894
|
+
next
|
895
|
+
end
|
896
|
+
|
897
|
+
# puts "child #{child}"
|
898
|
+
FileUtils.rm_rf(child)
|
899
|
+
|
900
|
+
c += 1
|
901
|
+
if c > 100
|
902
|
+
# If something goes wrong do not delete to whole harddisk. ;)
|
903
|
+
break
|
904
|
+
end
|
905
|
+
end
|
906
|
+
end
|
907
|
+
|
867
908
|
private
|
868
909
|
|
869
910
|
def create_dirs
|
data/lib/wallet.rb
CHANGED
@@ -4,7 +4,8 @@ require 'wallet/wallet'
|
|
4
4
|
require 'wallet/entry'
|
5
5
|
require 'wallet/command'
|
6
6
|
require 'wallet/command_add'
|
7
|
-
require 'wallet/command_list'
|
8
7
|
require 'wallet/command_categories'
|
9
|
-
require 'wallet/
|
8
|
+
require 'wallet/command_clear'
|
10
9
|
require 'wallet/command_csv'
|
10
|
+
require 'wallet/command_html'
|
11
|
+
require 'wallet/command_list'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thefox-wallet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Mayer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- lib/wallet/command.rb
|
103
103
|
- lib/wallet/command_add.rb
|
104
104
|
- lib/wallet/command_categories.rb
|
105
|
+
- lib/wallet/command_clear.rb
|
105
106
|
- lib/wallet/command_csv.rb
|
106
107
|
- lib/wallet/command_html.rb
|
107
108
|
- lib/wallet/command_list.rb
|
@@ -130,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
130
131
|
version: '0'
|
131
132
|
requirements: []
|
132
133
|
rubyforge_project:
|
133
|
-
rubygems_version: 2.6.
|
134
|
+
rubygems_version: 2.6.10
|
134
135
|
signing_key:
|
135
136
|
specification_version: 4
|
136
137
|
summary: Finances Tracking
|