reckon 0.4.3 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/Gemfile.lock +1 -1
 - data/README.md +2 -0
 - data/lib/reckon/app.rb +35 -10
 - data/reckon.gemspec +1 -1
 - data/spec/data_fixtures/tokens.yaml +3 -1
 - data/spec/reckon/app_spec.rb +2 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: cf1d814fe911f299cf58401c3b36734e29a172f1
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 9130495690de1f73cfa3570a6e3386f38df86830
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: b7c3e23f96983cd79844ba37524f1b843a1dbba230198cf813b83c7c65a076506fb2c66ab663dee0970db2d42e1d3e0b03adf41ee163d08f3b38dbb163c373a6
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: d74ab72db15d54bc0bfe548369ec9a8b3903760bc09fbc16340a6f64c929a69d595c4840900e8a425996bc580e5924321ece84b10d3e033b193b066f2520f7c2
         
     | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        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 
     | 
    
         
             
            ```
         
     | 
    
        data/lib/reckon/app.rb
    CHANGED
    
    | 
         @@ -4,12 +4,13 @@ require 'yaml' 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Reckon
         
     | 
| 
       6 
6 
     | 
    
         
             
              class App
         
     | 
| 
       7 
     | 
    
         
            -
                VERSION = "Reckon 0.4. 
     | 
| 
       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 
     | 
    
         
            -
                   
     | 
| 
       69 
     | 
    
         
            -
                     
     | 
| 
       70 
     | 
    
         
            -
                     
     | 
| 
       71 
     | 
    
         
            -
                     
     | 
| 
       72 
     | 
    
         
            -
                     
     | 
| 
      
 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 =  
     | 
| 
      
 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])
         
     | 
    
        data/reckon.gemspec
    CHANGED
    
    | 
         @@ -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. 
     | 
| 
      
 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}
         
     | 
    
        data/spec/reckon/app_spec.rb
    CHANGED
    
    | 
         @@ -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. 
     | 
| 
      
 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- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2015-12-02 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: rspec
         
     |