reckon 0.7.1 → 0.7.2

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 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