reckon 0.5.1 → 0.5.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: a7e9512d0b15c14548a04e80f5dd3a87f50ae9ff2654827b5970def94e174667
4
- data.tar.gz: f858c96b4b5f2a7b2c85845803109e566281c0fc945c46ba39758121701d0e9a
3
+ metadata.gz: 70bc1d3d98a4ba08a3bca57069073f165e68041a5e628475b6c6076550f6e419
4
+ data.tar.gz: 99daf95abf45fd4dd5549d08bb9f3816af596cd3790667ca224baf7d46053ed0
5
5
  SHA512:
6
- metadata.gz: 15526cfe3504d50859de7b652285b31f639b11daecd8536732b97e1f84d03814cb8040c8db830386f803de7836e11712b7069758a77bf290fab26699436440f2
7
- data.tar.gz: 99ae732793adeaa40f5c7235e690dfb80d839a31ecba52f989e0dea2d339cf012623f858c926261e4bd5eb731e2a3ff508370509d03560c64c2bd7cf4a737a7e
6
+ metadata.gz: 6c0790695ec045e5210d20de85e17da49868b396ad78e334f24fdae7511969552a72df90b649b781c8b0e7ddf046cf8f84e2b47e212c576048f86798389bb449
7
+ data.tar.gz: 18babc20d956315d9abed0cec59503f0859844a48e3cf5ee59d743dda487de762a9ab9787074e7553128d41834938f5eedeb2f92e5fda4fb1ab73939f81d0eb2
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.5.2](https://github.com/cantino/reckon/tree/v0.5.2) (2020-03-07)
4
+
5
+ [Full Changelog](https://github.com/cantino/reckon/compare/v0.5.1...v0.5.2)
6
+
7
+ **Closed issues:**
8
+
9
+ - \[BUG\] Reckon appears not to be parsing ISO standard date yyyy-mm-dd? [\#85](https://github.com/cantino/reckon/issues/85)
10
+ - \[Bug\]? Reckon fails to run on ruby 2.7.0 on Catalina [\#83](https://github.com/cantino/reckon/issues/83)
11
+ - --account-tokens issue [\#51](https://github.com/cantino/reckon/issues/51)
12
+
13
+ ## [v0.5.1](https://github.com/cantino/reckon/tree/v0.5.1) (2020-02-25)
14
+
15
+ [Full Changelog](https://github.com/cantino/reckon/compare/v0.5.0...v0.5.1)
16
+
17
+ **Closed issues:**
18
+
19
+ - Error Importing [\#64](https://github.com/cantino/reckon/issues/64)
20
+
21
+ **Merged pull requests:**
22
+
23
+ - guard against rows that don't parse dates [\#82](https://github.com/cantino/reckon/pull/82) ([benprew](https://github.com/benprew))
24
+
3
25
  ## [v0.5.0](https://github.com/cantino/reckon/tree/v0.5.0) (2020-02-19)
4
26
 
5
27
  [Full Changelog](https://github.com/cantino/reckon/compare/v0.4.4...v0.5.0)
@@ -1,4 +1,5 @@
1
1
  require 'matrix'
2
+ require 'set'
2
3
 
3
4
  # Implementation of consine similarity using TF-IDF for vectorization.
4
5
  # Used to suggest which account a transaction should be assigned to
@@ -12,24 +12,39 @@ module Reckon
12
12
  detect_columns
13
13
  end
14
14
 
15
- def row(index)
16
- csv_data[index].join(", ")
15
+ def columns
16
+ @columns ||=
17
+ begin
18
+ last_row_length = nil
19
+ csv_data.inject([]) do |memo, row|
20
+ unless row.all? { |i| i.nil? || i.length == 0 }
21
+ row.each_with_index do |entry, index|
22
+ memo[index] ||= []
23
+ memo[index] << (entry || '').strip
24
+ end
25
+ last_row_length = row.length
26
+ end
27
+ memo
28
+ end
29
+ end
17
30
  end
18
31
 
19
- def filter_csv
20
- if options[:ignore_columns]
21
- new_columns = []
22
- columns.each_with_index do |column, index|
23
- new_columns << column unless options[:ignore_columns].include?(index + 1)
24
- end
25
- @columns = new_columns
26
- end
32
+ def date_for(index)
33
+ @date_column.for(index)
34
+ end
35
+
36
+ def pretty_date_for(index)
37
+ @date_column.pretty_for( index )
27
38
  end
28
39
 
29
40
  def money_for(index)
30
41
  @money_column[index]
31
42
  end
32
43
 
44
+ def pretty_money(amount, negate = false)
45
+ Money.new( amount, @options ).pretty( negate )
46
+ end
47
+
33
48
  def pretty_money_for(index, negate = false)
34
49
  money = money_for(index)
35
50
  return 0 if money.nil?
@@ -37,20 +52,24 @@ module Reckon
37
52
  money.pretty(negate)
38
53
  end
39
54
 
40
- def pretty_money(amount, negate = false)
41
- Money.new( amount, @options ).pretty( negate )
55
+ def description_for(index)
56
+ description_column_indices.map { |i| columns[i][index] }.reject(&:empty?).join("; ").squeeze(" ").gsub(/(;\s+){2,}/, '').strip
42
57
  end
43
58
 
44
- def date_for(index)
45
- @date_column.for(index)
59
+ def row(index)
60
+ csv_data[index].join(", ")
46
61
  end
47
62
 
48
- def pretty_date_for(index)
49
- @date_column.pretty_for( index )
50
- end
63
+ private
51
64
 
52
- def description_for(index)
53
- description_column_indices.map { |i| columns[i][index] }.reject(&:empty?).join("; ").squeeze(" ").gsub(/(;\s+){2,}/, '').strip
65
+ def filter_csv
66
+ if options[:ignore_columns]
67
+ new_columns = []
68
+ columns.each_with_index do |column, index|
69
+ new_columns << column unless options[:ignore_columns].include?(index + 1)
70
+ end
71
+ @columns = new_columns
72
+ end
54
73
  end
55
74
 
56
75
  def evaluate_columns(cols)
@@ -94,48 +113,24 @@ module Reckon
94
113
  results << { :index => index, :money_score => money_score, :date_score => date_score }
95
114
  end
96
115
 
97
- return [results, found_likely_money_column]
98
- end
116
+ results.sort_by! { |n| -n[:money_score] }
99
117
 
100
- def merge_columns(a, b)
101
- output_columns = []
102
- columns.each_with_index do |column, index|
103
- if index == a
104
- new_column = MoneyColumn.new( column )
105
- .merge!( MoneyColumn.new( columns[b] ) )
106
- .map { |m| m.amount.to_s }
107
- output_columns << new_column
108
- elsif index == b
109
- # skip
110
- else
111
- output_columns << column
112
- end
118
+ # check if it looks like a 2-column file with a balance field
119
+ if results.length >= 3 && results[1][:money_score] + results[2][:money_score] >= results[0][:money_score]
120
+ results[1][:is_money_column] = true
121
+ results[2][:is_money_column] = true
122
+ else
123
+ results[0][:is_money_column] = true
113
124
  end
114
- output_columns
115
- end
116
125
 
117
- def evaluate_two_money_columns( columns, id1, id2, unmerged_results )
118
- merged_columns = merge_columns( id1, id2 )
119
- results, found_likely_money_column = evaluate_columns( merged_columns )
120
- if !found_likely_money_column
121
- new_res = results.find { |el| el[:index] == id1 }
122
- old_res1 = unmerged_results.find { |el| el[:index] == id1 }
123
- old_res2 = unmerged_results.find { |el| el[:index] == id2 }
124
- if new_res[:money_score] > old_res1[:money_score] &&
125
- new_res[:money_score] > old_res2[:money_score]
126
- found_likely_money_column = true
127
- end
128
- end
129
- [results, found_likely_money_column]
126
+ return results.sort_by { |n| n[:index] }
130
127
  end
131
128
 
132
- def found_double_money_column( id1, id2 )
133
- self.money_column_indices = [ id1, id2 ]
134
- unless settings[:testing]
135
- puts "It looks like this CSV has two seperate columns for money, one of which shows positive"
136
- puts "changes and one of which shows negative changes. If this is true, great. Otherwise,"
137
- puts "please report this issue to us so we can take a look!\n"
138
- end
129
+ def found_double_money_column(id1, id2)
130
+ self.money_column_indices = [id1, id2]
131
+ puts "It looks like this CSV has two seperate columns for money, one of which shows positive"
132
+ puts "changes and one of which shows negative changes. If this is true, great. Otherwise,"
133
+ puts "please report this issue to us so we can take a look!\n"
139
134
  end
140
135
 
141
136
  # Some csv files negative/positive amounts are indicated in separate account
@@ -165,41 +160,18 @@ module Reckon
165
160
  end
166
161
 
167
162
  def detect_columns
168
- results, found_likely_money_column = evaluate_columns(columns)
163
+ results = evaluate_columns(columns)
164
+
169
165
  if options[:money_column]
170
- found_likely_money_column = true
171
166
  self.money_column_indices = [ options[:money_column] - 1 ]
172
167
  else
173
- self.money_column_indices = [ results.max_by { |n| n[:money_score] }[:index] ]
174
- end
175
-
176
- if !found_likely_money_column
177
- found_likely_double_money_columns = false
178
- 0.upto(columns.length - 2) do |i|
179
- if MoneyColumn.new( columns[i] ).merge!( MoneyColumn.new( columns[i+1] ) )
180
- _, found_likely_double_money_columns = evaluate_columns(merge_columns(i, i+1))
181
- if found_likely_double_money_columns
182
- found_double_money_column( i, i + 1 )
183
- break
184
- end
185
- end
186
- end
187
-
188
- if !found_likely_double_money_columns
189
- 0.upto(columns.length - 2) do |i|
190
- if MoneyColumn.new( columns[i] ).merge!( MoneyColumn.new( columns[i+1] ) )
191
- # Try a more specific test
192
- _, found_likely_double_money_columns = evaluate_two_money_columns( columns, i, i+1, results )
193
- if found_likely_double_money_columns
194
- found_double_money_column( i, i + 1 )
195
- break
196
- end
197
- end
198
- end
199
- end
200
-
201
- if !found_likely_double_money_columns && !settings[:testing]
202
- puts "I didn't find a high-likelyhood money column, but I'm taking my best guess with column #{money_column_indices.first + 1}."
168
+ self.money_column_indices = results.select { |n| n[:is_money_column] }.map { |n| n[:index] }
169
+ if self.money_column_indices.length == 1
170
+ puts "Using column #{money_column_indices.first + 1} as the money column. Use --money-colum to specify a different one."
171
+ elsif self.money_column_indices.length == 2
172
+ found_double_money_column(*self.money_column_indices)
173
+ else
174
+ puts "Unable to determine a money column, use --money-column to specify the column reckon should use."
203
175
  end
204
176
  end
205
177
 
@@ -223,23 +195,6 @@ module Reckon
223
195
  self.description_column_indices = results.map { |i| i[:index] }
224
196
  end
225
197
 
226
- def columns
227
- @columns ||= begin
228
- last_row_length = nil
229
- csv_data.inject([]) do |memo, row|
230
- # fail "Input CSV must have consistent row lengths." if last_row_length && row.length != last_row_length
231
- unless row.all? { |i| i.nil? || i.length == 0 }
232
- row.each_with_index do |entry, index|
233
- memo[index] ||= []
234
- memo[index] << (entry || '').strip
235
- end
236
- last_row_length = row.length
237
- end
238
- memo
239
- end
240
- end
241
- end
242
-
243
198
  def parse(data, filename=nil)
244
199
  # Use force_encoding to convert the string to utf-8 with as few invalid characters
245
200
  # as possible.
@@ -281,15 +236,5 @@ module Reckon
281
236
  end
282
237
  m && m[1]
283
238
  end
284
-
285
- @settings = { :testing => false }
286
-
287
- def self.settings
288
- @settings
289
- end
290
-
291
- def settings
292
- self.class.settings
293
- end
294
239
  end
295
240
  end
@@ -71,12 +71,13 @@ module Reckon
71
71
 
72
72
  def Money::likelihood( entry )
73
73
  money_score = 0
74
- money_score += 20 if entry[/^[\-\+\(]{0,2}\$/]
74
+ # digits separated by , or . with no more than 2 trailing digits
75
+ money_score += 40 if entry.match(/\d+[,.]\d{2}[^\d]*$/)
75
76
  money_score += 10 if entry[/^\$?\-?\$?\d+[\.,\d]*?[\.,]\d\d$/]
76
77
  money_score += 10 if entry[/\d+[\.,\d]*?[\.,]\d\d$/]
77
78
  money_score += entry.gsub(/[^\d\.\-\+,\(\)]/, '').length if entry.length < 7
78
- money_score -= entry.length if entry.length > 8
79
- money_score -= 20 if entry !~ /^[\$\+\.\-,\d\(\)]+$/
79
+ money_score -= entry.length if entry.length > 12
80
+ money_score -= 20 if (entry !~ /^[\$\+\.\-,\d\(\)]+$/) && entry.length > 0
80
81
  money_score
81
82
  end
82
83
  end
@@ -1,3 +1,3 @@
1
1
  module Reckon
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
@@ -0,0 +1,8 @@
1
+ 01/09/2015,05354 SUBWAY,8.19,,1000.00
2
+ 02/18/2015,WENDY'S #6338,8.55,,1000.00
3
+ 02/25/2015,WENDY'S #6338,8.55,,1000.00
4
+ 02/25/2015,WENDY'S #6338,9.14,,1000.00
5
+ 02/27/2015,WENDY'S #6338,5.85,,1000.00
6
+ 03/09/2015,WENDY'S #6338,17.70,,1000.00
7
+ 03/16/2015,WENDY'S #6338,11.15,,1000.00
8
+ 03/23/2015,WENDY'S,10.12,,1000.00
@@ -0,0 +1,9 @@
1
+ Expenses:
2
+ Dining:
3
+ Coffee:
4
+ - 'STARBUCKS'
5
+ - 'TIM HORTON'
6
+ Resturant:
7
+ - 'WENDY''S'
8
+ - 'SUBWAY'
9
+ - 'BARAKAT'
@@ -0,0 +1,2 @@
1
+ Visa, 4514010000000000, 2020-02-20, , GOJEK SINGAPORE, 8.10 SGD @ .976500000000, -7.91, D
2
+ Visa, 4514010000000000, 2020-02-20, , GOJEK SINGAPORE, 6.00 SGD @ .976600000000, -5.86, D
@@ -121,6 +121,22 @@ describe Reckon::App do
121
121
  end
122
122
  end
123
123
 
124
+ context 'Issue #51 - regression test' do
125
+ it 'should assign correct accounts with tokens' do
126
+ output = StringIO.new
127
+ Reckon::App.new(
128
+ file: fixture_path('51-sample.csv'),
129
+ unattended: true,
130
+ account_tokens_file: fixture_path('51-tokens.yml'),
131
+ ignore_columns: [5],
132
+ bank_account: 'Assets:Chequing',
133
+ output_file: output
134
+ ).walk_backwards
135
+ expect(output.string).not_to include('Income:Unknown')
136
+ expect(output.string.scan('Expenses:Dining:Resturant').size).to eq(8)
137
+ end
138
+ end
139
+
124
140
  #DATA
125
141
  BANK_CSV = (<<-CSV).strip
126
142
  DEBIT,20091224120000[0:GMT],"HOST 037196321563 MO 12/22SLICEHOST",-85.00
@@ -5,38 +5,29 @@ require_relative "../spec_helper"
5
5
  require 'rubygems'
6
6
  require_relative '../../lib/reckon'
7
7
 
8
- Reckon::CSVParser.settings[:testing] = true
9
-
10
8
  describe Reckon::CSVParser do
11
- before do
12
- @chase = Reckon::CSVParser.new(file: fixture_path('chase.csv'))
13
- @some_other_bank = Reckon::CSVParser.new(file: fixture_path('some_other.csv'))
14
- @two_money_columns = Reckon::CSVParser.new(file: fixture_path('two_money_columns.csv'))
15
- @suntrust_csv = Reckon::CSVParser.new(file: fixture_path('suntrust.csv'))
16
- @simple_csv = Reckon::CSVParser.new(file: fixture_path('simple.csv'))
17
- @nationwide = Reckon::CSVParser.new(file: fixture_path('nationwide.csv'), csv_separator: ',', suffixed: true, currency: "POUND")
18
- @german_date = Reckon::CSVParser.new(file: fixture_path('german_date_example.csv'))
19
- @danish_kroner_nordea = Reckon::CSVParser.new(file: fixture_path('danish_kroner_nordea_example.csv'), csv_separator: ';', comma_separates_cents: true)
20
- @yyyymmdd_date = Reckon::CSVParser.new(file: fixture_path('yyyymmdd_date_example.csv'))
21
- @spanish_date = Reckon::CSVParser.new(file: fixture_path('spanish_date_example.csv'), date_format: '%d/%m/%Y')
22
- @english_date = Reckon::CSVParser.new(file: fixture_path('english_date_example.csv'))
23
- @ing_csv = Reckon::CSVParser.new(file: fixture_path('ing.csv'), comma_separates_cents: true )
24
- @austrian_csv = Reckon::CSVParser.new(file: fixture_path('austrian_example.csv'), comma_separates_cents: true, csv_separator: ';' )
25
- @french_csv = Reckon::CSVParser.new(file: fixture_path('french_example.csv'), csv_separator: ';', comma_separates_cents: true)
26
- @broker_canada = Reckon::CSVParser.new(file: fixture_path('broker_canada_example.csv'))
27
- @intuit_mint = Reckon::CSVParser.new(file: fixture_path('intuit_mint_example.csv'))
28
- end
29
-
30
- it "should be in testing mode" do
31
- @chase.settings[:testing].should be true
32
- Reckon::CSVParser.settings[:testing].should be true
33
- end
9
+ let(:chase) { Reckon::CSVParser.new(file: fixture_path('chase.csv')) }
10
+ let(:some_other_bank) { Reckon::CSVParser.new(file: fixture_path('some_other.csv')) }
11
+ let(:two_money_columns) { Reckon::CSVParser.new(file: fixture_path('two_money_columns.csv')) }
12
+ let(:suntrust_csv) { Reckon::CSVParser.new(file: fixture_path('suntrust.csv')) }
13
+ let(:simple_csv) { Reckon::CSVParser.new(file: fixture_path('simple.csv')) }
14
+ let(:nationwide) { Reckon::CSVParser.new(file: fixture_path('nationwide.csv'), csv_separator: ',', suffixed: true, currency: "POUND") }
15
+ let(:german_date) { Reckon::CSVParser.new(file: fixture_path('german_date_example.csv')) }
16
+ let(:danish_kroner_nordea) { Reckon::CSVParser.new(file: fixture_path('danish_kroner_nordea_example.csv'), csv_separator: ';', comma_separates_cents: true) }
17
+ let(:yyyymmdd_date) { Reckon::CSVParser.new(file: fixture_path('yyyymmdd_date_example.csv')) }
18
+ let(:spanish_date) { Reckon::CSVParser.new(file: fixture_path('spanish_date_example.csv'), date_format: '%d/%m/%Y') }
19
+ let(:english_date) { Reckon::CSVParser.new(file: fixture_path('english_date_example.csv')) }
20
+ let(:ing_csv) { Reckon::CSVParser.new(file: fixture_path('ing.csv'), comma_separates_cents: true ) }
21
+ let(:austrian_csv) { Reckon::CSVParser.new(file: fixture_path('austrian_example.csv'), comma_separates_cents: true, csv_separator: ';' ) }
22
+ let(:french_csv) { Reckon::CSVParser.new(file: fixture_path('french_example.csv'), csv_separator: ';', comma_separates_cents: true) }
23
+ let(:broker_canada) { Reckon::CSVParser.new(file: fixture_path('broker_canada_example.csv')) }
24
+ let(:intuit_mint) { Reckon::CSVParser.new(file: fixture_path('intuit_mint_example.csv')) }
34
25
 
35
26
  describe "parse" do
36
27
  it "should use binary encoding if none specified and chardet fails" do
37
28
  allow(CharDet).to receive(:detect).and_return({'encoding' => nil})
38
29
  app = Reckon::CSVParser.new(file: fixture_path("extratofake.csv"))
39
- expect(app.try_encoding("foobarbaz")).to eq("BINARY")
30
+ expect(app.send(:try_encoding, "foobarbaz")).to eq("BINARY")
40
31
  end
41
32
 
42
33
  it "should work with foreign character encodings" do
@@ -76,8 +67,8 @@ describe Reckon::CSVParser do
76
67
 
77
68
  describe "columns" do
78
69
  it "should return the csv transposed" do
79
- @simple_csv.columns.should == [["entry1", "entry4"], ["entry2", "entry5"], ["entry3", "entry6"]]
80
- @chase.columns.length.should == 4
70
+ simple_csv.columns.should == [["entry1", "entry4"], ["entry2", "entry5"], ["entry3", "entry6"]]
71
+ chase.columns.length.should == 4
81
72
  end
82
73
 
83
74
  it "should be ok with empty lines" do
@@ -88,46 +79,44 @@ describe Reckon::CSVParser do
88
79
  end
89
80
 
90
81
  describe "detect_columns" do
91
- before do
92
- @harder_date_example_csv = Reckon::CSVParser.new(file: fixture_path('harder_date_example.csv'))
93
- end
82
+ let(:harder_date_example_csv) { Reckon::CSVParser.new(file: fixture_path('harder_date_example.csv')) }
94
83
 
95
84
  it "should detect the money column" do
96
- @chase.money_column_indices.should == [3]
97
- @some_other_bank.money_column_indices.should == [3]
98
- @two_money_columns.money_column_indices.should == [3, 4]
99
- @suntrust_csv.money_column_indices.should == [3, 4]
100
- @nationwide.money_column_indices.should == [3, 4]
101
- @harder_date_example_csv.money_column_indices.should == [1]
102
- @danish_kroner_nordea.money_column_indices.should == [3]
103
- @yyyymmdd_date.money_column_indices.should == [3]
104
- @ing_csv.money_column_indices.should == [6]
105
- @austrian_csv.money_column_indices.should == [4]
106
- @french_csv.money_column_indices.should == [4]
107
- @broker_canada.money_column_indices.should == [8]
108
- @intuit_mint.money_column_indices.should == [3]
85
+ chase.money_column_indices.should == [3]
86
+ some_other_bank.money_column_indices.should == [3]
87
+ two_money_columns.money_column_indices.should == [3, 4]
88
+ suntrust_csv.money_column_indices.should == [3, 4]
89
+ nationwide.money_column_indices.should == [3, 4]
90
+ harder_date_example_csv.money_column_indices.should == [1]
91
+ danish_kroner_nordea.money_column_indices.should == [3]
92
+ yyyymmdd_date.money_column_indices.should == [3]
93
+ ing_csv.money_column_indices.should == [6]
94
+ austrian_csv.money_column_indices.should == [4]
95
+ french_csv.money_column_indices.should == [4]
96
+ broker_canada.money_column_indices.should == [8]
97
+ intuit_mint.money_column_indices.should == [3]
109
98
  end
110
99
 
111
100
  it "should detect the date column" do
112
- @chase.date_column_index.should == 1
113
- @some_other_bank.date_column_index.should == 1
114
- @two_money_columns.date_column_index.should == 0
115
- @harder_date_example_csv.date_column_index.should == 0
116
- @danish_kroner_nordea.date_column_index.should == 0
117
- @yyyymmdd_date.date_column_index.should == 1
118
- @french_csv.date_column_index.should == 1
119
- @broker_canada.date_column_index.should == 0
120
- @intuit_mint.date_column_index.should == 0
101
+ chase.date_column_index.should == 1
102
+ some_other_bank.date_column_index.should == 1
103
+ two_money_columns.date_column_index.should == 0
104
+ harder_date_example_csv.date_column_index.should == 0
105
+ danish_kroner_nordea.date_column_index.should == 0
106
+ yyyymmdd_date.date_column_index.should == 1
107
+ french_csv.date_column_index.should == 1
108
+ broker_canada.date_column_index.should == 0
109
+ intuit_mint.date_column_index.should == 0
121
110
  Reckon::CSVParser.new(:string => '2014-01-13,"22211100000",-10').date_column_index.should == 0
122
111
  end
123
112
 
124
113
  it "should consider all other columns to be description columns" do
125
- @chase.description_column_indices.should == [0, 2]
126
- @some_other_bank.description_column_indices.should == [0, 2]
127
- @two_money_columns.description_column_indices.should == [1, 2, 5]
128
- @harder_date_example_csv.description_column_indices.should == [2, 3, 4, 5, 6, 7]
129
- @danish_kroner_nordea.description_column_indices.should == [1, 2, 4]
130
- @yyyymmdd_date.description_column_indices.should == [0, 2]
114
+ chase.description_column_indices.should == [0, 2]
115
+ some_other_bank.description_column_indices.should == [0, 2]
116
+ two_money_columns.description_column_indices.should == [1, 2, 5]
117
+ harder_date_example_csv.description_column_indices.should == [2, 3, 4, 5, 6, 7]
118
+ danish_kroner_nordea.description_column_indices.should == [1, 2, 4]
119
+ yyyymmdd_date.description_column_indices.should == [0, 2]
131
120
  end
132
121
  end
133
122
 
@@ -143,36 +132,36 @@ describe Reckon::CSVParser do
143
132
 
144
133
  describe "money_for" do
145
134
  it "should return the appropriate fields" do
146
- @chase.money_for(1).should == -20
147
- @chase.money_for(4).should == 1558.52
148
- @chase.money_for(7).should == -116.22
149
- @some_other_bank.money_for(1).should == -20
150
- @some_other_bank.money_for(4).should == 1558.52
151
- @some_other_bank.money_for(7).should == -116.22
152
- @two_money_columns.money_for(0).should == -76
153
- @two_money_columns.money_for(1).should == 327.49
154
- @two_money_columns.money_for(2).should == -800
155
- @two_money_columns.money_for(3).should == -88.55
156
- @two_money_columns.money_for(4).should == 88.55
157
- @nationwide.money_for(0).should == 500.00
158
- @nationwide.money_for(1).should == -20.00
159
- @danish_kroner_nordea.money_for(0).should == -48.00
160
- @danish_kroner_nordea.money_for(1).should == -79.00
161
- @danish_kroner_nordea.money_for(2).should == 497.90
162
- @danish_kroner_nordea.money_for(3).should == -995.00
163
- @danish_kroner_nordea.money_for(4).should == -3452.90
164
- @danish_kroner_nordea.money_for(5).should == -655.00
165
- @yyyymmdd_date.money_for(0).should == -123.45
166
- @ing_csv.money_for(0).should == -136.13
167
- @ing_csv.money_for(1).should == 375.00
168
- @austrian_csv.money_for(0).should == -18.00
169
- @austrian_csv.money_for(2).should == 120.00
170
- @french_csv.money_for(0).should == -10.00
171
- @french_csv.money_for(1).should == -5.76
172
- @broker_canada.money_for(0).should == 12.55
173
- @broker_canada.money_for(1).should == -81.57
174
- @intuit_mint.money_for(0).should == 0.01
175
- @intuit_mint.money_for(1).should == -331.63
135
+ chase.money_for(1).should == -20
136
+ chase.money_for(4).should == 1558.52
137
+ chase.money_for(7).should == -116.22
138
+ some_other_bank.money_for(1).should == -20
139
+ some_other_bank.money_for(4).should == 1558.52
140
+ some_other_bank.money_for(7).should == -116.22
141
+ two_money_columns.money_for(0).should == -76
142
+ two_money_columns.money_for(1).should == 327.49
143
+ two_money_columns.money_for(2).should == -800
144
+ two_money_columns.money_for(3).should == -88.55
145
+ two_money_columns.money_for(4).should == 88.55
146
+ nationwide.money_for(0).should == 500.00
147
+ nationwide.money_for(1).should == -20.00
148
+ danish_kroner_nordea.money_for(0).should == -48.00
149
+ danish_kroner_nordea.money_for(1).should == -79.00
150
+ danish_kroner_nordea.money_for(2).should == 497.90
151
+ danish_kroner_nordea.money_for(3).should == -995.00
152
+ danish_kroner_nordea.money_for(4).should == -3452.90
153
+ danish_kroner_nordea.money_for(5).should == -655.00
154
+ yyyymmdd_date.money_for(0).should == -123.45
155
+ ing_csv.money_for(0).should == -136.13
156
+ ing_csv.money_for(1).should == 375.00
157
+ austrian_csv.money_for(0).should == -18.00
158
+ austrian_csv.money_for(2).should == 120.00
159
+ french_csv.money_for(0).should == -10.00
160
+ french_csv.money_for(1).should == -5.76
161
+ broker_canada.money_for(0).should == 12.55
162
+ broker_canada.money_for(1).should == -81.57
163
+ intuit_mint.money_for(0).should == 0.01
164
+ intuit_mint.money_for(1).should == -331.63
176
165
  end
177
166
 
178
167
  it "should handle the comma_separates_cents option correctly" do
@@ -200,59 +189,58 @@ describe Reckon::CSVParser do
200
189
 
201
190
  describe "date_for" do
202
191
  it "should return a parsed date object" do
203
- @chase.date_for(1).year.should == Time.parse("2009/12/24").year
204
- @chase.date_for(1).month.should == Time.parse("2009/12/24").month
205
- @chase.date_for(1).day.should == Time.parse("2009/12/24").day
206
- @some_other_bank.date_for(1).year.should == Time.parse("2010/12/24").year
207
- @some_other_bank.date_for(1).month.should == Time.parse("2010/12/24").month
208
- @some_other_bank.date_for(1).day.should == Time.parse("2010/12/24").day
209
- @german_date.date_for(1).year.should == Time.parse("2009/12/24").year
210
- @german_date.date_for(1).month.should == Time.parse("2009/12/24").month
211
- @german_date.date_for(1).day.should == Time.parse("2009/12/24").day
212
- @danish_kroner_nordea.date_for(0).year.should == Time.parse("2012/11/16").year
213
- @danish_kroner_nordea.date_for(0).month.should == Time.parse("2012/11/16").month
214
- @danish_kroner_nordea.date_for(0).day.should == Time.parse("2012/11/16").day
215
- @yyyymmdd_date.date_for(0).year.should == Time.parse("2012/12/31").year
216
- @yyyymmdd_date.date_for(0).month.should == Time.parse("2012/12/31").month
217
- @yyyymmdd_date.date_for(0).day.should == Time.parse("2012/12/31").day
218
- @spanish_date.date_for(1).year.should == Time.parse("2009/12/02").year
219
- @spanish_date.date_for(1).month.should == Time.parse("2009/12/02").month
220
- @spanish_date.date_for(1).day.should == Time.parse("2009/12/02").day
221
- @english_date.date_for(1).year.should == Time.parse("2009/12/24").year
222
- @english_date.date_for(1).month.should == Time.parse("2009/12/24").month
223
- @english_date.date_for(1).day.should == Time.parse("2009/12/24").day
224
- @nationwide.date_for(1).month.should == 10
225
- @ing_csv.date_for(1).month.should == Time.parse("2012/11/12").month
226
- @ing_csv.date_for(1).day.should == Time.parse("2012/11/12").day
227
- @broker_canada.date_for(5).year.should == 2014
228
- @broker_canada.date_for(5).month.should == 1
229
- @broker_canada.date_for(5).day.should == 7
230
- @intuit_mint.date_for(1).year.should == 2014
231
- @intuit_mint.date_for(1).month.should == 2
232
- @intuit_mint.date_for(1).day.should == 3
192
+ chase.date_for(1).year.should == Time.parse("2009/12/24").year
193
+ chase.date_for(1).month.should == Time.parse("2009/12/24").month
194
+ chase.date_for(1).day.should == Time.parse("2009/12/24").day
195
+ some_other_bank.date_for(1).year.should == Time.parse("2010/12/24").year
196
+ some_other_bank.date_for(1).month.should == Time.parse("2010/12/24").month
197
+ some_other_bank.date_for(1).day.should == Time.parse("2010/12/24").day
198
+ german_date.date_for(1).year.should == Time.parse("2009/12/24").year
199
+ german_date.date_for(1).month.should == Time.parse("2009/12/24").month
200
+ german_date.date_for(1).day.should == Time.parse("2009/12/24").day
201
+ danish_kroner_nordea.date_for(0).year.should == Time.parse("2012/11/16").year
202
+ danish_kroner_nordea.date_for(0).month.should == Time.parse("2012/11/16").month
203
+ danish_kroner_nordea.date_for(0).day.should == Time.parse("2012/11/16").day
204
+ yyyymmdd_date.date_for(0).year.should == Time.parse("2012/12/31").year
205
+ yyyymmdd_date.date_for(0).month.should == Time.parse("2012/12/31").month
206
+ yyyymmdd_date.date_for(0).day.should == Time.parse("2012/12/31").day
207
+ spanish_date.date_for(1).year.should == Time.parse("2009/12/02").year
208
+ spanish_date.date_for(1).month.should == Time.parse("2009/12/02").month
209
+ spanish_date.date_for(1).day.should == Time.parse("2009/12/02").day
210
+ english_date.date_for(1).year.should == Time.parse("2009/12/24").year
211
+ english_date.date_for(1).month.should == Time.parse("2009/12/24").month
212
+ english_date.date_for(1).day.should == Time.parse("2009/12/24").day
213
+ nationwide.date_for(1).month.should == 10
214
+ ing_csv.date_for(1).month.should == Time.parse("2012/11/12").month
215
+ ing_csv.date_for(1).day.should == Time.parse("2012/11/12").day
216
+ broker_canada.date_for(5).year.should == 2014
217
+ broker_canada.date_for(5).month.should == 1
218
+ broker_canada.date_for(5).day.should == 7
219
+ intuit_mint.date_for(1).year.should == 2014
220
+ intuit_mint.date_for(1).month.should == 2
221
+ intuit_mint.date_for(1).day.should == 3
233
222
  end
234
223
  end
235
224
 
236
225
  describe "description_for" do
237
226
  it "should return the combined fields that are not money for date fields" do
238
- @chase.description_for(1).should == "CHECK; CHECK 2656"
239
- @chase.description_for(7).should == "CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL"
227
+ chase.description_for(1).should == "CHECK; CHECK 2656"
228
+ chase.description_for(7).should == "CREDIT; PAYPAL TRANSFER PPD ID: PAYPALSDSL"
240
229
  end
241
230
 
242
231
  it "should not append empty description column" do
243
232
  parser = Reckon::CSVParser.new(:string => '01/09/2015,05354 SUBWAY,8.19,,',:date_format => '%d/%m/%Y')
244
- parser.description_column_indices.should == [1, 4]
245
233
  parser.description_for(0).should == '05354 SUBWAY'
246
234
  end
247
235
  end
248
236
 
249
237
  describe "pretty_money_for" do
250
238
  it "work with negative and positive numbers" do
251
- @some_other_bank.pretty_money_for(1).should == "-$20.00"
252
- @some_other_bank.pretty_money_for(4).should == " $1558.52"
253
- @some_other_bank.pretty_money_for(7).should == "-$116.22"
254
- @some_other_bank.pretty_money_for(5).should == " $0.23"
255
- @some_other_bank.pretty_money_for(6).should == "-$0.96"
239
+ some_other_bank.pretty_money_for(1).should == "-$20.00"
240
+ some_other_bank.pretty_money_for(4).should == " $1558.52"
241
+ some_other_bank.pretty_money_for(7).should == "-$116.22"
242
+ some_other_bank.pretty_money_for(5).should == " $0.23"
243
+ some_other_bank.pretty_money_for(6).should == "-$0.96"
256
244
  end
257
245
 
258
246
  it "work with other currencies such as €" do
@@ -274,8 +262,15 @@ describe Reckon::CSVParser do
274
262
  end
275
263
 
276
264
  it "should work with merge columns" do
277
- @nationwide.pretty_money_for(0).should == " 500.00 POUND"
278
- @nationwide.pretty_money_for(1).should == "-20.00 POUND"
265
+ nationwide.pretty_money_for(0).should == " 500.00 POUND"
266
+ nationwide.pretty_money_for(1).should == "-20.00 POUND"
267
+ end
268
+ end
269
+
270
+ describe '85 regression test' do
271
+ it 'should detect correct date column' do
272
+ p = Reckon::CSVParser.new(file:fixture_path('85-date-example.csv'))
273
+ expect(p.date_column_index).to eq(2)
279
274
  end
280
275
  end
281
276
  end
@@ -8,79 +8,92 @@ require 'reckon'
8
8
  describe Reckon::Money do
9
9
  describe "from_s" do
10
10
  it "should handle currency indicators" do
11
- Reckon::Money::from_s( "$2.00" ).should == 2.00
12
- Reckon::Money::from_s( "-$1025.67" ).should == -1025.67
13
- Reckon::Money::from_s( "$-1025.67" ).should == -1025.67
11
+ expect(Reckon::Money::from_s( "$2.00" )).to eq(2.00)
12
+ expect(Reckon::Money::from_s("-$1025.67")).to eq(-1025.67)
13
+ expect(Reckon::Money::from_s("$-1025.67")).to eq(-1025.67)
14
14
  end
15
15
 
16
16
  it "should handle the comma_separates_cents option correctly" do
17
- Reckon::Money::from_s( "$2,00", :comma_separates_cents => true ).should == 2.00
18
- Reckon::Money::from_s( "-$1025,67", :comma_separates_cents => true ).should == -1025.67
19
- Reckon::Money::from_s( "$-1025,67", :comma_separates_cents => true ).should == -1025.67
17
+ expect(Reckon::Money::from_s("$2,00", :comma_separates_cents => true)).to eq(2.00)
18
+ expect(Reckon::Money::from_s("-$1025,67", :comma_separates_cents => true )).to eq(-1025.67)
19
+ expect(Reckon::Money::from_s("$-1025,67", :comma_separates_cents => true )).to eq(-1025.67)
20
20
  end
21
21
 
22
22
  it "should return 0 for an empty string" do
23
- Reckon::Money::from_s( "" ).should == 0
23
+ expect(Reckon::Money::from_s("")).to eq(0)
24
24
  end
25
25
 
26
26
  it "should handle 1000 indicators correctly" do
27
- Reckon::Money::from_s( "$2.000,00", :comma_separates_cents => true ).should == 2000.00
28
- Reckon::Money::from_s( "-$1,025.67" ).should == -1025.67
27
+ expect(Reckon::Money::from_s("$2.000,00", :comma_separates_cents => true)).to eq(2000.00)
28
+ expect(Reckon::Money::from_s("-$1,025.67")).to eq(-1025.67)
29
29
  end
30
30
 
31
31
  it "should keep numbers together" do
32
- Reckon::Money::from_s( "1A1" ).should == 1
32
+ expect(Reckon::Money::from_s("1A1")).to eq(1)
33
33
  end
34
34
 
35
35
  it "should prefer numbers with precision of two" do
36
- Reckon::Money::from_s( "1A2.00" ).should == 2
37
- Reckon::Money::from_s( "2.00A1" ).should == 2
36
+ expect(Reckon::Money::from_s("1A2.00")).to eq(2)
37
+ expect(Reckon::Money::from_s("2.00A1")).to eq(2)
38
38
  end
39
39
 
40
40
  it "should handle arbitrary prefixes and postfixes" do
41
- Reckon::Money::from_s( "AB1.00C" ).should == 1
42
- Reckon::Money::from_s( "AB0C" ).should == 0
43
- Reckon::Money::from_s( "AB-2.00C" ).should == -2
41
+ expect(Reckon::Money::from_s("AB1.00C")).to eq(1)
42
+ expect(Reckon::Money::from_s("AB0C")).to eq(0)
43
+ expect(Reckon::Money::from_s("AB-2.00C")).to eq(-2)
44
44
  end
45
45
 
46
46
  it "should return nil if no numbers are found" do
47
- Reckon::Money::from_s( "BAC" ).should == nil
47
+ expect(Reckon::Money::from_s("BAC")).to be_nil()
48
48
  end
49
49
  end
50
50
 
51
51
  describe "pretty" do
52
52
  it "work with negative and positive numbers" do
53
- Reckon::Money.new( -20.00 ).pretty.should == "-$20.00"
54
- Reckon::Money.new( 1558.52 ).pretty.should == " $1558.52"
53
+ expect(Reckon::Money.new(-20.00).pretty).to eq("-$20.00")
54
+ expect(Reckon::Money.new(1558.52).pretty).to eq(" $1558.52")
55
55
  end
56
56
 
57
57
  it "work with other currencies such as €" do
58
- Reckon::Money.new( -20.00, :currency => "€", :suffixed => false ).pretty.should == "-€20.00"
59
- Reckon::Money.new( 1558.52, :currency => "€", :suffixed => false ).pretty.should == " €1558.52"
58
+ expect(Reckon::Money.new(-20.00, currency: "€", suffixed: false).pretty).to eq("-€20.00")
59
+ expect(Reckon::Money.new(1558.52, currency: "€", suffixed: false).pretty).to eq(" €1558.52")
60
60
  end
61
61
 
62
62
  it "work with suffixed currencies such as SEK" do
63
- Reckon::Money.new( -20.00, :currency => "SEK", :suffixed => true ).pretty.should == "-20.00 SEK"
64
- Reckon::Money.new( 1558.52, :currency => "SEK", :suffixed => true ).pretty.should == " 1558.52 SEK"
63
+ expect(Reckon::Money.new( -20.00, :currency => "SEK", :suffixed => true ).pretty).to eq("-20.00 SEK")
64
+ expect(Reckon::Money.new( 1558.52, :currency => "SEK", :suffixed => true ).pretty).to eq(" 1558.52 SEK")
65
65
  end
66
66
  end
67
67
 
68
68
  describe "likelihood" do
69
69
  it "should return the likelihood that a string represents money" do
70
- Reckon::Money::likelihood( "$20.00" ).should == 45
70
+ expect(Reckon::Money::likelihood( "$20.00" )).to eq(65)
71
+ end
72
+
73
+ it "should return neutral for empty string" do
74
+ expect(Reckon::Money::likelihood("")).to eq(0)
75
+ end
76
+
77
+ it "should recognize non-us currencies" do
78
+ expect(Reckon::Money::likelihood("£480.00")).to eq(30)
79
+ expect(Reckon::Money::likelihood("£1.480,00")).to eq(30)
80
+ end
81
+
82
+ it 'should not identify date columns as money' do
83
+ expect(Reckon::Money::likelihood("22.01.2014")).to eq(0)
71
84
  end
72
85
  end
73
86
 
74
87
  describe "equality" do
75
88
  it "should be comparable to other money" do
76
- Reckon::Money.new( 2.0 ).should == Reckon::Money.new( 2.0 )
77
- Reckon::Money.new( 1.0 ).should <= Reckon::Money.new( 2.0 )
78
- Reckon::Money.new( 3.0 ).should > Reckon::Money.new( 2.0 )
89
+ expect(Reckon::Money.new(2.0)).to eq(Reckon::Money.new(2.0))
90
+ expect(Reckon::Money.new(1.0)).to be <= Reckon::Money.new(2.0)
91
+ expect(Reckon::Money.new(3.0)).to be > Reckon::Money.new(2.0)
79
92
  end
80
93
  it "should be comparable to other float" do
81
- Reckon::Money.new( 2.0 ).should == 2.0
82
- Reckon::Money.new( 1.0 ).should <= 2.0
83
- Reckon::Money.new( 3.0 ).should > 2.0
94
+ expect(Reckon::Money.new(2.0)).to eq(2.0)
95
+ expect(Reckon::Money.new(1.0)).to be <= 2.0
96
+ expect(Reckon::Money.new(3.0)).to be > 2.0
84
97
  end
85
98
  end
86
99
  end
@@ -3,7 +3,26 @@ require 'rspec'
3
3
  require 'reckon'
4
4
 
5
5
  RSpec.configure do |config|
6
+ config.before(:all, &:silence_output)
7
+ config.after(:all, &:enable_output)
6
8
  def fixture_path(file)
7
9
  File.expand_path(File.join(File.dirname(__FILE__), "data_fixtures", file))
8
10
  end
9
11
  end
12
+
13
+ public
14
+
15
+ # Redirects stderr and stout to /dev/null.txt
16
+ def silence_output
17
+ # Store the original stderr and stdout in order to restore them later
18
+ @original_stdout = $stdout
19
+
20
+ # Redirect stderr and stdout
21
+ $stdout = File.new(File.join(File.dirname(__FILE__), 'test_log.txt'), 'w')
22
+ end
23
+
24
+ # Replace stderr and stdout so anything else is output correctly
25
+ def enable_output
26
+ $stdout = @original_stdout
27
+ @original_stdout = nil
28
+ 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.5.1
4
+ version: 0.5.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: 2020-02-25 00:00:00.000000000 Z
13
+ date: 2020-03-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -140,9 +140,12 @@ files:
140
140
  - lib/reckon/money.rb
141
141
  - lib/reckon/version.rb
142
142
  - reckon.gemspec
143
+ - spec/data_fixtures/51-sample.csv
144
+ - spec/data_fixtures/51-tokens.yml
143
145
  - spec/data_fixtures/73-sample.csv
144
146
  - spec/data_fixtures/73-tokens.yml
145
147
  - spec/data_fixtures/73-transactions.ledger
148
+ - spec/data_fixtures/85-date-example.csv
146
149
  - spec/data_fixtures/austrian_example.csv
147
150
  - spec/data_fixtures/bom_utf8_file.csv
148
151
  - spec/data_fixtures/broker_canada_example.csv
@@ -193,8 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
196
  - !ruby/object:Gem::Version
194
197
  version: '0'
195
198
  requirements: []
196
- rubyforge_project:
197
- rubygems_version: 2.7.6.2
199
+ rubygems_version: 3.0.6
198
200
  signing_key:
199
201
  specification_version: 4
200
202
  summary: Utility for interactively converting and labeling CSV files for the Ledger