reckon 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13ec00f6b1277d98d6df6264af61020310ab5bf61197412a116a2f61901e6214
4
- data.tar.gz: cf1b1e21a64fac57a5796b64f53da971a48c4bb3f439be94fd847441c5b36a0f
3
+ metadata.gz: 5984a4f8cd36d4e14f013c14bb111725f8681b90768b6710679820d1325a02e5
4
+ data.tar.gz: b392d89078a7679f01a344799512ec0467cfe8cad101374a5b8fd198c7e39480
5
5
  SHA512:
6
- metadata.gz: 450fb569cf8509563edd5fb36239965b9cd29b28d544399bcc10cf510a146d68fb56c3dd1737a1904cd7f23ab3453128d522fb07159068bbc6ed2d44cb0fe1d6
7
- data.tar.gz: 461bade5035f16c278131102df52b91e39a365b18c3e73875730616b5489f07f7c0528094da13a06558791b4238d1d6cc495452b14c917b15eef5eea2719e909
6
+ metadata.gz: ae9b8348e93294d45354f1b96045305dd480b23cd34dcaca3f958fcbc866582000faa1711ea6cbb552578ffe98f126943221b98af298757b86e6dfa54c623f9d
7
+ data.tar.gz: f43e7128e198c9b73fc40b148cbe281d0bc02aeec90d576615e24fe98789a1846553121319152bffb3a9ca966fd26e1b3916da90480979c5d55106e06dbfe7f2
@@ -34,10 +34,10 @@ jobs:
34
34
  - 2.3.7
35
35
  steps:
36
36
  - uses: actions/checkout@v2
37
+ - name: Update package
38
+ run: sudo apt-get update
37
39
  - name: Install packages
38
- run: sudo apt-get -y install ledger hledger
39
- - name: Install bundler
40
- run: sudo gem install -v 1.17.3 bundler
40
+ run: sudo apt-get -y install ledger hledger expect
41
41
  - name: Set up Ruby
42
42
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
43
43
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
@@ -45,6 +45,6 @@ jobs:
45
45
  # uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
46
46
  with:
47
47
  ruby-version: ${{ matrix.ruby-version }}
48
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
48
+ bundler-cache: true # runs 'bundle install' and caches installed gems
49
49
  - name: Run tests
50
50
  run: bundle exec rake test_all
data/CHANGELOG.md CHANGED
@@ -1,6 +1,21 @@
1
1
  # Changelog
2
2
 
