reckon 0.9.5 → 0.9.6
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/Rakefile +2 -0
- data/bin/build-new-version.sh +2 -1
- data/lib/reckon/ledger_parser.rb +5 -5
- data/lib/reckon/version.rb +1 -1
- data/spec/reckon/ledger_parser_spec.rb +105 -77
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f1e02a1c5dde18325b138afa66518fc2516ea30e8c39eae5cdff2808f5f8bb4
|
4
|
+
data.tar.gz: 3d70362d3b8c8a3e6e147f4ca3466e35db7905e2bfe60571de9d219c330e23db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 707f23ee5da2df3837f0ae5c520e8b62d802d812dd9ab3acef72853c5e7d27d51b7aeaa269f89c66de1b73ab0e6891fb9ced9d3f59fb11c49d7679fa84c0e4f5
|
7
|
+
data.tar.gz: 73bbdf6dec9a09c23735695d8c192fde6b94df1d4931e7e79a256bed20a736e46d1503985dc29689f7f4fbaefd5c11413f4a41eb58516691b77daef99c2c8c75
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -8,6 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
8
8
|
|
9
9
|
task default: :spec
|
10
10
|
|
11
|
+
desc "Run specs and integration tests"
|
11
12
|
task :test_all do
|
12
13
|
puts "#{`ledger --version |head -n1`}"
|
13
14
|
puts "Running unit tests"
|
@@ -16,6 +17,7 @@ task :test_all do
|
|
16
17
|
Rake::Task["test_integration"].invoke
|
17
18
|
end
|
18
19
|
|
20
|
+
desc "Run integration tests"
|
19
21
|
task :test_integration do
|
20
22
|
cmd = 'prove -v ./spec/integration/test.sh'
|
21
23
|
raise 'Integration tests failed' unless system(cmd)
|
data/bin/build-new-version.sh
CHANGED
@@ -28,5 +28,6 @@ gem build reckon.gemspec
|
|
28
28
|
echo "Push changes and tags"
|
29
29
|
echo "git push && git push --tags"
|
30
30
|
echo "Push new gem"
|
31
|
-
echo "gem push reckon-$VERSION.gem"
|
31
|
+
echo "gem push reckon-$VERSION.gem --otp (ykman oath accounts code -s rubygems.org)"
|
32
|
+
echo "Publish draft github release"
|
32
33
|
gh release create "v$VERSION" "reckon-$VERSION.gem" --draft --generate-notes
|
data/lib/reckon/ledger_parser.rb
CHANGED
@@ -107,8 +107,8 @@
|
|
107
107
|
require 'rubygems'
|
108
108
|
|
109
109
|
module Reckon
|
110
|
+
# Parses ledger files
|
110
111
|
class LedgerParser
|
111
|
-
|
112
112
|
# ledger is an object that response to #each_line,
|
113
113
|
# (i.e. a StringIO or an IO object)
|
114
114
|
def initialize(options = {})
|
@@ -130,7 +130,7 @@ module Reckon
|
|
130
130
|
next if entry =~ /^\s*[#{comment_chars}]/
|
131
131
|
|
132
132
|
# (date, type, code, description), type and code are optional
|
133
|
-
if (m = entry.match(%r{^(\d+[
|
133
|
+
if (m = entry.match(%r{^(\d+[^\s]+)\s+([*!])?\s*(\([^)]+\))?\s*(.*)$}))
|
134
134
|
add_entry(entries, new_entry)
|
135
135
|
new_entry = {
|
136
136
|
date: try_parse_date(m[1]),
|
@@ -140,7 +140,7 @@ module Reckon
|
|
140
140
|
accounts: []
|
141
141
|
}
|
142
142
|
elsif entry =~ /^\s*$/ && new_entry[:date]
|
143
|
-
add_entry(entries,new_entry)
|
143
|
+
add_entry(entries, new_entry)
|
144
144
|
new_entry = {}
|
145
145
|
elsif new_entry[:date] && entry =~ /^\s+/
|
146
146
|
LOGGER.info("Adding new account #{entry}")
|
@@ -175,13 +175,13 @@ module Reckon
|
|
175
175
|
end
|
176
176
|
|
177
177
|
def format_row(row, line1, line2)
|
178
|
-
|
178
|
+
note = row[:note] ? "\t; row[:note]" : ""
|
179
|
+
out = "#{row[:pretty_date]}\t#{row[:description]}#{note}\n"
|
179
180
|
out += "\t#{line1.first}\t\t\t#{line1.last}\n"
|
180
181
|
out += "\t#{line2.first}\t\t\t#{line2.last}\n\n"
|
181
182
|
out
|
182
183
|
end
|
183
184
|
|
184
|
-
|
185
185
|
private
|
186
186
|
|
187
187
|
def add_entry(entries, entry)
|
data/lib/reckon/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#encoding: utf-8
|
2
|
+
# encoding: utf-8
|
3
3
|
|
4
4
|
require_relative "../spec_helper"
|
5
5
|
require 'rubygems'
|
@@ -28,27 +28,31 @@ describe Reckon::LedgerParser do
|
|
28
28
|
property_of do
|
29
29
|
Rantly do
|
30
30
|
description = Proc.new do
|
31
|
-
sized(15)
|
31
|
+
sized(15) {
|
32
|
+
string
|
33
|
+
}.tr(%q{'`:*\\}, '').gsub(/\s+/, ' ').gsub(/^[!;<\[( #{comment_chars}]+/, '')
|
32
34
|
end
|
33
35
|
currency = choose(*currencies) # to be consistent within the transaction
|
34
|
-
single_line_comments = ";#|%*".split('').map { |n|
|
36
|
+
single_line_comments = ";#|%*".split('').map { |n|
|
37
|
+
"#{n} #{call(description)}"
|
38
|
+
}
|
35
39
|
comments = ['', '; ', "\t;#{call(description)}", " ; #{call(description)}"]
|
36
40
|
date = Time.at(range(0, 1_581_389_644)).strftime(choose(*formats))
|
37
41
|
codes = [' ', " (#{string(:alnum).tr('()', '')}) "]
|
38
42
|
account = Proc.new { choose(*delimiters) + call(description) }
|
39
43
|
account_money = Proc.new do
|
40
|
-
|
44
|
+
sprintf("%.02f", (float * range(5, 10) + 1) * choose(1, -1))
|
41
45
|
end
|
42
46
|
account_line = Proc.new do
|
43
47
|
call(account) + \
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
choose(*delimiters) + \
|
49
|
+
currency + \
|
50
|
+
choose(*currency_delimiters) + \
|
51
|
+
call(account_money) + \
|
52
|
+
choose(*comments)
|
49
53
|
end
|
50
54
|
ledger = "#{date}#{choose(*types)}#{choose(*codes)}#{call(description)}\n"
|
51
|
-
range(1,5).times do
|
55
|
+
range(1, 5).times do
|
52
56
|
ledger += "#{call(account_line)}\n"
|
53
57
|
end
|
54
58
|
ledger += "#{call(account)}\n"
|
@@ -56,7 +60,10 @@ describe Reckon::LedgerParser do
|
|
56
60
|
ledger
|
57
61
|
end
|
58
62
|
end.check(1000) do |s|
|
59
|
-
filter_format = lambda { |n|
|
63
|
+
filter_format = lambda { |n|
|
64
|
+
[n['date'], n['desc'], n['name'],
|
65
|
+
sprintf("%.02f", n['amount'])]
|
66
|
+
}
|
60
67
|
headers = %w[date code desc name currency amount type commend]
|
61
68
|
safe_s = Shellwords.escape(s)
|
62
69
|
|
@@ -64,7 +71,8 @@ describe Reckon::LedgerParser do
|
|
64
71
|
actual = CSV.parse(lp_csv, headers: headers).map(&filter_format)
|
65
72
|
|
66
73
|
ledger_csv = `echo #{safe_s} | ledger csv --date-format '%Y/%m/%d' -f - `
|
67
|
-
expected = CSV.parse(ledger_csv.gsub('\"', '""'),
|
74
|
+
expected = CSV.parse(ledger_csv.gsub('\"', '""'),
|
75
|
+
headers: headers).map(&filter_format)
|
68
76
|
expected.length.times do |i|
|
69
77
|
expect(actual[i]).to eq(expected[i])
|
70
78
|
end
|
@@ -72,34 +80,35 @@ describe Reckon::LedgerParser do
|
|
72
80
|
end
|
73
81
|
|
74
82
|
it 'should filter block comments' do
|
75
|
-
ledger =
|
76
|
-
1970/11/01 Dinner should show up
|
77
|
-
|
78
|
-
|
83
|
+
ledger = <<~HERE
|
84
|
+
1970/11/01 Dinner should show up
|
85
|
+
Assets:Checking -123.00
|
86
|
+
Expenses:Restaurants
|
79
87
|
|
80
|
-
comment
|
88
|
+
comment
|
81
89
|
|
82
|
-
1970/11/01 Lunch should NOT show up
|
83
|
-
|
84
|
-
|
90
|
+
1970/11/01 Lunch should NOT show up
|
91
|
+
Assets:Checking -12.00
|
92
|
+
Expenses:Restaurants
|
85
93
|
|
86
|
-
end comment
|
87
|
-
HERE
|
94
|
+
end comment
|
95
|
+
HERE
|
88
96
|
entries = Reckon::LedgerParser.new.parse(StringIO.new(ledger))
|
89
97
|
expect(entries.length).to eq(1)
|
90
98
|
expect(entries.first[:desc]).to eq('Dinner should show up')
|
91
|
-
|
92
99
|
end
|
93
100
|
|
94
101
|
it 'should transaction comments' do
|
95
|
-
ledger =
|
96
|
-
2020-03-27 AMZN Mktp USX999H3203; Shopping; Sale
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
HERE
|
102
|
+
ledger = <<~HERE
|
103
|
+
2020-03-27 AMZN Mktp USX999H3203; Shopping; Sale
|
104
|
+
Expenses:Household $82.77
|
105
|
+
Liabilities:ChaseSapphire -$81.77
|
106
|
+
# END FINANCE SCRIPT OUTPUT Thu 02 Apr 2020 12:05:54 PM EDT
|
107
|
+
HERE
|
101
108
|
entries = Reckon::LedgerParser.new.parse(StringIO.new(ledger))
|
102
|
-
expect(entries.first[:accounts].map { |n|
|
109
|
+
expect(entries.first[:accounts].map { |n|
|
110
|
+
n[:name]
|
111
|
+
}).to eq(['Expenses:Household', 'Liabilities:ChaseSapphire'])
|
103
112
|
expect(entries.first[:accounts].size).to eq(2)
|
104
113
|
expect(entries.length).to eq(1)
|
105
114
|
end
|
@@ -123,80 +132,99 @@ HERE
|
|
123
132
|
@entries.last[:accounts].last[:name].should == "Assets:Bank:Checking"
|
124
133
|
@entries.last[:accounts].last[:amount].should == -20.24
|
125
134
|
end
|
135
|
+
|
136
|
+
it "should parse dot-separated dates" do
|
137
|
+
ledger = <<~HERE
|
138
|
+
2024.03.12 groceries; 11223344556; 32095205940
|
139
|
+
assets:bank:spending 530.00 NOK
|
140
|
+
assets:bank:co:groceries
|
141
|
+
|
142
|
+
2024.03.13 autosave; 11223344555; 11223344556
|
143
|
+
assets:bank:savings
|
144
|
+
assets:bank:spending -10.00 NOK
|
145
|
+
HERE
|
146
|
+
options = { ledger_date_format: '%Y.%m.%d' }
|
147
|
+
entries = Reckon::LedgerParser.new(options).parse(StringIO.new(ledger))
|
148
|
+
expect(entries.first[:date]).to eq(Date.new(2024, 3, 12))
|
149
|
+
expect(entries.last[:date]).to eq(Date.new(2024, 3, 13))
|
150
|
+
expect(entries.length).to eq(2)
|
151
|
+
end
|
126
152
|
end
|
127
153
|
|
128
154
|
describe "balance" do
|
129
155
|
it "it should balance out missing account values" do
|
130
156
|
@ledger.send(:balance, [
|
131
|
-
|
132
|
-
|
133
|
-
|
157
|
+
{ :name => "Account1", :amount => 1000 },
|
158
|
+
{ :name => "Account2", :amount => nil }
|
159
|
+
]).should == [{ :name => "Account1", :amount => 1000 },
|
160
|
+
{ :name => "Account2", :amount => -1000 }]
|
134
161
|
end
|
135
162
|
|
136
163
|
it "it should balance out missing account values" do
|
137
164
|
@ledger.send(:balance, [
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
165
|
+
{ :name => "Account1", :amount => 1000 },
|
166
|
+
{ :name => "Account2", :amount => 100 },
|
167
|
+
{ :name => "Account3", :amount => -200 },
|
168
|
+
{ :name => "Account4", :amount => nil }
|
169
|
+
]).should == [
|
170
|
+
{ :name => "Account1", :amount => 1000 },
|
171
|
+
{ :name => "Account2", :amount => 100 },
|
172
|
+
{ :name => "Account3", :amount => -200 },
|
173
|
+
{ :name => "Account4", :amount => -900 }
|
174
|
+
]
|
148
175
|
end
|
149
176
|
|
150
177
|
it "it should work on normal values too" do
|
151
178
|
@ledger.send(:balance, [
|
152
|
-
|
153
|
-
|
154
|
-
|
179
|
+
{ :name => "Account1", :amount => 1000 },
|
180
|
+
{ :name => "Account2", :amount => -1000 }
|
181
|
+
]).should == [{ :name => "Account1", :amount => 1000 },
|
182
|
+
{ :name => "Account2", :amount => -1000 }]
|
155
183
|
end
|
156
184
|
end
|
157
185
|
|
158
186
|
# Data
|
159
187
|
|
160
|
-
EXAMPLE_LEDGER = (
|
161
|
-
= /^Expenses:Books/
|
162
|
-
|
188
|
+
EXAMPLE_LEDGER = (<<~LEDGER).strip
|
189
|
+
= /^Expenses:Books/
|
190
|
+
(Liabilities:Taxes) -0.10
|
163
191
|
|
164
|
-
~ Monthly
|
165
|
-
|
166
|
-
|
192
|
+
~ Monthly
|
193
|
+
Assets:Bank:Checking $500.00
|
194
|
+
Income:Salary
|
167
195
|
|
168
|
-
2004-05-01 * Checking balance
|
169
|
-
|
170
|
-
|
196
|
+
2004-05-01 * Checking balance
|
197
|
+
Assets:Bank:Checking $1,000.00
|
198
|
+
Equity:Opening Balances
|
171
199
|
|
172
|
-
2004-05-01 * Checking balance
|
173
|
-
|
174
|
-
|
200
|
+
2004-05-01 * Checking balance
|
201
|
+
Assets:Bank:Checking €1,000.00
|
202
|
+
Equity:Opening Balances
|
175
203
|
|
176
|
-
2004-05-01 * Checking balance
|
177
|
-
|
178
|
-
|
204
|
+
2004-05-01 * Checking balance
|
205
|
+
Assets:Bank:Checking 1,000.00 SEK
|
206
|
+
Equity:Opening Balances
|
179
207
|
|
180
|
-
2004/05/01 * Investment balance
|
181
|
-
|
182
|
-
|
208
|
+
2004/05/01 * Investment balance
|
209
|
+
Assets:Brokerage 50 AAPL @ $30.00
|
210
|
+
Equity:Opening Balances
|
183
211
|
|
184
|
-
; blah
|
185
|
-
!account blah
|
212
|
+
; blah
|
213
|
+
!account blah
|
186
214
|
|
187
|
-
!end
|
215
|
+
!end
|
188
216
|
|
189
|
-
D $1,000
|
217
|
+
D $1,000
|
190
218
|
|
191
|
-
2004/05/14 * Pay day
|
192
|
-
|
193
|
-
|
219
|
+
2004/05/14 * Pay day
|
220
|
+
Assets:Bank:Checking $500.00
|
221
|
+
Income:Salary
|
194
222
|
|
195
|
-
2004/05/27 Book Store
|
196
|
-
|
197
|
-
|
198
|
-
2004/05/27 (100) Credit card company
|
199
|
-
|
200
|
-
|
223
|
+
2004/05/27 Book Store
|
224
|
+
Expenses:Books $20.00
|
225
|
+
Liabilities:MasterCard
|
226
|
+
2004/05/27 (100) Credit card company
|
227
|
+
Liabilities:MasterCard $20.24
|
228
|
+
Assets:Bank:Checking
|
201
229
|
LEDGER
|
202
230
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reckon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Cantino
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-03-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|