moneybook 0.1.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +130 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/moneybook +30 -10
- data/moneybook.gemspec +4 -4
- metadata +7 -7
- data/README.rdoc +0 -19
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
INTRO
|
2
|
+
=====
|
3
|
+
MoneyBook is a simple ruby command line application to track group expenses
|
4
|
+
and know exactly how much each one of your friends owes you from your last trip!
|
5
|
+
|
6
|
+
It's not super easy to use, nor is it meant to be (since I wrote it for myself), but
|
7
|
+
it's meant to be powerful and useful.
|
8
|
+
|
9
|
+
QUICK START
|
10
|
+
===========
|
11
|
+
|
12
|
+
to install simply do:
|
13
|
+
gem install moneybook
|
14
|
+
|
15
|
+
now to create your first moneybook file do:
|
16
|
+
moneybook new TITLE
|
17
|
+
|
18
|
+
and follow the onscreen instructions (give title, list of people in the group and optionally a currency exchange)
|
19
|
+
next edit the file as you wish and, when you want to know how things stand (how much
|
20
|
+
each one has to give/receive) simply do this:
|
21
|
+
moneybook parse moneybook_file.txt
|
22
|
+
|
23
|
+
If you want to see intermediate results (they will give you a better
|
24
|
+
understanding of the whys..) simply add a -i option, like this:
|
25
|
+
moneybook parse -i moneybook_file.txt
|
26
|
+
|
27
|
+
To see other available options do this:
|
28
|
+
moneybook parse --help
|
29
|
+
|
30
|
+
EXAMPLE FILE
|
31
|
+
============
|
32
|
+
|
33
|
+
### trip to paris ###
|
34
|
+
#### 2011-01-10 #####
|
35
|
+
#####################
|
36
|
+
|
37
|
+
PEOPLE: Jack Mary Kevin
|
38
|
+
|
39
|
+
# Jack payed 120$ for the tickets for all three..
|
40
|
+
flight tickets (120Jack)
|
41
|
+
|
42
|
+
# Jack payed 50$ and Mary 30$ for the dinner at hotel, and they didn't all spend the same:
|
43
|
+
# Kev got a dessert! He spent 10$ more than the others..
|
44
|
+
dinner at hotel (50Jack 30Mary) +10Kevin
|
45
|
+
|
46
|
+
# The museum was payed by Mary, and Kevin will pay only 5$ since he's a student.. Mary and
|
47
|
+
# Jack will then pay the rest (10$ each). Names can be abbrev: Kevin -> Kev -> K
|
48
|
+
museum (25Mary) 5Kev
|
49
|
+
|
50
|
+
# Knowing he was in debt, Kevin decides to give 50$ to Jack to start paying him back..
|
51
|
+
50Kevin -> Jack
|
52
|
+
|
53
|
+
the output to the example file above is:
|
54
|
+
|
55
|
+
### trip to paris ###
|
56
|
+
#### 2011-01-10 #####
|
57
|
+
#####################
|
58
|
+
|
59
|
+
|
60
|
+
# Jack payed 120$ for the tickets for all three..
|
61
|
+
==== flight tickets (120Jack) ====
|
62
|
+
total: 120.0
|
63
|
+
+-------+-------+-------+
|
64
|
+
| jack | kevin | mary |
|
65
|
+
+-------+-------+-------+
|
66
|
+
| 120.0 | | |
|
67
|
+
| 40.0 | 40.0 | 40.0 |
|
68
|
+
+-------+-------+-------+
|
69
|
+
| 80.0 | -40.0 | -40.0 |
|
70
|
+
+-------+-------+-------+
|
71
|
+
| 80.0 | -40.0 | -40.0 |
|
72
|
+
+-------+-------+-------+
|
73
|
+
|
74
|
+
# Jack payed 50$ and Mary 30$ for the dinner at hotel, and they didn't all spend the same:
|
75
|
+
# Kev got a dessert! He spent 10$ more than the others..
|
76
|
+
==== dinner at hotel (50Jack 30Mary) +10Kevin ====
|
77
|
+
total: 80.0
|
78
|
+
+-------+-------+-------+
|
79
|
+
| jack | kevin | mary |
|
80
|
+
+-------+-------+-------+
|
81
|
+
| 50.0 | | 30.0 |
|
82
|
+
| 23.3 | 33.3 | 23.3 |
|
83
|
+
+-------+-------+-------+
|
84
|
+
| 26.7 | -33.3 | 6.7 |
|
85
|
+
+-------+-------+-------+
|
86
|
+
| 106.7 | -73.3 | -33.3 |
|
87
|
+
+-------+-------+-------+
|
88
|
+
|
89
|
+
# The museum was payed by Mary, and Kevin will pay only 5$ since he's a student.. Mary and
|
90
|
+
# Jack will then pay the rest (10$ each). Names can be abbrev: Kevin -> Kev -> K
|
91
|
+
==== museum (25Mary) 5Kev ====
|
92
|
+
total: 25.0
|
93
|
+
+-------+-------+-------+
|
94
|
+
| jack | kevin | mary |
|
95
|
+
+-------+-------+-------+
|
96
|
+
| | | 25.0 |
|
97
|
+
| 10.0 | 5.0 | 10.0 |
|
98
|
+
+-------+-------+-------+
|
99
|
+
| -10.0 | -5.0 | 15.0 |
|
100
|
+
+-------+-------+-------+
|
101
|
+
| 96.7 | -78.3 | -18.3 |
|
102
|
+
+-------+-------+-------+
|
103
|
+
|
104
|
+
# Knowing he was in debt, Kevin decides to give 50$ to Jack to start paying him back..
|
105
|
+
==== 50Kevin -> Jack ====
|
106
|
+
total: 50.0
|
107
|
+
+-------+-------+-------+
|
108
|
+
| jack | kevin | mary |
|
109
|
+
+-------+-------+-------+
|
110
|
+
| | 50.0 | |
|
111
|
+
| 50.0 | | |
|
112
|
+
+-------+-------+-------+
|
113
|
+
| -50.0 | 50.0 | |
|
114
|
+
+-------+-------+-------+
|
115
|
+
| 46.7 | -28.3 | -18.3 |
|
116
|
+
+-------+-------+-------+
|
117
|
+
jack receives 46.67 spent 73.33 given 170.00
|
118
|
+
mary gives -18.33 spent 73.33 given 55.00
|
119
|
+
kevin gives -28.33 spent 78.33 given 50.00
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
each table is the result of each line in the source file, in each table there are 4 lines:
|
124
|
+
the first line is what's been payed [given], the second line is who should have payed it [spent],
|
125
|
+
then third line is the difference (so if the number is negative, the person owes money to
|
126
|
+
those whose number is positive), and the fourth line is the total balance that far.
|
127
|
+
|
128
|
+
At the end the total balance is also printed in words, kevin and mary both give something
|
129
|
+
to jack! And for each one is said how much he spent and how much he actually gave. The balance
|
130
|
+
is the difference: given - (spent + paybacks). Paybacks are not considered in the spent field.
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ require 'jeweler'
|
|
13
13
|
Jeweler::Tasks.new do |gem|
|
14
14
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
15
|
gem.name = "moneybook"
|
16
|
-
gem.homepage = "http://github.com/vircheck/
|
16
|
+
gem.homepage = "http://github.com/vircheck/MoneyBook"
|
17
17
|
gem.license = "MIT"
|
18
18
|
gem.summary = "keep track of money in a group"
|
19
19
|
gem.description = "keep track of money in a group"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bin/moneybook
CHANGED
@@ -11,6 +11,9 @@ require 'date'
|
|
11
11
|
require 'abbrev'
|
12
12
|
require 'pp'
|
13
13
|
|
14
|
+
REGEXP_COMP_LINE = /^\s*([\w\ \']+?)\s*\((.+)\)\s*(.+)?/
|
15
|
+
REGEXP_PAYBACK_LINE = /\A\s*(.+)\s*\-+\>\s*(.+)\Z/
|
16
|
+
|
14
17
|
class Array
|
15
18
|
def normalize_length
|
16
19
|
max = self.inject{|longest, current| longest.to_s.length > current.to_s.length ? longest : current }.to_s.length
|
@@ -31,6 +34,14 @@ def process_command(cmd)
|
|
31
34
|
opts.on("-i", "--[no-]intermediate", "Show intermediate computations") do |i|
|
32
35
|
options[:intermediate] = i
|
33
36
|
end
|
37
|
+
opts.on("-t", "--tail NUMBER", Integer, "Show intermediate computations only on last NUMBER lines") do |t|
|
38
|
+
options[:tail] = true
|
39
|
+
options[:tail_number] = t
|
40
|
+
end
|
41
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
42
|
+
puts opts
|
43
|
+
exit
|
44
|
+
end
|
34
45
|
end.parse!(args)
|
35
46
|
command_parse(options, args.last)
|
36
47
|
else
|
@@ -96,27 +107,36 @@ def command_parse(options, filename)
|
|
96
107
|
people_abbreviations = []
|
97
108
|
sq = [] #big table to make the computations..
|
98
109
|
f=File.open(filename,'r').read
|
110
|
+
### in case it's a UTF-16LE file...
|
99
111
|
if f[0]==255 && f[1]==254 then
|
100
112
|
f=Iconv.iconv('UTF-8', 'UTF-16LE', f)[0][3..-1]
|
101
113
|
puts "converting from UTF-16LE..."
|
102
114
|
end
|
115
|
+
### count number of computational lines (for the --tail option)
|
116
|
+
number_of_computational_lines = f.to_a.count{|x|x =~ REGEXP_PAYBACK_LINE || x =~ REGEXP_COMP_LINE}
|
117
|
+
reached_tail = !options[:tail]
|
118
|
+
current_comp_line = 0
|
119
|
+
### start computation
|
103
120
|
f.each_line{|line|
|
104
121
|
if line =~ /^\s*\#/ || line =~ /\A\s*\Z/
|
105
122
|
# this is interpreted as a comment line
|
106
|
-
puts line if intermediate
|
123
|
+
puts line if intermediate && reached_tail
|
107
124
|
elsif (m = line.match(/\A\s*PEOPLE\s*\:?\s*((\s+\w+)+)\s*\Z/).andand[1].andand.split(/\s+/).andand.delete_if{|x|x==""}) != nil then
|
108
125
|
m.each{|z|people<<z.to_s.downcase}
|
109
126
|
people_abbreviations = people.abbrev
|
127
|
+
puts "[people in list: #{people.join(', ')}]" if intermediate
|
110
128
|
elsif (currency_change == 0) && ((m = line.match(/\A\s*CHANGE\s*\:\s*([\.\d]+)\s*\Z/).andand[1].to_f) != 0) then
|
111
129
|
currency_change = m
|
112
|
-
puts "currency change is #{currency_change}"
|
130
|
+
puts "[currency change is #{currency_change}]" if intermediate
|
113
131
|
else
|
132
|
+
current_comp_line += 1
|
133
|
+
reached_tail = true if options[:tail] && current_comp_line > number_of_computational_lines - options[:tail_number]
|
114
134
|
original_str = false
|
115
|
-
if temp=line.match(
|
135
|
+
if temp=line.match(REGEXP_PAYBACK_LINE) then
|
116
136
|
original_str = line.strip
|
117
137
|
line = "PAYBACK (#{temp[1].to_s}) #{temp[2].to_s}"
|
118
138
|
end
|
119
|
-
x = line.strip.match(
|
139
|
+
x = line.strip.match(REGEXP_COMP_LINE).to_a.map{|z| z.to_s}
|
120
140
|
sq << {:name => x[1].to_s, :original_str => original_str || line.strip, :true_str => x[2].to_s, :virtual_str => x[3].to_s, :true => {}, :virtual => {}, :balance => {},
|
121
141
|
:true_total => 0, :virtual_total => 0}
|
122
142
|
c=sq.last
|
@@ -190,8 +210,8 @@ def command_parse(options, filename)
|
|
190
210
|
c[:balance][person] = c[:true][person] - c[:virtual][person]
|
191
211
|
}
|
192
212
|
### PRINT INTERMEDIATE RESULTS ###
|
193
|
-
if intermediate then
|
194
|
-
puts "==== #{c[:original_str].to_s} ===="
|
213
|
+
if intermediate && reached_tail then
|
214
|
+
puts "==== #{"%2d: " % current_comp_line} #{c[:original_str].to_s} ===="
|
195
215
|
puts "total: #{c[:true_total].to_s}"
|
196
216
|
mytable = table do |t|
|
197
217
|
t.headings = people.sort
|
@@ -210,16 +230,16 @@ def command_parse(options, filename)
|
|
210
230
|
}
|
211
231
|
### PRINT FINAL RESULTS ###
|
212
232
|
final = get_final(sq, people)
|
213
|
-
puts "in local currency:" if currency_change > 0
|
233
|
+
puts "=== in local currency:" if currency_change > 0
|
214
234
|
people_to_print = people.normalize_length
|
215
235
|
people.each_index{|i|
|
216
236
|
person = people[i]
|
217
|
-
puts "#{people_to_print[i]}
|
237
|
+
puts "#{people_to_print[i]} #{final[0][person] > 0 ? 'receives' : 'gives '} #{"% 8.2f" % final[0][person]} spent #{"% 8.2f" % final[1][person]} given #{"% 8.2f" % final[2][person]}"
|
218
238
|
}
|
219
|
-
puts "in converted currency:" if currency_change > 0
|
239
|
+
puts "=== in converted currency (multiplying by #{currency_change}):" if currency_change > 0
|
220
240
|
people.each_index{|i|
|
221
241
|
person = people[i]
|
222
|
-
puts "#{people_to_print[i]}
|
242
|
+
puts "#{people_to_print[i]} #{final[0][person] > 0 ? 'receives' : 'gives '} #{"% 8.2f" % (final[0][person]*currency_change)} spent #{"% 8.2f" % (final[1][person]*currency_change)} given #{"% 8.2f" % (final[2][person]*currency_change)}" if currency_change > 0
|
223
243
|
}
|
224
244
|
end
|
225
245
|
|
data/moneybook.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{moneybook}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["luca cioria"]
|
@@ -16,14 +16,14 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.executables = ["moneybook"]
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"LICENSE.txt",
|
19
|
-
"README.
|
19
|
+
"README.md"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
23
|
"Gemfile",
|
24
24
|
"Gemfile.lock",
|
25
25
|
"LICENSE.txt",
|
26
|
-
"README.
|
26
|
+
"README.md",
|
27
27
|
"Rakefile",
|
28
28
|
"VERSION",
|
29
29
|
"bin/moneybook",
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"test/helper.rb",
|
33
33
|
"test/test_moneybook.rb"
|
34
34
|
]
|
35
|
-
s.homepage = %q{http://github.com/vircheck/
|
35
|
+
s.homepage = %q{http://github.com/vircheck/MoneyBook}
|
36
36
|
s.licenses = ["MIT"]
|
37
37
|
s.require_paths = ["lib"]
|
38
38
|
s.rubygems_version = %q{1.4.2}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moneybook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- luca cioria
|
@@ -128,13 +128,13 @@ extensions: []
|
|
128
128
|
|
129
129
|
extra_rdoc_files:
|
130
130
|
- LICENSE.txt
|
131
|
-
- README.
|
131
|
+
- README.md
|
132
132
|
files:
|
133
133
|
- .document
|
134
134
|
- Gemfile
|
135
135
|
- Gemfile.lock
|
136
136
|
- LICENSE.txt
|
137
|
-
- README.
|
137
|
+
- README.md
|
138
138
|
- Rakefile
|
139
139
|
- VERSION
|
140
140
|
- bin/moneybook
|
@@ -143,7 +143,7 @@ files:
|
|
143
143
|
- test/helper.rb
|
144
144
|
- test/test_moneybook.rb
|
145
145
|
has_rdoc: true
|
146
|
-
homepage: http://github.com/vircheck/
|
146
|
+
homepage: http://github.com/vircheck/MoneyBook
|
147
147
|
licenses:
|
148
148
|
- MIT
|
149
149
|
post_install_message:
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= moneybook
|
2
|
-
|
3
|
-
Simple program to keep track of money in a ground, for example during a trip
|
4
|
-
|
5
|
-
== Contributing to moneybook
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
-
* Fork the project
|
10
|
-
* Start a feature/bugfix branch
|
11
|
-
* Commit and push until you are happy with your contribution
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2011 luca cioria. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|