3
- ## [v0.7.1](https://github.com/cantino/reckon/tree/v0.7.1) (2021-02-06)
3
+ ## [v0.7.2](https://github.com/cantino/reckon/tree/v0.7.2) (2021-04-22)
4
+
5
+ [Full Changelog](https://github.com/cantino/reckon/compare/v0.7.1...v0.7.2)
6
+
7
+ **Closed issues:**
8
+
9
+ - \[feature request\] Better format for large transactions [\#108](https://github.com/cantino/reckon/issues/108)
10
+ - cosine similarity not comparing documents correctly [\#106](https://github.com/cantino/reckon/issues/106)
11
+
12
+ **Merged pull requests:**
13
+
14
+ - Add thousands separator in money output. Fixes \#108. [\#109](https://github.com/cantino/reckon/pull/109) ([benprew](https://github.com/benprew))
15
+ - Cosine similarity should use all docs tokens. not just matched tokens. [\#107](https://github.com/cantino/reckon/pull/107) ([benprew](https://github.com/benprew))
16
+ - Test getting expect working with actions [\#105](https://github.com/cantino/reckon/pull/105) ([benprew](https://github.com/benprew))
17
+
18
+ ## [v0.7.1](https://github.com/cantino/reckon/tree/v0.7.1) (2021-02-07)
4
19
 
5
20
  [Full Changelog](https://github.com/cantino/reckon/compare/v0.7.0...v0.7.1)
6
21
 
@@ -135,7 +150,6 @@
135
150
  - Fix bugs in ledger file parsing. Fixes \#56. [\#81](https://github.com/cantino/reckon/pull/81) ([benprew](https://github.com/benprew))
136
151
  - Better file encoding suggestions [\#80](https://github.com/cantino/reckon/pull/80) ([benprew](https://github.com/benprew))
137
152
  - :bug: fix matching algorithm, add logging and a spec helper. Fixes \#73 [\#79](https://github.com/cantino/reckon/pull/79) ([benprew](https://github.com/benprew))
138
- - bug: invalid header lines should be ignored, not parsed. [\#78](https://github.com/cantino/reckon/pull/78) ([benprew](https://github.com/benprew))
139
153
  - convert default date format to iso8601 [\#77](https://github.com/cantino/reckon/pull/77) ([benprew](https://github.com/benprew))
140
154
  - Fix rspec failure for ruby 2.3 and 2.4 [\#69](https://github.com/cantino/reckon/pull/69) ([BlackEdder](https://github.com/BlackEdder))
141
155
  - Allow setting of money and date columns by index [\#67](https://github.com/cantino/reckon/pull/67) ([cantino](https://github.com/cantino))
@@ -188,6 +202,7 @@
188
202
 
189
203
  **Merged pull requests:**
190
204
 
205
+ - bug: invalid header lines should be ignored, not parsed. [\#78](https://github.com/cantino/reckon/pull/78) ([benprew](https://github.com/benprew))
191
206
  - Better ISO 8601 dates support [\#49](https://github.com/cantino/reckon/pull/49) ([vzctl](https://github.com/vzctl))
192
207
  - Unattended mode and custom tokens support [\#47](https://github.com/cantino/reckon/pull/47) ([vzctl](https://github.com/vzctl))
193
208
  - \[RFC\] Implement issue \#40: Tab completion [\#46](https://github.com/cantino/reckon/pull/46) ([BlackEdder](https://github.com/BlackEdder))
@@ -201,6 +216,7 @@
201
216
 
202
217
  - Fix --encoding option [\#41](https://github.com/cantino/reckon/pull/41) ([mamciek](https://github.com/mamciek))
203
218
  - Bumped version number [\#37](https://github.com/cantino/reckon/pull/37) ([BlackEdder](https://github.com/BlackEdder))
219
+ - Ing csv [\#30](https://github.com/cantino/reckon/pull/30) ([BlackEdder](https://github.com/BlackEdder))
204
220
 
205
221
  ## [v0.3.9](https://github.com/cantino/reckon/tree/v0.3.9) (2014-02-20)
206
222
 
@@ -217,15 +233,12 @@
217
233
  - Date format [\#35](https://github.com/cantino/reckon/pull/35) ([BlackEdder](https://github.com/BlackEdder))
218
234
  - Added example from a french bank [\#34](https://github.com/cantino/reckon/pull/34) ([BlackEdder](https://github.com/BlackEdder))
219
235
  - Austrian example [\#33](https://github.com/cantino/reckon/pull/33) ([BlackEdder](https://github.com/BlackEdder))
220
- - Ing csv [\#30](https://github.com/cantino/reckon/pull/30) ([BlackEdder](https://github.com/BlackEdder))
221
236
  - Further improvements in nationwide csv handling [\#29](https://github.com/cantino/reckon/pull/29) ([BlackEdder](https://github.com/BlackEdder))
222
237
  - Refactor: Add money class [\#28](https://github.com/cantino/reckon/pull/28) ([BlackEdder](https://github.com/BlackEdder))
223
238
  - Initial split of CSVparser from class App [\#27](https://github.com/cantino/reckon/pull/27) ([BlackEdder](https://github.com/BlackEdder))
224
239
  - Updated version of pull request 24: Allow for other currency symbols while calculating money\_score [\#26](https://github.com/cantino/reckon/pull/26) ([BlackEdder](https://github.com/BlackEdder))
225
240
  - Change double column detection [\#23](https://github.com/cantino/reckon/pull/23) ([BlackEdder](https://github.com/BlackEdder))
226
- - Added optional argument to contains\_header to skip multiple header lines [\#22](https://github.com/cantino/reckon/pull/22) ([BlackEdder](https://github.com/BlackEdder))
227
241
  - Add a Bitdeli Badge to README [\#20](https://github.com/cantino/reckon/pull/20) ([bitdeli-chef](https://github.com/bitdeli-chef))
228
- - Update README to show latest usage info [\#19](https://github.com/cantino/reckon/pull/19) ([purcell](https://github.com/purcell))
229
242
 
230
243
  ## [v0.3.8](https://github.com/cantino/reckon/tree/v0.3.8) (2013-07-03)
231
244
 
@@ -242,6 +255,7 @@
242
255
 
243
256
  **Merged pull requests:**
244
257
 
258
+ - Update README to show latest usage info [\#19](https://github.com/cantino/reckon/pull/19) ([purcell](https://github.com/purcell))
245
259
  - add support for spanish dates dd/mm/yyyy closes \#13 [\#14](https://github.com/cantino/reckon/pull/14) ([mauromorales](https://github.com/mauromorales))
246
260
  - fix issue showing true when parsing the currency option related to \#7 [\#12](https://github.com/cantino/reckon/pull/12) ([mauromorales](https://github.com/mauromorales))
247
261
 
@@ -251,6 +265,7 @@
251
265
 
252
266
  **Merged pull requests:**
253
267
 
268
+ - Added optional argument to contains\_header to skip multiple header lines [\#22](https://github.com/cantino/reckon/pull/22) ([BlackEdder](https://github.com/BlackEdder))
254
269
  - Updated the sources to allow for custom curreny [\#11](https://github.com/cantino/reckon/pull/11) ([ghost](https://github.com/ghost))
255
270
  - Add --account option on the commandline [\#10](https://github.com/cantino/reckon/pull/10) ([copiousfreetime](https://github.com/copiousfreetime))
256
271
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reckon (0.7.1)
4
+ reckon (0.7.2)
5
5
  chronic (>= 0.3.0)
6
6
  highline (>= 1.5.2)
7
7
  rchardet (>= 1.8.0)
data/Rakefile CHANGED
@@ -17,6 +17,6 @@ task :test_all do
17
17
  end
18
18
 
19
19
  task :integration_tests do
20
- puts `./spec/integration/test.sh`
21
- raise 'Integration tests failed' if $CHILD_STATUS.exitstatus != 0
20
+ cmd = 'prove -v ./spec/integration/test.sh'
21
+ raise 'Integration tests failed' unless system(cmd)
22
22
  end
@@ -5,7 +5,7 @@ set -e
5
5
  VERSION=$1
6
6
 
7
7
  echo "Install github_changelog_generator"
8
- gem install --user github_changelog_generator
8
+ # gem install --user github_changelog_generator
9
9
 
10
10
  echo "Update 'lib/reckon/version.rb'"
11
11
  echo -e "module Reckon\n VERSION=\"$VERSION\"\nend" > lib/reckon/version.rb
data/bin/reckon CHANGED
@@ -13,6 +13,9 @@ reckon = Reckon::App.new(options)
13
13
 
14
14
  if options[:print_table]
15
15
  reckon.output_table
16
+ if options[:table_output_file]
17
+ File.open(options[:table_output_file], 'w') { |fh| reckon.output_table fh }
18
+ end
16
19
  exit
17
20
  end
18
21
 
data/lib/reckon/app.rb CHANGED
@@ -20,10 +20,10 @@ module Reckon
20
20
  learn!
21
21
  end
22
22
 
23
- def interactive_output(str)
23
+ def interactive_output(str, fh = $stdout)
24
24
  return if options[:unattended]
25
25
 
26
- puts str
26
+ fh.puts str
27
27
  end
28
28
 
29
29
  def learn!
@@ -161,7 +161,7 @@ module Reckon
161
161
  rows.sort_by { |n| [n[:date], -n[:money], n[:description]] }.each { |row| yield row }
162
162
  end
163
163
 
164
- def print_transaction(rows)
164
+ def print_transaction(rows, fh = $stdout)
165
165
  str = "\n"
166
166
  header = %w[Date Amount Description Note]
167
167
  maxes = header.map(&:length)
@@ -185,7 +185,7 @@ module Reckon
185
185
  str += "\n"
186
186
  end
187
187
 
188
- interactive_output str
188
+ interactive_output str, fh
189
189
  end
190
190
 
191
191
  def ask_account_question(msg, row)
@@ -280,12 +280,12 @@ module Reckon
280
280
  exit
281
281
  end
282
282
 
283
- def output_table
283
+ def output_table(fh = $stdout)
284
284
  rows = []
285
285
  each_row_backwards do |row|
286
286
  rows << row
287
287
  end
288
- print_transaction(rows)
288
+ print_transaction(rows, fh)
289
289
  end
290
290
  end
291
291
  end
@@ -1,47 +1,52 @@
1
1
  require 'matrix'
2
2
  require 'set'
3
3
 
4
- # Implementation of consine similarity using TF-IDF for vectorization.
5
- # Used to suggest which account a transaction should be assigned to
4
+ # Implementation of cosine similarity using TF-IDF for vectorization.
5
+ #
6
+ # In information retrieval, tf–idf, short for term frequency–inverse document frequency,
7
+ # is a numerical statistic that is intended to reflect how important a word is to a
8
+ # document in a collection or corpus
9
+ #
10
+ # Cosine Similarity a measurement to determine how similar 2 documents are to each other.
11
+ #
12
+ # These weights and measures are used to suggest which account a transaction should be
13
+ # assigned to.
6
14
  module Reckon
7
15
  class CosineSimilarity
16
+ DocumentInfo = Struct.new(:tokens, :accounts)
17
+
8
18
  def initialize(options)
19
+ @docs = DocumentInfo.new({}, {})
9
20
  @options = options
10
- @tokens = {}
11
- @accounts = Hash.new(0)
12
21
  end
13
22
 
14
23
  def add_document(account, doc)
15
- tokenize(doc).each do |n|
24
+ tokens = tokenize(doc)
25
+ LOGGER.info "doc tokens: #{tokens}"
26
+ tokens.each do |n|
16
27
  (token, count) = n
17
28
 
18
- @tokens[token] ||= {}
19
- @tokens[token][account] ||= 0
20
- @tokens[token][account] += count
21
- @accounts[account] += count
29
+ @docs.tokens[token] ||= Hash.new(0)
30
+ @docs.tokens[token][account] += count
31
+ @docs.accounts[account] ||= Hash.new(0)
32
+ @docs.accounts[account][token] += count
22
33
  end
23
34
  end
24
35
 
25
36
  # find most similar documents to query
26
37
  def find_similar(query)
27
- (query_scores, corpus_scores) = td_idf_scores_for(query)
38
+ LOGGER.info "find_similar #{query}"
28
39
 
29
- query_vector = Vector.elements(query_scores, false)
40
+ accounts = docs_to_check(query).map do |a|
41
+ [a, tfidf(@docs.accounts[a])]
42
+ end
30
43
 
31
- # For each doc, calculate the similarity to the query
32
- suggestions = corpus_scores.map do |account, scores|
33
- acct_vector = Vector.elements(scores, false)
44
+ q = tfidf(tokenize(query))
34
45
 
35
- acct_query_dp = acct_vector.inner_product(query_vector)
36
- # similarity is a float between 1 and -1, where 1 is exactly the same and -1 is
37
- # exactly opposite
38
- # see https://en.wikipedia.org/wiki/Cosine_similarity
39
- # cos(theta) = (A . B) / (||A|| ||B||)
40
- # where A . B is the "dot product" and ||A|| is the magnitude of A
41
- # ruby has the 'matrix' library we can use to do these calculations.
46
+ suggestions = accounts.map do |a, d|
42
47
  {
43
- similarity: acct_query_dp / (acct_vector.magnitude * query_vector.magnitude),
44
- account: account,
48
+ similarity: calc_similarity(q, d),
49
+ account: a
45
50
  }
46
51
  end.select { |n| n[:similarity] > 0 }.sort_by { |n| -n[:similarity] }
47
52
 
@@ -52,50 +57,51 @@ module Reckon
52
57
 
53
58
  private
54
59
 
55
- def td_idf_scores_for(query)
56
- query_tokens = tokenize(query)
57
- corpus = Set.new
58
- corpus_scores = {}
59
- query_scores = []
60
- num_docs = @accounts.length
61
-
62
- query_tokens.each do |n|
63
- (token, _count) = n
64
- next unless @tokens[token]
65
- corpus = corpus.union(Set.new(@tokens[token].keys))
60
+ def docs_to_check(query)
61
+ return tokenize(query).reduce(Set.new) do |corpus, t|
62
+ corpus.union(Set.new(@docs.tokens[t[0]]&.keys))
66
63
  end
64
+ end
67
65
 
68
- query_tokens.each do |n|
69
- (token, count) = n
70
-
71
- # if no other docs have token, ignore it
72
- next unless @tokens[token]
66
+ def tfidf(tokens)
67
+ scores = {}
73
68
 
74
- ## First, calculate scores for our query as we're building scores for the corpus
75
- query_scores << calc_tf_idf(
76
- count,
77
- query_tokens.length,
78
- @tokens[token].length,
79
- num_docs
69
+ tokens.each do |t, n|
70
+ scores[t] = calc_tf_idf(
71
+ n,
72
+ tokens.length,
73
+ @docs.tokens[t]&.length&.to_f || 0,
74
+ @docs.accounts.length
80
75
  )
81
-
82
- ## Next, calculate for the corpus, where our "account" is a document
83
- corpus.each do |account|
84
- corpus_scores[account] ||= []
85
-
86
- corpus_scores[account] << calc_tf_idf(
87
- (@tokens[token][account] || 0),
88
- @accounts[account].to_f,
89
- @tokens[token].length.to_f,
90
- num_docs
91
- )
92
- end
93
76
  end
94
- [query_scores, corpus_scores]
77
+
78
+ return scores
95
79
  end
96
80
 
97
- def calc_tf_idf(token_count, num_words_in_doc, df, num_docs)
81
+ # Cosine similarity is used to compare how similar 2 documents are. Returns a float
82
+ # between 1 and -1, where 1 is exactly the same and -1 is exactly opposite.
83
+ #
84
+ # see https://en.wikipedia.org/wiki/Cosine_similarity
85
+ # cos(theta) = (A . B) / (||A|| ||B||)
86
+ # where A . B is the "dot product" and ||A|| is the magnitude of A
87
+ #
88
+ # The variables A and B are the set of unique terms in q and d.
89
+ #
90
+ # For example, when q = "big red balloon" and d ="small green balloon" then the
91
+ # variables are (big,red,balloon,small,green) and a = (1,1,1,0,0) and b =
92
+ # (0,0,1,1,1).
93
+ #
94
+ # query and doc are hashes of token => tf/idf score
95
+ def calc_similarity(query, doc)
96
+ tokens = Set.new(query.keys + doc.keys)
97
+
98
+ a = Vector.elements(tokens.map { |n| query[n] || 0 }, false)
99
+ b = Vector.elements(tokens.map { |n| doc[n] || 0 }, false)
100
+
101
+ return a.inner_product(b) / (a.magnitude * b.magnitude)
102
+ end
98
103
 
104
+ def calc_tf_idf(token_count, num_words_in_doc, df, num_docs)
99
105
  # tf(t,d) = count of t in d / number of words in d
100
106
  tf = token_count / num_words_in_doc.to_f
101
107
 
@@ -109,14 +115,13 @@ module Reckon
109
115
  end
110
116
 
111
117
  def tokenize(str)
112
- mk_tokens(str).inject(Hash.new(0)) do |memo, n|
118
+ mk_tokens(str).each_with_object(Hash.new(0)) do |n, memo|
113
119
  memo[n] += 1
114
- memo
115
120
  end.to_a
116
121
  end
117
122
 
118
123
  def mk_tokens(str)
119
- str.downcase.tr(';', ' ').tr("'", '').split(/[^a-z0-9.]+/)
124
+ str.downcase.tr(';', ' ').tr("'", '').split(/[^a-z0-9.]+/).reject(&:empty?)
120
125
  end
121
126
  end
122
127
  end
data/lib/reckon/money.rb CHANGED
@@ -50,11 +50,18 @@ module Reckon
50
50
  return @amount_raw[0] == '-' ? @amount_raw[1..-1] : "-#{@amount_raw}"
51
51
  end
52
52
 
53
- if @suffixed
54
- (@amount >= 0 ? " " : "") + sprintf("%0.2f #{@currency}", @amount * (negate ? -1 : 1))
55
- else
56
- (@amount >= 0 ? " " : "") + sprintf("%0.2f", @amount * (negate ? -1 : 1)).gsub(/^((\-)|)(?=\d)/, "\\1#{@currency}")
57
- end
53
+ amt = pretty_amount(@amount * (negate ? -1 : 1))
54
+ amt = if @suffixed
55
+ "#{amt} #{@currency}"
56
+ else
57
+ amt.gsub(/^((-)|)(?=\d)/, "\\1#{@currency}")
58
+ end
59
+
60
+ return (@amount >= 0 ? " " : "") + amt
61
+ end
62
+
63
+ def pretty_amount(amount)
64
+ sprintf("%0.2f", amount).reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
58
65
  end
59
66
 
60
67
  def parse(value, options = {})
@@ -85,6 +85,10 @@ module Reckon
85
85
  options[:account_tokens_file] = a
86
86
  end
87
87
 
88
+ opts.on("", "--table-output-file FILE") do |n|
89
+ options[:table_output_file] = n
90
+ end
91
+
88
92
  options[:default_into_account] = 'Expenses:Unknown'
89
93
  opts.on("", "--default-into-account NAME", "Default into account") do |a|
90
94
  options[:default_into_account] = a
@@ -1,3 +1,3 @@
1
1
  module Reckon
2
- VERSION="0.7.1"
2
+ VERSION="0.7.2"
3
3
  end
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+
5
+ require 'reckon'
6
+
7
+ ledger_file = ARGV[0]
8
+ account = ARGV[1]
9
+ seed = ARGV[2] ? ARGV[2].to_i : Random.new_seed
10
+
11
+ ledger = Reckon::LedgerParser.new(File.read(ledger_file))
12
+ matcher = Reckon::CosineSimilarity.new({})
13
+
14
+ train = []
15
+ test = []
16
+
17
+ def has_account(account, entry)
18
+ entry[:accounts].map { |a| a[:name] }.include?(account)
19
+ end
20
+
21
+ entries = ledger.entries.select { |e| has_account(account, e) }
22
+
23
+ r = Random.new(seed)
24
+ entries.length.times do |i|
25
+ r.rand < 0.9 ? train << i : test << i
26
+ end
27
+
28
+ train.each do |i|
29
+ entry = entries[i]
30
+ entry[:accounts].each do |a|
31
+ matcher.add_document(
32
+ a[:name],
33
+ [entry[:desc], a[:amount]].join(" ")
34
+ )
35
+ end
36
+ end
37
+
38
+ result = [nil] * test.length
39
+ test.each do |i|
40
+ entry = entries[i]
41
+ matches = matcher.find_similar(
42
+ entry[:desc] + " " + entry[:accounts][0][:amount].to_s
43
+ )
44
+
45
+ if !matches[0] || !has_account(matches[0][:account], entry)
46
+ result[i] = [entry, matches]
47
+ end
48
+ end
49
+
50
+ # pp result.compact
51
+ puts "using #{seed} as random seed"
52
+ puts "true: #{result.count(nil)} false: #{result.count { |v| !v.nil? }}"
@@ -1,5 +1,5 @@
1
1
  2003-12-24 CREDIT; Some Company vendorpymt PPD ID: 5KL3832735
2
- Assets:Bank:Checking $2105.00
2
+ Assets:Bank:Checking $2,105.00
3
3
  Income:Unknown
4
4
 
5
5
  2004-12-24 CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL
@@ -15,11 +15,11 @@
15
15
  Expenses:Unknown
16
16
 
17
17
  2007-12-24 CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563
18
- Assets:Bank:Checking $1558.52
18
+ Assets:Bank:Checking $1,558.52
19
19
  Income:Unknown
20
20
 
21
21
  2008-12-24 CREDIT; Some Company vendorpymt PPD ID: 59728JSL20
22
- Assets:Bank:Checking $3520.00
22
+ Assets:Bank:Checking $3,520.00
23
23
  Income:Unknown
24
24
 
25
25
  2009-12-24 DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/expect -f
2
+
3
+
4
+ set timeout 7
5
+ match_max 100000
6
+ expect "What is this account named in Ledger |Assets:Bank:Checking|?\r
7
+ \[1G▽\[6n"
8
+ send -- "\[45;2R"
9
+ expect -exact "\[1G\[K\[6n"
10
+ send -- "\[45;1R"
11
+ expect "\[1G\[K\[1G\[1G"
12
+ send -- "T"
13
+ expect "\[1GT\[K\[1G\[2G"
14
+ send -- "e"
15
+ expect "\[1GTe\[K\[1G\[3G"
16
+ send -- "s"
17
+ expect "\[1GTes\[K\[1G\[4G"
18
+ send -- "t"
19
+ expect "\[1GTest\[K\[1G\[5G"
20
+ send -- ":"
21
+ expect "\[1GTest:\[K\[1G\[6G"
22
+ send -- ":"
23
+ expect "\[1GTest::\[K\[1G\[7G"
24
+ send -- "B"
25
+ expect "\[1GTest::B\[K\[1G\[8G"
26
+ send -- "a"
27
+ expect "\[1GTest::Ba\[K\[1G\[9G"
28
+ send -- "n"
29
+ expect "\[1GTest::Ban\[K\[1G\[10G"
30
+ send -- "k"
31
+ expect "\[1GTest::Bank\[K\[1G\[11G"
32
+ send -- "\r"
33
+ expect eof
@@ -0,0 +1,11 @@
1
+
2
+ Date | Amount | Description | Note |
3
+ 2003-12-24 | $2,105.00 | CREDIT; Some Company vendorpymt PPD ID: 5KL3832735 | |
4
+ 2004-12-24 | -$116.22 | CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL | |
5
+ 2005-12-24 | -$0.96 | DEBIT; WEBSITE-BALANCE-10DEC09 12 12/10WEBSITE-BAL | |
6
+ 2006-12-24 | $0.23 | DEBIT; WEBSITE-BALANCE-17DEC09 12 12/17WEBSITE-BAL | |
7
+ 2007-12-24 | $1,558.52 | CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563 | |
8
+ 2008-12-24 | $3,520.00 | CREDIT; Some Company vendorpymt PPD ID: 59728JSL20 | |
9
+ 2009-12-24 | -$7.00 | DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04 | |
10
+ 2010-12-24 | -$20.00 | CHECK; CHECK 2656 | |
11
+ 2011-12-24 | -$85.00 | DEBIT; HOST 037196321563 MO 12/22SLICEHOST | |
@@ -0,0 +1,9 @@
1
+ DEBIT,2011/12/24,"HOST 037196321563 MO 12/22SLICEHOST",($85.00)
2
+ CHECK,2010/12/24,"CHECK 2656",($20.00)
3
+ DEBIT,2009/12/24,"GITHUB 041287430274 CA 12/22GITHUB 04",($7.00)
4
+ CREDIT,2008/12/24,"Some Company vendorpymt PPD ID: 59728JSL20",$3520.00
5
+ CREDIT,2007/12/24,"Blarg BLARG REVENUE PPD ID: 00jah78563",$1558.52
6
+ DEBIT,2006/12/24,"WEBSITE-BALANCE-17DEC09 12 12/17WEBSITE-BAL",$.23
7
+ DEBIT,2005/12/24,"WEBSITE-BALANCE-10DEC09 12 12/10WEBSITE-BAL",($0.96)
8
+ CREDIT,2004/12/24,"PAYPAL TRANSFER PPD ID: PAYPALSDSL",($116.22)
9
+ CREDIT,2003/12/24,"Some Company vendorpymt PPD ID: 5KL3832735",$2105.00
@@ -0,0 +1 @@
1
+ -f input.csv -p
@@ -8,7 +8,7 @@
8
8
 
9
9
  2013-06-19 2013-06-24; Buy; ISHARES S&P/TSX CAPPED REIT IN; XRE; 300; 15.90; CDN; CAD
10
10
  Income:Unknown
11
- Assets:Bank:Checking -$4779.95
11
+ Assets:Bank:Checking -$4,779.95
12
12
 
13
13
  2013-06-27 2013-06-27; Dividend; ICICI BK SPONSORED ADR; IBN; 100; USD
14
14
  Assets:Bank:Checking $66.70
@@ -19,7 +19,7 @@
19
19
  Income:Unknown
20
20
 
21
21
  2014-01-07 2014-01-10; Sell; BMO NASDAQ 100 EQTY HEDGED TO; ZQQ; -300; 27.44; CDN; CAD
22
- Assets:Bank:Checking $8222.05
22
+ Assets:Bank:Checking $8,222.05
23
23
  Income:Unknown
24
24
 
25
25
  2014-01-07 2014-01-07; Interest; BMO S&P/TSX EQUAL WEIGHT BKS I; ZEB; 250; CAD
@@ -1,5 +1,5 @@
1
1
  2009-12-10 CREDIT; Some Company vendorpymt PPD ID: 5KL3832735
2
- Assets:Bank:Checking $2105.00
2
+ Assets:Bank:Checking $2,105.00
3
3
  Income:Unknown
4
4
 
5
5
  2009-12-11 CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL
@@ -15,11 +15,11 @@
15
15
  Assets:Bank:Checking -$12.23
16
16
 
17
17
  2009-12-23 CREDIT; Some Company vendorpymt PPD ID: 59728JSL20
18
- Assets:Bank:Checking $3520.00
18
+ Assets:Bank:Checking $3,520.00
19
19
  Income:Unknown
20
20
 
21
21
  2009-12-23 CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563
22
- Assets:Bank:Checking $1558.52
22
+ Assets:Bank:Checking $1,558.52
23
23
  Income:Unknown
24
24
 
25
25
  2009-12-24 DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04
@@ -1,5 +1,5 @@
1
1
  2009-12-10 CREDIT; Some Company vendorpymt PPD ID: 5KL3832735
2
- Assets:Bank:Checking $2105.00
2
+ Assets:Bank:Checking $2,105.00
3
3
  Income:Default
4
4
 
5
5
  2009-12-11 CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL
@@ -15,11 +15,11 @@
15
15
  Assets:Bank:Checking -$12.23
16
16
 
17
17
  2009-12-23 CREDIT; Some Company vendorpymt PPD ID: 59728JSL20
18
- Assets:Bank:Checking $3520.00
18
+ Assets:Bank:Checking $3,520.00
19
19
  Income:Default
20
20
 
21
21
  2009-12-23 CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563
22
- Assets:Bank:Checking $1558.52
22
+ Assets:Bank:Checking $1,558.52
23
23
  Income:Default
24
24
 
25
25
  2009-12-24 DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04
@@ -1,5 +1,5 @@
1
1
  2009-12-10 CREDIT; Some Company vendorpymt PPD ID: 5KL3832735
2
- Assets:Bank:Checking $2105.00
2
+ Assets:Bank:Checking $2,105.00
3
3
  Income:Unknown
4
4
 
5
5
  2009-12-11 CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL
@@ -15,11 +15,11 @@
15
15
  Assets:Bank:Checking -$12.23
16
16
 
17
17
  2009-12-23 CREDIT; Some Company vendorpymt PPD ID: 59728JSL20
18
- Assets:Bank:Checking $3520.00
18
+ Assets:Bank:Checking $3,520.00
19
19
  Income:Unknown
20
20
 
21
21
  2009-12-23 CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563
22
- Assets:Bank:Checking $1558.52
22
+ Assets:Bank:Checking $1,558.52
23
23
  Income:Unknown
24
24
 
25
25
  2009-12-24 DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04
@@ -1,5 +1,5 @@
1
1
  2009-12-10 CREDIT; Some Company vendorpymt PPD ID: 5KL3832735
2
- Assets:Bank:Checking $2105.00
2
+ Assets:Bank:Checking $2,105.00
3
3
  Income:Unknown
4
4
 
5
5
  2009-12-11 CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL
@@ -15,11 +15,11 @@
15
15
  Assets:Bank:Checking -$12.23
16
16
 
17
17
  2009-12-23 CREDIT; Some Company vendorpymt PPD ID: 59728JSL20
18
- Assets:Bank:Checking $3520.00
18
+ Assets:Bank:Checking $3,520.00
19
19
  Income:Unknown
20
20
 
21
21
  2009-12-23 CREDIT; Blarg BLARG REVENUE PPD ID: 00jah78563
22
- Assets:Bank:Checking $1558.52
22
+ Assets:Bank:Checking $1,558.52
23
23
  Income:Unknown
24
24
 
25
25
  2009-12-24 DEBIT; GITHUB 041287430274 CA 12/22GITHUB 04
@@ -4,7 +4,7 @@
4
4
 
5
5
  2012-09-12 Dankort-nota B.J. TRADING E 14660; 12-09-2012; 26164,80
6
6
  Expenses:Unknown
7
- Assets:Bank:Checking -$3452.90
7
+ Assets:Bank:Checking -$3,452.90
8
8
 
9
9
  2012-10-12 Visa kob DKK 995,00 WWW.ASOS.COM 00000; 12-10-2012; 27939,54
10
10
  Expenses:Unknown
@@ -3,7 +3,7 @@
3
3
  Income:Unknown
4
4
 
5
5
  2012-11-01 Proventos; 496774
6
- Assets:Bank:Checking $1000.00
6
+ Assets:Bank:Checking $1,000.00
7
7
  Income:Unknown
8
8
 
9
9
  2012-11-01 0000-9; Transferência on line - 01/11 4885 256620-6 XXXXXXXXXXXXX; 224885000256620
@@ -1,5 +1,5 @@
1
1
  2009-11-04 TRANSFER CREDIT INTERNET TRANSFER; INTERNET TRANSFER; 1234.00
2
- Assets:Bank:Checking $1234.00
2
+ Assets:Bank:Checking $1,234.00
3
3
  Income:Unknown
4
4
 
5
5
  2009-11-10 TRANSFER DEBIT INTERNET TRANSFER; INTERNET TRANSFER MORTGAGE; 0.00
@@ -16,5 +16,5 @@
16
16
 
17
17
  2011-11-04 TRANSFER DEBIT INTERNET TRANSFER; INTERNET TRANSFER SAV TO MECU; 0.00
18
18
  Income:Unknown
19
- Assets:Bank:Checking -$1234.00
19
+ Assets:Bank:Checking -$1,234.00
20
20
 
@@ -4,10 +4,12 @@
4
4
 
5
5
  set -Euo pipefail
6
6
 
7
+
7
8
  SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
8
9
  TEST_DIFF=""
9
10
  OUTPUT=""
10
- RECKON_CMD="env RUBYLIB=$SCRIPT_DIR/../../lib:$RUBYLIB reckon -v"
11
+ RECKON_CMD="reckon -v"
12
+ export RUBYLIB=$SCRIPT_DIR/../../lib:${RUBYLIB:-}
11
13
  export PATH="$SCRIPT_DIR/../../bin:$PATH"
12
14
 
13
15
  main () {
@@ -21,16 +23,20 @@ main () {
21
23
 
22
24
  echo > test.log
23
25
 
26
+ NUM_TESTS=$(echo "$TESTS" |wc -l)
27
+
28
+ echo "1..$NUM_TESTS"
29
+
30
+ I=1
31
+
24
32
  for t in $TESTS; do
25
- OUTPUT_FILE=$(mktemp)
26
33
  TEST_DIR=$(dirname "$t")
27
34
  pushd "$TEST_DIR" >/dev/null || exit 1
28
- echo "$TEST_DIR Running..."
29
- TEST_CMD="$RECKON_CMD -o $OUTPUT_FILE $(cat test_args)"
30
- TEST_LOG=$(eval "$TEST_CMD" 2>&1)
31
- ERROR=0
32
-
33
- compare_output "$OUTPUT_FILE"
35
+ if [[ -e "cli_input.exp" ]]; then
36
+ cli_test
37
+ else
38
+ unattended_test
39
+ fi
34
40
 
35
41
  popd >/dev/null || exit 1
36
42
  # have to save output after popd
@@ -38,11 +44,41 @@ main () {
38
44
  echo -e "TEST_CMD\n$TEST_LOG" >> test.log
39
45
 
40
46
  if [[ $ERROR -ne 0 ]]; then
47
+ echo -e "not ok $I - $TEST_DIR"
48
+ tail -n25 test.log
41
49
  exit 1
50
+ else
51
+ echo -e "ok $I - $TEST_DIR"
42
52
  fi
53
+ I=$(($I + 1))
43
54
  done
44
55
  }
45
56
 
57
+ cli_test () {
58
+ OUTPUT_FILE=$(mktemp)
59
+ TEST_CMD="$RECKON_CMD --table-output-file $OUTPUT_FILE $(cat test_args)"
60
+ TEST_CMD="expect -d -c 'spawn $TEST_CMD' cli_input.exp"
61
+ TEST_LOG=$(eval "$TEST_CMD" 2>&1)
62
+ ERROR=0
63
+ TEST_DIFF=$(diff -u "$OUTPUT_FILE" "expected_output")
64
+
65
+ # ${#} is character length, test that there was no output from diff
66
+ if [ ${#TEST_DIFF} -eq 0 ]; then
67
+ ERROR=0
68
+ else
69
+ ERROR=1
70
+ fi
71
+ }
72
+
73
+ unattended_test() {
74
+ OUTPUT_FILE=$(mktemp)
75
+ TEST_CMD="$RECKON_CMD -o $OUTPUT_FILE $(cat test_args)"
76
+ TEST_LOG=$(eval "$TEST_CMD" 2>&1)
77
+ ERROR=0
78
+
79
+ compare_output "$OUTPUT_FILE"
80
+ }
81
+
46
82
  test_fail () {
47
83
  STATUS=$?
48
84
  if [[ $STATUS -ne 0 ]]; then
@@ -55,7 +91,13 @@ compare_output_for () {
55
91
  OUTPUT_FILE=$1
56
92
  LEDGER=$2
57
93
 
58
- TEST_DIFF=$(diff -u <($LEDGER -f output.ledger r --date-format %F 2>&1) <($LEDGER -f "$OUTPUT_FILE" r --date-format %F 2>&1) )
94
+ EXPECTED_FILE=$(mktemp)
95
+ ACTUAL_FILE=$(mktemp)
96
+
97
+ $LEDGER -f output.ledger r >"$EXPECTED_FILE" 2>&1 || return 1
98
+ $LEDGER -f output.ledger r >"$ACTUAL_FILE" 2>&1 || return 1
99
+
100
+ TEST_DIFF=$(diff -u "$EXPECTED_FILE" "$ACTUAL_FILE")
59
101
 
60
102
  # ${#} is character length, test that there was no output from diff
61
103
  if [ ${#TEST_DIFF} -eq 0 ]; then
@@ -69,11 +111,9 @@ compare_output () {
69
111
  OUTPUT_FILE=$1
70
112
 
71
113
  for n in {ledger,hledger}; do
72
- echo -n " - $n..."
73
114
  if compare_output_for "$OUTPUT_FILE" "$n"; then
74
- echo "SUCCESS!"
115
+ ERROR=0
75
116
  else
76
- echo "FAILED!"
77
117
  ERROR=1
78
118
  return 0
79
119
  fi
@@ -16,7 +16,7 @@ describe Reckon::App do
16
16
  describe "each_row_backwards" do
17
17
  it "should return rows with hashes" do
18
18
  @rows[0][:pretty_date].should == "2009-12-10"
19
- @rows[0][:pretty_money].should == " $2105.00"
19
+ @rows[0][:pretty_money].should == " $2,105.00"
20
20
  @rows[0][:description].should == "CREDIT; Some Company vendorpymt PPD ID: 5KL3832735"
21
21
  @rows[1][:pretty_date].should == "2009-12-11"
22
22
  @rows[1][:pretty_money].should == " $116.22"
@@ -242,7 +242,7 @@ describe Reckon::CSVParser do
242
242
  describe "pretty_money_for" do
243
243
  it "work with negative and positive numbers" do
244
244
  some_other_bank.pretty_money_for(1).should == "-$20.00"
245
- some_other_bank.pretty_money_for(4).should == " $1558.52"
245
+ some_other_bank.pretty_money_for(4).should == " $1,558.52"
246
246
  some_other_bank.pretty_money_for(7).should == "-$116.22"
247
247
  some_other_bank.pretty_money_for(5).should == " $0.23"
248
248
  some_other_bank.pretty_money_for(6).should == "-$0.96"
@@ -251,7 +251,7 @@ describe Reckon::CSVParser do
251
251
  it "work with other currencies such as €" do
252
252
  euro_bank = Reckon::CSVParser.new(file: fixture_path('some_other.csv'), currency: "€", suffixed: false )
253
253
  euro_bank.pretty_money_for(1).should == "-€20.00"
254
- euro_bank.pretty_money_for(4).should == " €1558.52"
254
+ euro_bank.pretty_money_for(4).should == " €1,558.52"
255
255
  euro_bank.pretty_money_for(7).should == "-€116.22"
256
256
  euro_bank.pretty_money_for(5).should == " €0.23"
257
257
  euro_bank.pretty_money_for(6).should == "-€0.96"
@@ -260,7 +260,7 @@ describe Reckon::CSVParser do
260
260
  it "work with suffixed currencies such as SEK" do
261
261
  swedish_bank = Reckon::CSVParser.new(file: fixture_path('some_other.csv'), currency: 'SEK', suffixed: true )
262
262
  swedish_bank.pretty_money_for(1).should == "-20.00 SEK"
263
- swedish_bank.pretty_money_for(4).should == " 1558.52 SEK"
263
+ swedish_bank.pretty_money_for(4).should == " 1,558.52 SEK"
264
264
  swedish_bank.pretty_money_for(7).should == "-116.22 SEK"
265
265
  swedish_bank.pretty_money_for(5).should == " 0.23 SEK"
266
266
  swedish_bank.pretty_money_for(6).should == "-0.96 SEK"
@@ -32,17 +32,17 @@ describe Reckon::Money do
32
32
  describe "pretty" do
33
33
  it "work with negative and positive numbers" do
34
34
  expect(Reckon::Money.new(-20.00).pretty).to eq("-$20.00")
35
- expect(Reckon::Money.new(1558.52).pretty).to eq(" $1558.52")
35
+ expect(Reckon::Money.new(1558.52).pretty).to eq(" $1,558.52")
36
36
  end
37
37
 
38
38
  it "work with other currencies such as €" do
39
39
  expect(Reckon::Money.new(-20.00, currency: "€", suffixed: false).pretty).to eq("-€20.00")
40
- expect(Reckon::Money.new(1558.52, currency: "€", suffixed: false).pretty).to eq(" €1558.52")
40
+ expect(Reckon::Money.new(1558.52, currency: "€", suffixed: false).pretty).to eq(" €1,558.52")
41
41
  end
42
42
 
43
43
  it "work with suffixed currencies such as SEK" do
44
44
  expect(Reckon::Money.new(-20.00, currency: "SEK", suffixed: true).pretty).to eq("-20.00 SEK")
45
- expect(Reckon::Money.new(1558.52, currency: "SEK", suffixed: true).pretty).to eq(" 1558.52 SEK")
45
+ expect(Reckon::Money.new(1558.52, currency: "SEK", suffixed: true).pretty).to eq(" 1,558.52 SEK")
46
46
  end
47
47
  end
48
48
 
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.7.1
4
+ version: 0.7.2
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: 2021-02-07 00:00:00.000000000 Z
13
+ date: 2021-04-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -130,6 +130,7 @@ files:
130
130
  - lib/reckon/options.rb
131
131
  - lib/reckon/version.rb
132
132
  - reckon.gemspec
133
+ - spec/cosine_training_and_test.rb
133
134
  - spec/data_fixtures/51-sample.csv
134
135
  - spec/data_fixtures/51-tokens.yml
135
136
  - spec/data_fixtures/73-sample.csv
@@ -162,6 +163,10 @@ files:
162
163
  - spec/integration/another_bank_example/input.csv
163
164
  - spec/integration/another_bank_example/output.ledger
164
165
  - spec/integration/another_bank_example/test_args
166
+ - spec/integration/ask_for_account/cli_input.exp
167
+ - spec/integration/ask_for_account/expected_output
168
+ - spec/integration/ask_for_account/input.csv
169
+ - spec/integration/ask_for_account/test_args
165
170
  - spec/integration/austrian_example/input.csv
166
171
  - spec/integration/austrian_example/output.ledger
167
172
  - spec/integration/austrian_example/test_args