amex_csv_to_ledger 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 293cf23b091e043c0dfbb7a2e1ac82fcc5a42030d41a97124f4e3c469f205d38
4
+ data.tar.gz: 68f8bcbc78d056cb1209065b432b97e9697b60e9f112e463334f944a2f985df2
5
+ SHA512:
6
+ metadata.gz: f3a3991de3df88999aff7116d0d96a162fbb31bd9662c04abfba393208ed079e90e08f55247dd74dff6404f0bba25d8e3d531eb95b232cf40e34799716df276c
7
+ data.tar.gz: 5da02d8e0152f2a08fd0fe79b86dc97353ce35a375a789e0b777866ef31d076e9b163a6bb014098c6be949b2a2fa8f990806997bc10211da52a852e389b962bc
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ require:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
5
+ AllCops:
6
+ NewCops: enable
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'minitest', '~> 5.0'
8
+ gem 'pry-byebug', '~> 3.10'
9
+ gem 'rake', '~> 13.0'
10
+ gem 'rubocop', '~> 1.21'
11
+ gem 'rubocop-minitest', '~> 0.21'
12
+ gem 'rubocop-rake', '~> 0.6'
data/Gemfile.lock ADDED
@@ -0,0 +1,60 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ amex_csv_to_ledger (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ byebug (11.1.3)
11
+ coderay (1.1.3)
12
+ json (2.6.2)
13
+ method_source (1.0.0)
14
+ minitest (5.16.3)
15
+ parallel (1.22.1)
16
+ parser (3.1.2.1)
17
+ ast (~> 2.4.1)
18
+ pry (0.14.1)
19
+ coderay (~> 1.1)
20
+ method_source (~> 1.0)
21
+ pry-byebug (3.10.1)
22
+ byebug (~> 11.0)
23
+ pry (>= 0.13, < 0.15)
24
+ rainbow (3.1.1)
25
+ rake (13.0.6)
26
+ regexp_parser (2.5.0)
27
+ rexml (3.2.5)
28
+ rubocop (1.35.0)
29
+ json (~> 2.3)
30
+ parallel (~> 1.10)
31
+ parser (>= 3.1.2.1)
32
+ rainbow (>= 2.2.2, < 4.0)
33
+ regexp_parser (>= 1.8, < 3.0)
34
+ rexml (>= 3.2.5, < 4.0)
35
+ rubocop-ast (>= 1.20.1, < 2.0)
36
+ ruby-progressbar (~> 1.7)
37
+ unicode-display_width (>= 1.4.0, < 3.0)
38
+ rubocop-ast (1.21.0)
39
+ parser (>= 3.1.1.0)
40
+ rubocop-minitest (0.21.0)
41
+ rubocop (>= 0.90, < 2.0)
42
+ rubocop-rake (0.6.0)
43
+ rubocop (~> 1.0)
44
+ ruby-progressbar (1.11.0)
45
+ unicode-display_width (2.2.0)
46
+
47
+ PLATFORMS
48
+ x86_64-linux
49
+
50
+ DEPENDENCIES
51
+ amex_csv_to_ledger!
52
+ minitest (~> 5.0)
53
+ pry-byebug (~> 3.10)
54
+ rake (~> 13.0)
55
+ rubocop (~> 1.21)
56
+ rubocop-minitest (~> 0.21)
57
+ rubocop-rake (~> 0.6)
58
+
59
+ BUNDLED WITH
60
+ 2.3.7
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # AMEX CSV to Ledger
2
+
3
+ Configurable Ruby gem to convert American Express CSV statements to Ledger 3
4
+ format.
5
+
6
+ ## Dependencies
7
+
8
+ Requires Ruby 2.6 or above.
9
+
10
+ ## Installation
11
+
12
+ It's easiest to install it as a Ruby gem:
13
+
14
+ $ gem install amex_csv_to_ledger
15
+
16
+ ## Usage
17
+
18
+ Run the executable that ships with the gem and pass in the path to an AMEX CSV.
19
+
20
+ $ amex_csv_to_ledger statement.csv
21
+
22
+ The output will be the converted statement.
23
+
24
+ ## Configuration
25
+
26
+ It's possible to configure various things in the output of this script, such as
27
+ the currency, what category names to use, tabs vs. spaces, etc.
28
+
29
+ There's a template that is populated with the default values in the doc folder.
30
+ Copy it to your home config directory to use it.
31
+
32
+ mkdir ~/.config/amex_csv_to_ledger
33
+ cp doc/config.yml.example ~/.config/amex_csv_to_ledger/config.yml
34
+
35
+ Then edit it to your liking, it's a normal YAML file.
36
+
37
+ ## Development
38
+
39
+ After checking out the repo, run `bundle` to install dependencies. Then, run
40
+ `rake test` to run the tests.
41
+
42
+ Bear in mind when running tests that the tests will pick up the config in your
43
+ home directory. Remove it if you are getting failures.
44
+
45
+ To install this gem onto your local machine, run `bundle exec rake install`. To
46
+ release a new version, update the version number in `version.rb`, and then run
47
+ `bundle exec rake release`, which will create a git tag for the version, push
48
+ git commits and the created tag, and push the `.gem` file to
49
+ [rubygems.org](https://rubygems.org).
50
+
51
+ ## Contributing
52
+
53
+ Bug reports and pull requests are welcome. Send via email to the author, the
54
+ address is in git.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/test_*.rb']
10
+ end
11
+
12
+ require 'rubocop/rake_task'
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
@@ -0,0 +1,6 @@
1
+ date_format: '%Y-%m-%d'
2
+ use_tabs: false
3
+ indent_size: 4
4
+ currency_prefixed: false
5
+ currency: 'GBP'
6
+ amex_category: 'liabilities:creditcard:amex'
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module AmexCsvToLedger
6
+ # Class to load and parse the config file.
7
+ class Config
8
+ DEFAULT_PATH = '~/.config/amex_csv_to_ledger/config.yml'
9
+
10
+ def initialize(path = DEFAULT_PATH)
11
+ @config = YAML.load_file(File.expand_path(path))
12
+ rescue StandardError
13
+ @config = {}
14
+ end
15
+
16
+ def date_format
17
+ @config.fetch('date_format', '%Y-%m-%d')
18
+ end
19
+
20
+ def use_tabs?
21
+ @config.fetch('use_tabs', false)
22
+ end
23
+
24
+ def indent_size
25
+ @config.fetch('indent_size', 4)
26
+ end
27
+
28
+ def expense_placeholder
29
+ @config.fetch('expense_placeholder', 'expenses:placeholder')
30
+ end
31
+
32
+ def currency_prefixed?
33
+ @config.fetch('currency_prefixed', false)
34
+ end
35
+
36
+ def currency
37
+ @config.fetch('currency', 'GBP')
38
+ end
39
+
40
+ def amex_category
41
+ @config.fetch('amex_category', 'liabilities:creditcard:amex')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module AmexCsvToLedger
6
+ # Class to format ledger date lines with a description.
7
+ class LedgerDateLine
8
+ AMEX_DATE_FORMAT = '%Y/%m/%d'
9
+
10
+ attr_reader :description
11
+
12
+ def initialize(date:, description:)
13
+ @date = date
14
+ @description = description
15
+ end
16
+
17
+ def output
18
+ "#{date} #{description}"
19
+ end
20
+
21
+ private
22
+
23
+ def date
24
+ parsed_date.strftime(date_format)
25
+ end
26
+
27
+ def parsed_date
28
+ Date.parse(@date, AMEX_DATE_FORMAT)
29
+ end
30
+
31
+ def date_format
32
+ AmexCsvToLedger.config.date_format
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmexCsvToLedger
4
+ # Class to format ledger expense lines with a currency amount.
5
+ class LedgerExpenseLine
6
+ DEFAULT_SPACING = 62 # spacing used by LedgerAlignBuffer
7
+ TAB_LENGTH = 8
8
+
9
+ attr_reader :amount
10
+
11
+ def initialize(amount:)
12
+ @amount = amount
13
+ end
14
+
15
+ def output
16
+ "#{indent}#{placeholder}#{spaces}#{formatted_amount}"
17
+ end
18
+
19
+ private
20
+
21
+ def indent
22
+ if use_tabs?
23
+ "\t"
24
+ else
25
+ ' ' * indent_size
26
+ end
27
+ end
28
+
29
+ def placeholder
30
+ AmexCsvToLedger.config.expense_placeholder
31
+ end
32
+
33
+ def spaces
34
+ ' ' * spacing
35
+ end
36
+
37
+ def spacing
38
+ len = DEFAULT_SPACING - indent_size - placeholder.length - amount.length
39
+
40
+ if currency_prefixed?
41
+ len - currency.length
42
+ else
43
+ len
44
+ end
45
+ end
46
+
47
+ def currency
48
+ AmexCsvToLedger.config.currency
49
+ end
50
+
51
+ def use_tabs?
52
+ AmexCsvToLedger.config.use_tabs?
53
+ end
54
+
55
+ def indent_size
56
+ if use_tabs?
57
+ TAB_LENGTH
58
+ else
59
+ AmexCsvToLedger.config.indent_size
60
+ end
61
+ end
62
+
63
+ def currency_prefixed?
64
+ AmexCsvToLedger.config.currency_prefixed?
65
+ end
66
+
67
+ def formatted_amount
68
+ if currency_prefixed?
69
+ "#{currency}#{amount}"
70
+ else
71
+ "#{amount} #{currency}"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmexCsvToLedger
4
+ # Class to format ledger outgoing lines.
5
+ class LedgerOutgoingLine
6
+ TAB_LENGTH = 8
7
+
8
+ def output
9
+ "#{indent}#{outgoing_account}"
10
+ end
11
+
12
+ private
13
+
14
+ def indent
15
+ if use_tabs?
16
+ "\t"
17
+ else
18
+ ' ' * indent_size
19
+ end
20
+ end
21
+
22
+ def outgoing_account
23
+ AmexCsvToLedger.config.amex_category
24
+ end
25
+
26
+ def use_tabs?
27
+ AmexCsvToLedger.config.use_tabs?
28
+ end
29
+
30
+ def indent_size
31
+ AmexCsvToLedger.config.indent_size
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmexCsvToLedger
4
+ # A class to glue together all the ledger lines to create a full report.
5
+ class LedgerReport
6
+ attr_reader :statement
7
+
8
+ def initialize(statement)
9
+ @statement = statement
10
+ end
11
+
12
+ def lines
13
+ statement.lines.map do |line|
14
+ [
15
+ date_line(line),
16
+ expense_line(line),
17
+ outgoing_line
18
+ ].join("\n")
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def date_line(line)
25
+ LedgerDateLine.new(
26
+ date: line.date,
27
+ description: line.description
28
+ ).output
29
+ end
30
+
31
+ def expense_line(line)
32
+ LedgerExpenseLine.new(amount: line.amount).output
33
+ end
34
+
35
+ def outgoing_line
36
+ LedgerOutgoingLine.new.output
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ module AmexCsvToLedger
6
+ # Class to hold the data found in an AMEX statement.
7
+ class Statement
8
+ attr_reader :csv
9
+
10
+ def initialize(csv)
11
+ @csv = csv
12
+ end
13
+
14
+ def lines
15
+ @lines ||= CSV.parse(csv, headers: true).map do |row|
16
+ StatementLine.new(
17
+ amount: row['Amount'],
18
+ date: row['Date'],
19
+ description: row['Description']
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmexCsvToLedger
4
+ # Class to hold the data found in a line of an AMEX statement.
5
+ class StatementLine
6
+ attr_reader :amount, :date, :description
7
+
8
+ def initialize(amount:, date:, description:)
9
+ @amount = amount
10
+ @date = date
11
+ @description = description
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AmexCsvToLedger
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'amex_csv_to_ledger/version'
4
+ require_relative 'amex_csv_to_ledger/config'
5
+ require_relative 'amex_csv_to_ledger/ledger_date_line'
6
+ require_relative 'amex_csv_to_ledger/ledger_expense_line'
7
+ require_relative 'amex_csv_to_ledger/ledger_outgoing_line'
8
+ require_relative 'amex_csv_to_ledger/ledger_report'
9
+ require_relative 'amex_csv_to_ledger/statement'
10
+ require_relative 'amex_csv_to_ledger/statement_line'
11
+
12
+ # Top level class for the converter which glues together all of the code.
13
+ module AmexCsvToLedger
14
+ def self.convert(csv_path)
15
+ csv = File.open(csv_path)
16
+ statement = Statement.new(csv)
17
+ puts LedgerReport.new(statement).lines.join("\n\n")
18
+ end
19
+
20
+ def self.config
21
+ Config.new
22
+ end
23
+ end
data/tmp/.gitkeep ADDED
File without changes
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amex_csv_to_ledger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - baak6
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-08-22 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Command line utility to convert AMEX CSV to Ledger.
14
+ email:
15
+ - baak6@baak6.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".rubocop.yml"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - README.md
24
+ - Rakefile
25
+ - doc/config.yml.example
26
+ - lib/amex_csv_to_ledger.rb
27
+ - lib/amex_csv_to_ledger/config.rb
28
+ - lib/amex_csv_to_ledger/ledger_date_line.rb
29
+ - lib/amex_csv_to_ledger/ledger_expense_line.rb
30
+ - lib/amex_csv_to_ledger/ledger_outgoing_line.rb
31
+ - lib/amex_csv_to_ledger/ledger_report.rb
32
+ - lib/amex_csv_to_ledger/statement.rb
33
+ - lib/amex_csv_to_ledger/statement_line.rb
34
+ - lib/amex_csv_to_ledger/version.rb
35
+ - tmp/.gitkeep
36
+ homepage: https://git.baak6.com/amex_csv_to_ledger.git/
37
+ licenses:
38
+ - GPL-3.0
39
+ metadata:
40
+ source_code_uri: https://git.baak6.com/amex_csv_to_ledger.git/
41
+ rubygems_mfa_required: 'true'
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.6.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.3.7
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: AMEX CSV to Ledger.
61
+ test_files: []