reckon 0.4.3 → 0.4.4

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
  SHA1:
3
- metadata.gz: def2132cbd39a44c0aece86b0ffa5f47c1be645e
4
- data.tar.gz: 0d8b5e4458577817812a7f35dc62a0afc9e696e2
3
+ metadata.gz: cf1d814fe911f299cf58401c3b36734e29a172f1
4
+ data.tar.gz: 9130495690de1f73cfa3570a6e3386f38df86830
5
5
  SHA512:
6
- metadata.gz: 836a0e77e93157362465452ff7ff2760c1a2bee8c5181cbe2a850e2229caf7bdc75b986f87465f61a5c8d34ae66e942985341d3d80d3eb6941e68d79f3217bcd
7
- data.tar.gz: 1065704ac1fba78cf115cd9406ddf18eb0bf93650d61fee2439b93e1d691fc304637d9742ae88e37050a472297466a375d76fc41261a9a8398a6015a0017328d
6
+ metadata.gz: b7c3e23f96983cd79844ba37524f1b843a1dbba230198cf813b83c7c65a076506fb2c66ab663dee0970db2d42e1d3e0b03adf41ee163d08f3b38dbb163c373a6
7
+ data.tar.gz: d74ab72db15d54bc0bfe548369ec9a8b3903760bc09fbc16340a6f64c929a69d595c4840900e8a425996bc580e5924321ece84b10d3e033b193b066f2520f7c2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reckon (0.4.3)
4
+ reckon (0.4.4)
5
5
  chronic (>= 0.3.0)
6
6
  fastercsv (>= 1.5.1)
7
7
  highline (>= 1.5.2)
data/README.md CHANGED
@@ -90,6 +90,8 @@ Expenses:
90
90
  - 'MasterCard'
91
91
  Rent:
92
92
  - '0011223344' # Landlord bank number
93
+ Hosting:
94
+ - /hosting/i # This regexp will catch descriptions such as WebHosting or filehosting
93
95
  '[Internal:Transfer]': # Virtual account
94
96
  - '4433221100' # Your own account number
95
97
  ```
@@ -4,12 +4,13 @@ require 'yaml'
4
4
 
5
5
  module Reckon
6
6
  class App
7
- VERSION = "Reckon 0.4.3"
8
- attr_accessor :options, :accounts, :tokens, :seen, :csv_parser
7
+ VERSION = "Reckon 0.4.4"
8
+ attr_accessor :options, :accounts, :tokens, :seen, :csv_parser, :regexps
9
9
 
10
10
  def initialize(options = {})
11
11
  self.options = options
12
12
  self.tokens = {}
13
+ self.regexps = {}
13
14
  self.accounts = {}
14
15
  self.seen = {}
15
16
  self.options[:currency] ||= '$'
@@ -54,7 +55,7 @@ module Reckon
54
55
  if options[:account_tokens_file]
55
56
  fail "#{options[:account_tokens_file]} doesn't exist!" unless File.exists?(options[:account_tokens_file])
56
57
  extract_account_tokens(YAML.load_file(options[:account_tokens_file])).each do |account, tokens|
57
- tokens.each { |t| learn_about_account(account, t) }
58
+ tokens.each { |t| learn_about_account(account, t, true) }
58
59
  end
59
60
  end
60
61
  return unless options[:existing_ledger_file]
@@ -63,13 +64,27 @@ module Reckon
63
64
  learn_from(ledger_data)
64
65
  end
65
66
 
66
- def learn_about_account(account, data)
67
+ def learn_about_account(account, data, parse_regexps = false)
67
68
  accounts[account] ||= 0
68
- tokenize(data).each do |token|
69
- tokens[token] ||= {}
70
- tokens[token][account] ||= 0
71
- tokens[token][account] += 1
72
- accounts[account] += 1
69
+ if parse_regexps && data.start_with?('/')
70
+ # https://github.com/tenderlove/psych/blob/master/lib/psych/visitors/to_ruby.rb
71
+ match = data.match(/^\/(.*)\/([ix]*)$/m)
72
+ fail "failed to parse regexp #{data}" unless match
73
+ options = 0
74
+ (match[2] || '').split('').each do |option|
75
+ case option
76
+ when 'x' then options |= Regexp::EXTENDED
77
+ when 'i' then options |= Regexp::IGNORECASE
78
+ end
79
+ end
80
+ regexps[Regexp.new(match[1], options)] = account
81
+ else
82
+ tokenize(data).each do |token|
83
+ tokens[token] ||= {}
84
+ tokens[token][account] ||= 0
85
+ tokens[token][account] += 1
86
+ accounts[account] += 1
87
+ end
73
88
  end
74
89
  end
75
90
 
@@ -92,7 +107,8 @@ module Reckon
92
107
  seen_anything_new = true
93
108
  end
94
109
 
95
- possible_answers = weighted_account_match( row ).map! { |a| a[:account] }
110
+ possible_answers = most_specific_regexp_match(row)
111
+ possible_answers = weighted_account_match( row ).map! { |a| a[:account] } if possible_answers.empty?
96
112
 
97
113
  ledger = if row[:money] > 0
98
114
  if options[:unattended]
@@ -151,6 +167,15 @@ module Reckon
151
167
  options[:output_file].flush
152
168
  end
153
169
 
170
+ def most_specific_regexp_match( row )
171
+ matches = regexps.map { |regexp, account|
172
+ if match = regexp.match(row[:description])
173
+ [account, match[0]]
174
+ end
175
+ }.compact
176
+ matches.sort_by! { |account, matched_text| matched_text.length }.map(&:first)
177
+ end
178
+
154
179
  # Weigh accounts by how well they match the row
155
180
  def weighted_account_match( row )
156
181
  query_tokens = tokenize(row[:description])
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = %q{reckon}
6
- s.version = "0.4.3"
6
+ s.version = "0.4.4"
7
7
  s.authors = ["Andrew Cantino", "BlackEdder"]
8
8
  s.email = %q{andrew@iterationlabs.com}
9
9
  s.homepage = %q{https://github.com/cantino/reckon}
@@ -5,9 +5,11 @@ Income:
5
5
  Expenses:
6
6
  Bank:
7
7
  - 'Comission'
8
- - 'MasterCard'
8
+ - /mastercard/i
9
9
  Rent:
10
10
  - '0011223344' # Landlord bank number
11
+ Websites:
12
+ - /web/i
11
13
  Books:
12
14
  - 'Book'
13
15
  '[Internal:Transfer]': # Virtual account
@@ -62,13 +62,14 @@ describe Reckon::App do
62
62
  @output_file.string.scan('Expenses:Books').count.should == 1
63
63
  end
64
64
 
65
- it 'should learn from an account tokens file' do
65
+ it 'should learn from an account tokens file and parse regexps' do
66
66
  @chase = Reckon::App.new(:string => BANK_CSV,
67
67
  :unattended => true,
68
68
  :output_file => @output_file,
69
69
  :account_tokens_file => 'spec/data_fixtures/tokens.yaml')
70
70
  @chase.walk_backwards
71
71
  @output_file.string.scan('Expenses:Books').count.should == 1
72
+ @output_file.string.scan('Expenses:Websites').count.should == 2
72
73
  end
73
74
  end
74
75
  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.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Cantino
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-08-16 00:00:00.000000000 Z
12
+ date: 2015-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec