amex_csv_to_ledger 0.1.0

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 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: []