hledger-forecast 1.3.0 → 1.5.0

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: ac4e0a16f2b440612fb4596519b02c02d4a88b0d5f9cdb95c0988047a9892c3e
4
- data.tar.gz: 6f9aed952f65c445d965a9b3dd7ccdb25fdb2c300bdee748ffab51b6a5a5056e
3
+ metadata.gz: 0f769e017bc9ad46ea7d7571f74c64286e9c2415d0696e40f3301438a9038514
4
+ data.tar.gz: 52f69b30edfbc0c9d5430b88d25687c9c311d6c6aa4b1e5fd3b2815b3602d240
5
5
  SHA512:
6
- metadata.gz: 40eb12f6238c4cc0f8fc37e85a74a6f4e88fbbd12917b07dfd2d305dd47f0cb09e1c999a343744d5766cb03c1484533e67ae6eb3e7ed6a7c3548f5f177eea55e
7
- data.tar.gz: e09a771caf387bf62d9b09ca58ff59073589edeb0d9cbc3a9523246c31b7172b83869101fe6a020474d501a3b739dbe7a24ac6676a4baafb1380a5fe0c2a84b5
6
+ metadata.gz: 2721eb985469db575b66172a94ee670e96711437da7b94f27da53301beed9f385b46c19121c9d365ce01fb0423ea5ea728ce511296c29adc26fc2051ff33e794
7
+ data.tar.gz: e41363954be45ca668dd73cc1a816b47a94419be53cde4fccdfc5a88a55601a2166e5f6eeb6532d4673c3bfe204020122165b71fabcca07a9dbf7cf0f1f80271
data/README.md CHANGED
@@ -11,30 +11,30 @@
11
11
  <a href="https://github.com/olimorris/hledger-forecast/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/olimorris/hledger-forecast/ci.yml?branch=main&label=tests&style=for-the-badge"></a>
12
12
  </p>
13
13
 
14
- **"Improved", you say?** Using a _CSV_ (or _YML_) file, forecasts can be quickly generated into a _journal_ file ready to be fed into [hledger](https://github.com/simonmichael/hledger). **A 15 line [CSV file](https://github.com/olimorris/hledger-forecast/blob/main/example.csv) can generate a 42 line hledger [forecast file](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)!**
14
+ **"Improved", you say?** Using a _CSV_ (or _YML_) file, forecasts can be quickly generated into a _journal_ file ready to be fed into [hledger](https://github.com/simonmichael/hledger). **A 16 line [CSV file](https://github.com/olimorris/hledger-forecast/blob/main/example.csv) can generate a 46 line hledger [forecast file](https://github.com/olimorris/hledger-forecast/blob/main/example.journal)!**
15
15
 
16
16
  Forecasts can also be constrained between dates, inflated by modifiers, tracked until they appear in your bank statements and summarized into your own daily/weekly/monthly/yearly personal forecast income and expenditure statement.
17
17
 
18
18
  ## :sparkles: Features
19
19
 
20
- - :muscle: Uses a simple CSV (or YML) file to generate forecasts which can be used with hledger
21
- - :date: Can smartly track forecasts against your bank statement
22
- - :moneybag: Can automatically apply modifiers such as inflation/deflation to forecasts
23
- - :abacus: Enables the use of maths in your forecasts (for amounts and dates)
24
- - :chart_with_upwards_trend: Display your forecasts as income and expenditure reports (e.g. daily, weekly, monthly)
20
+ - :rocket: Uses a simple CSV (or YML) file to generate forecasts which can be used with hledger
21
+ - :calendar: Can smartly track forecasts against your bank statement
22
+ - :dollar: Can automatically apply modifiers such as inflation/deflation to forecasts
23
+ - :mag: Enables the use of maths in your forecasts (for amounts and dates)
24
+ - :bar_chart: Display your forecasts as income and expenditure reports (e.g. daily, weekly, monthly)
25
+ - :twisted_rightwards_arrows: Compare and display the difference between hledger outputs
25
26
  - :computer: Simple and easy to use CLI
26
27
 
27
28
  ## :camera_flash: Screenshots
28
29
 
29
- **CSV forecast and corresponding journal output**
30
+ **A CSV forecast and the hledger journal it generates**
30
31
 
31
- <img src="https://github.com/olimorris/hledger-forecast/assets/9512444/430503b5-f447-4972-b122-b48f8628aff9" alt="Hledger-Forecast" />
32
+ <img src="https://github.com/olimorris/hledger-forecast/assets/9512444/430503b5-f447-4972-b122-b48f8628aff9" alt="hledger-Forecast" />
32
33
 
33
- **Output from the `summarize` command**
34
+ **The ouput from the `summarize` command**
34
35
 
35
36
  <img src="https://github.com/olimorris/hledger-forecast/assets/9512444/f5017ea2-9606-46ec-8b38-8840dc175e7b" alt="Summarize command" />
36
37
 
37
-
38
38
  ## :package: Installation
39
39
 
40
40
  Assuming you have Ruby and [Rubygems](http://rubygems.org/pages/download) installed on your system, simply run:
@@ -52,8 +52,9 @@ The available options are:
52
52
  Usage: hledger-forecast [command] [options]
53
53
 
54
54
  Commands:
55
- generate Generate the forecast file
55
+ generate Generate a forecast from a file
56
56
  summarize Summarize the forecast file and output to the terminal
57
+ compare Compare and highlight the differences between two CSV files
57
58
 
58
59
  Options:
59
60
  -h, --help Show this help message
@@ -70,6 +71,7 @@ The available options are:
70
71
  -f, --forecast FILE The path to the FORECAST CSV/YML file to generate from
71
72
  -o, --output-file FILE The path to the OUTPUT file to create
72
73
  -t, --transaction FILE The path to the TRANSACTION journal file
74
+ -v, --verbose Don't group transactions by type in the output file
73
75
  --force Force an overwrite of the output file
74
76
  --no-track Don't track any transactions
75
77
  -h, --help Show this help message
@@ -86,11 +88,11 @@ To work with hledger, include the forecast file and use the `--forecast` flag:
86
88
 
87
89
  The command will generate a forecast up to the end of Feb 2024, showing the balance for any asset accounts, overlaying some bank transactions with the forecast journal file. Forecasting in hledger can be complicated so be sure to refer to the [documentation](https://hledger.org/dev/hledger.html) or start a [discussion](https://github.com/olimorris/hledger-forecast/discussions/new?category=q-a).
88
90
 
91
+ If you use the `hledger-ui` tool, it may be helpful to use the `--verbose` flag. This ensures that transactions are not grouped together in the forecast journal file, making descriptions much easier to read.
92
+
89
93
  ### Summarize command
90
94
 
91
- As your configuration file grows, it can be helpful to sum up the total amounts and output them to the CLI.
92
- Furthermore, being able to see your monthly profit and loss statement _if_ you were to purchase that new item may
93
- influence your buying decision. In hledger-forecast, this can be achieved by:
95
+ As your forecast file grows, it can be helpful to sum up the total amounts and output them to the CLI. Think of this command as your own _profit and loss_ summarizer, generating a statement over a period you specify.
94
96
 
95
97
  hledger-forecast summarize -f my_forecast.csv
96
98
 
@@ -104,6 +106,18 @@ The available options are:
104
106
  -v, --verbose Show additional information in the summary
105
107
  -h, --help Show this help message
106
108
 
109
+ ### Compare command
110
+
111
+ A core part of managing your personal finances is the comparison of what you _expected_ to happen versus what _actually_ happened. This can be challenging to accomplish with hledger so to make this easier, the app has a useful `compare` command:
112
+
113
+ hledger-forecast compare [path/to/file1.csv] [path/to/file2.csv]
114
+
115
+ To generate CSV output with hledger, append `-O csv > output.csv` to your desired command.
116
+
117
+ To make it easier to read horizontal output in the terminal, consider the use of a terminal pager like [most](https://en.wikipedia.org/wiki/Most_(Unix)) by appending `| most` to the compare command.
118
+
119
+ > **Note:** The two CSV files being compared must have the same structure
120
+
107
121
  ## :gear: Creating your forecast
108
122
 
109
123
  The app makes it easy to generate a comprehensive _journal_ file with very few lines of code, making it much easier to stay on top of your forecasting from month to month.
@@ -372,4 +386,3 @@ The app will use a hledger query to determine if the combination of category and
372
386
  ## :pencil2: Contributing
373
387
 
374
388
  I am open to any pull requests that fix bugs but would ask that any new functionality is discussed before it could be accepted.
375
-
@@ -8,6 +8,8 @@ module HledgerForecast
8
8
  generate(options)
9
9
  when 'summarize'
10
10
  summarize(options)
11
+ when 'compare'
12
+ compare(options)
11
13
  else
12
14
  puts "Unknown command: #{command}"
13
15
  exit(1)
@@ -22,8 +24,9 @@ module HledgerForecast
22
24
  opts.banner = "Usage: hledger-forecast [command] [options]"
23
25
  opts.separator ""
24
26
  opts.separator "Commands:"
25
- opts.separator " generate Generate the forecast file"
27
+ opts.separator " generate Generate a forecast from a file"
26
28
  opts.separator " summarize Summarize the forecast file and output to the terminal"
29
+ opts.separator " compare Compare and highlight the differences between two CSV files"
27
30
  opts.separator ""
28
31
  opts.separator "Options:"
29
32
 
@@ -38,6 +41,11 @@ module HledgerForecast
38
41
  end
39
42
  end
40
43
 
44
+ if args.empty?
45
+ puts global
46
+ exit(1)
47
+ end
48
+
41
49
  begin
42
50
  global.order!(args)
43
51
  command = args.shift || 'generate'
@@ -52,6 +60,8 @@ module HledgerForecast
52
60
  options = parse_generate_options(args)
53
61
  when 'summarize'
54
62
  options = parse_summarize_options(args)
63
+ when 'compare'
64
+ options = parse_compare_options(args)
55
65
  else
56
66
  puts "Unknown command: #{command}"
57
67
  puts global
@@ -64,7 +74,7 @@ module HledgerForecast
64
74
  def self.parse_generate_options(args)
65
75
  options = {}
66
76
 
67
- OptionParser.new do |opts|
77
+ global = OptionParser.new do |opts|
68
78
  opts.banner = "Usage: hledger-forecast generate [options]"
69
79
  opts.separator ""
70
80
 
@@ -91,6 +101,11 @@ module HledgerForecast
91
101
  options[:transaction_file] = file
92
102
  end
93
103
 
104
+ opts.on("-v", "--verbose",
105
+ "Don't group transactions by type in the output file") do
106
+ options[:verbose] = true
107
+ end
108
+
94
109
  opts.on("--force",
95
110
  "Force an overwrite of the output file") do
96
111
  options[:force] = true
@@ -105,11 +120,24 @@ module HledgerForecast
105
120
  puts opts
106
121
  exit
107
122
  end
108
- end.parse!(args)
123
+ end
124
+
125
+ begin
126
+ global.parse!(args)
127
+ rescue OptionParser::InvalidOption => e
128
+ puts e
129
+ puts global
130
+ exit(1)
131
+ end
132
+
133
+ if options.empty?
134
+ puts global
135
+ exit(1)
136
+ end
109
137
 
110
- options[:forecast_file] = "forecast.csv" unless options[:forecast_file]
111
- options[:file_type] = "csv" unless options[:file_type]
112
- options[:output_file] = "forecast.journal" unless options[:output_file]
138
+ options[:forecast_file] ||= "forecast.csv"
139
+ options[:file_type] ||= "csv"
140
+ options[:output_file] ||= "forecast.journal"
113
141
 
114
142
  options
115
143
  end
@@ -117,7 +145,7 @@ module HledgerForecast
117
145
  def self.parse_summarize_options(args)
118
146
  options = {}
119
147
 
120
- OptionParser.new do |opts|
148
+ global = OptionParser.new do |opts|
121
149
  opts.banner = "Usage: hledger-forecast summarize [options]"
122
150
  opts.separator ""
123
151
 
@@ -163,7 +191,47 @@ module HledgerForecast
163
191
  puts opts
164
192
  exit
165
193
  end
166
- end.parse!(args)
194
+ end
195
+
196
+ begin
197
+ global.parse!(args)
198
+ rescue OptionParser::InvalidOption => e
199
+ puts e
200
+ puts global
201
+ exit(1)
202
+ end
203
+
204
+ if options.empty?
205
+ puts global
206
+ exit(1)
207
+ end
208
+
209
+ options
210
+ end
211
+
212
+ def self.parse_compare_options(args)
213
+ options = {}
214
+
215
+ global = OptionParser.new do |opts|
216
+ opts.banner = "Usage: hledger-forecast compare [path/to/file1.csv] [path/to/file2.csv]"
217
+ opts.separator ""
218
+ end
219
+
220
+ begin
221
+ global.parse!(args)
222
+ rescue OptionParser::InvalidOption => e
223
+ puts e
224
+ puts global
225
+ exit(1)
226
+ end
227
+
228
+ if args[0].nil? || args[1].nil?
229
+ puts global
230
+ exit(1)
231
+ end
232
+
233
+ options[:file1] = args[0]
234
+ options[:file2] = args[1]
167
235
 
168
236
  options
169
237
  end
@@ -205,5 +273,13 @@ module HledgerForecast
205
273
 
206
274
  puts SummarizerFormatter.format(summarizer[:output], summarizer[:settings])
207
275
  end
276
+
277
+ def self.compare(options)
278
+ if !File.exist?(options[:file1]) || !File.exist?(options[:file2])
279
+ return puts "\nError: ".bold.red + "One or more of the files could not be found to compare"
280
+ end
281
+
282
+ puts Comparator.compare(options[:file1], options[:file2])
283
+ end
208
284
  end
209
285
  end
@@ -0,0 +1,80 @@
1
+ module HledgerForecast
2
+ # Compare the output of two CSV files
3
+ class Comparator
4
+ def initialize
5
+ @table = Terminal::Table.new
6
+ end
7
+
8
+ def self.compare(file1, file2)
9
+ new.compare(file1, file2)
10
+ end
11
+
12
+ def compare(file1, file2)
13
+ compare_csvs(file1, file2)
14
+ end
15
+
16
+ private
17
+
18
+ def compare_csvs(file1, file2)
19
+ csv1 = CSV.read(file1)
20
+ csv2 = CSV.read(file2)
21
+
22
+ unless csv1.length == csv2.length && csv1[0].length == csv2[0].length
23
+ return puts "\nError: ".bold.red + "The files have different formats and cannot be compared"
24
+ end
25
+
26
+ @table.add_row csv2[0].map(&:bold)
27
+ @table.add_separator
28
+
29
+ generate_diff(csv1, csv2).drop(1).each do |row|
30
+ @table.add_row [row[0].bold] + row[1..]
31
+ end
32
+
33
+ puts @table
34
+ end
35
+
36
+ def header?(row_num)
37
+ row_num == 0
38
+ end
39
+
40
+ def generate_diff(csv1, csv2)
41
+ csv1.each_with_index.map do |row, i|
42
+ row.each_with_index.map do |cell, j|
43
+ if header?(i) || j == 0 # Checking for the first column here
44
+ csv2[i][j]
45
+ else
46
+ difference = parse_money(cell) - parse_money(csv2[i][j])
47
+ format_difference(difference, detect_currency(cell))
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def detect_currency(str)
54
+ # Explicitly check for common currencies first
55
+ return "GBP" if str.include?("£")
56
+ return "EUR" if str.include?("€")
57
+ return "USD" if str.include?("$")
58
+
59
+ Money::Currency.table.each_value do |currency|
60
+ return currency[:iso_code] if str.include?(currency[:symbol])
61
+ end
62
+
63
+ nil
64
+ end
65
+
66
+ def parse_money(value)
67
+ # Remove currency symbols and parse the result as a float, then convert to cents
68
+ cleaned_value = value.gsub(/[^0-9.]/, '').to_f
69
+ cleaned_value.to_i
70
+ end
71
+
72
+ def format_difference(amount, currency)
73
+ formatted_amount = Formatter.format_money(amount, { currency: currency })
74
+
75
+ return formatted_amount if amount == 0
76
+
77
+ amount > 0 ? formatted_amount.green : formatted_amount.red
78
+ end
79
+ end
80
+ end
@@ -13,11 +13,7 @@ module HledgerForecast
13
13
  def generate
14
14
  data.each_value do |blocks|
15
15
  blocks.each do |block|
16
- if block[:type] == "custom"
17
- process_custom_block(block)
18
- else
19
- process_block(block)
20
- end
16
+ process_block(block)
21
17
  end
22
18
  end
23
19
 
@@ -34,30 +30,59 @@ module HledgerForecast
34
30
  @output = []
35
31
  end
36
32
 
37
- def process_custom_block(block)
33
+ def process_block(block)
38
34
  block[:transactions].each do |to, transactions|
39
35
  to = get_header(block[:to], to)
40
36
 
41
- transactions.each do |t|
42
- header = "~ #{t[:frequency]} from #{block[:from]}#{to} * #{t[:description]}\n"
43
- footer = " #{block[:account]}\n\n"
44
- output << { header: header, transactions: write_transactions([t]), footer: footer }
37
+ if block[:type] == "custom"
38
+ process_custom_transactions(block, to, transactions)
39
+ else
40
+ process_standard_transactions(block, to, transactions)
45
41
  end
46
42
  end
47
43
  end
48
44
 
49
- def process_block(block)
50
- block[:transactions].each do |to, transactions|
51
- to = get_header(block[:to], to)
52
- block[:descriptions] = get_descriptions(transactions)
45
+ def process_custom_transactions(block, to, transactions)
46
+ transactions.each do |t|
47
+ frequency = get_periodic_rules(block[:type], t[:frequency])
53
48
 
54
- frequency = get_periodic_rules(block[:type], block[:frequency])
49
+ header = build_header(block, to, frequency, t[:description])
50
+ footer = build_footer(block)
51
+ output << build_transaction(header, [t], footer)
52
+ end
53
+ end
55
54
 
56
- header = "#{frequency} #{block[:from]}#{to} * #{block[:descriptions]}\n"
57
- footer = " #{block[:account]}\n\n"
55
+ def process_standard_transactions(block, to, transactions)
56
+ if @options[:verbose]
57
+ transactions.map do |t|
58
+ # Skip transactions that have been marked as tracked
59
+ next if t[:track]
58
60
 
59
- output << { header: header, transactions: write_transactions(transactions), footer: footer }
61
+ frequency = get_periodic_rules(block[:type], block[:frequency])
62
+ header = build_header(block, to, frequency, t[:description])
63
+ footer = build_footer(block)
64
+ output << build_transaction(header, [t], footer)
65
+ end
66
+ return
60
67
  end
68
+
69
+ block[:descriptions] = get_descriptions(transactions)
70
+ frequency = get_periodic_rules(block[:type], block[:frequency])
71
+ header = build_header(block, to, frequency, block[:descriptions])
72
+ footer = build_footer(block)
73
+ output << build_transaction(header, transactions, footer)
74
+ end
75
+
76
+ def build_header(block, to, frequency, description)
77
+ "#{frequency} #{block[:from]}#{to} * #{description}\n"
78
+ end
79
+
80
+ def build_footer(block)
81
+ " #{block[:account]}\n\n"
82
+ end
83
+
84
+ def build_transaction(header, transactions, footer)
85
+ { header: header, transactions: write_transactions(transactions), footer: footer }
61
86
  end
62
87
 
63
88
  def get_header(block, transaction)
@@ -1,3 +1,3 @@
1
1
  module HledgerForecast
2
- VERSION = "1.3.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -12,9 +12,11 @@ require 'yaml'
12
12
 
13
13
  Money.locale_backend = nil
14
14
  Money.rounding_mode = BigDecimal::ROUND_HALF_UP
15
+ Money.default_currency = 'USD'
15
16
 
16
17
  require_relative 'hledger_forecast/calculator'
17
18
  require_relative 'hledger_forecast/cli'
19
+ require_relative 'hledger_forecast/comparator'
18
20
  require_relative 'hledger_forecast/csv_parser'
19
21
  require_relative 'hledger_forecast/formatter'
20
22
  require_relative 'hledger_forecast/generator'
@@ -12,6 +12,19 @@ output = <<~JOURNAL
12
12
 
13
13
  JOURNAL
14
14
 
15
+ def strip_ansi_codes(str)
16
+ str.gsub(/\e\[([;\d]+)?m/, "")
17
+ end
18
+
19
+ def capture_stdout
20
+ old_stdout = $stdout
21
+ $stdout = StringIO.new
22
+ yield
23
+ $stdout.string
24
+ ensure
25
+ $stdout = old_stdout
26
+ end
27
+
15
28
  RSpec.describe 'command' do
16
29
  it 'uses the CLI to generate an output' do
17
30
  generated_journal = './test_output.journal'
@@ -30,4 +43,19 @@ RSpec.describe 'command' do
30
43
 
31
44
  expect(File.read(generated_journal)).to eq(output)
32
45
  end
46
+
47
+ it 'uses the CLI to compare two CSV files' do
48
+ expected_output = strip_ansi_codes(<<~OUTPUT)
49
+ +---------+---------+---------+
50
+ | account | 2023-07 | 2023-08 |
51
+ +---------+---------+---------+
52
+ | total | £-10.00 | €10.00 |
53
+ +---------+---------+---------+
54
+
55
+ OUTPUT
56
+
57
+ actual_output = `./bin/hledger-forecast compare ./spec/stubs/output1.csv ./spec/stubs/output2.csv`
58
+
59
+ expect(strip_ansi_codes(actual_output)).to eq(expected_output)
60
+ end
33
61
  end
@@ -0,0 +1,54 @@
1
+ require_relative '../lib/hledger_forecast'
2
+ require 'stringio'
3
+
4
+ def strip_ansi_codes(str)
5
+ str.gsub(/\e\[([;\d]+)?m/, "")
6
+ end
7
+
8
+ def capture_stdout
9
+ old_stdout = $stdout
10
+ $stdout = StringIO.new
11
+ yield
12
+ $stdout.string
13
+ ensure
14
+ $stdout = old_stdout
15
+ end
16
+
17
+ RSpec.describe HledgerForecast::Comparator do
18
+ let(:file1_content) do
19
+ <<~CSV
20
+ "account","2023-07","2023-08"
21
+ "total","£100.00","€200.00"
22
+ CSV
23
+ end
24
+
25
+ let(:file2_content) do
26
+ <<~CSV
27
+ "account","2023-07","2023-08"
28
+ "total","£110.00","€190.00"
29
+ CSV
30
+ end
31
+
32
+ let(:file1) { StringIO.new(file1_content) }
33
+ let(:file2) { StringIO.new(file2_content) }
34
+
35
+ before do
36
+ allow(CSV).to receive(:read).with('file1.csv').and_return(CSV.parse(file1.read))
37
+ allow(CSV).to receive(:read).with('file2.csv').and_return(CSV.parse(file2.read))
38
+ end
39
+
40
+ it "compares the contents of two CSV files and outputs the difference" do
41
+ comparator = described_class.new
42
+
43
+ expected_output = strip_ansi_codes(<<~OUTPUT)
44
+ +---------+---------+---------+
45
+ | account | 2023-07 | 2023-08 |
46
+ +---------+---------+---------+
47
+ | total | £-10.00 | €10.00 |
48
+ +---------+---------+---------+
49
+ OUTPUT
50
+
51
+ actual_output = capture_stdout { comparator.compare('file1.csv', 'file2.csv') }
52
+ expect(strip_ansi_codes(actual_output)).to eq(expected_output)
53
+ end
54
+ end
@@ -0,0 +1,2 @@
1
+ "account","2023-07","2023-08"
2
+ "total","£100.00","€200.00"
@@ -0,0 +1,2 @@
1
+ "account","2023-07","2023-08"
2
+ "total","£110.00","€190.00"
@@ -0,0 +1,27 @@
1
+ require_relative '../lib/hledger_forecast'
2
+
3
+ output = <<~JOURNAL
4
+ ~ monthly from 2023-03-01 * Mortgage
5
+ Expenses:Mortgage £2,000.55; Mortgage
6
+ Assets:Bank
7
+
8
+ ~ monthly from 2023-03-01 * Food
9
+ Expenses:Food £100.00 ; Food
10
+ Assets:Bank
11
+
12
+ ~ monthly from 2023-03-01 * Savings
13
+ Assets:Bank £-1,000.00; Savings
14
+ Assets:Savings
15
+
16
+ JOURNAL
17
+
18
+ RSpec.describe 'verbose command' do
19
+ it 'does not group similar type transactions together in the output' do
20
+ generated_journal = './test_output.journal'
21
+ File.delete(generated_journal) if File.exist?(generated_journal)
22
+
23
+ system("./bin/hledger-forecast generate -f ./spec/stubs/forecast.csv -o ./test_output.journal --verbose --force")
24
+
25
+ expect(File.read(generated_journal)).to eq(output)
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hledger-forecast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oli Morris
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-09 00:00:00.000000000 Z
11
+ date: 2023-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -116,6 +116,7 @@ files:
116
116
  - lib/hledger_forecast.rb
117
117
  - lib/hledger_forecast/calculator.rb
118
118
  - lib/hledger_forecast/cli.rb
119
+ - lib/hledger_forecast/comparator.rb
119
120
  - lib/hledger_forecast/csv_parser.rb
120
121
  - lib/hledger_forecast/formatter.rb
121
122
  - lib/hledger_forecast/generator.rb
@@ -126,7 +127,8 @@ files:
126
127
  - lib/hledger_forecast/transactions/modifiers.rb
127
128
  - lib/hledger_forecast/transactions/trackers.rb
128
129
  - lib/hledger_forecast/version.rb
129
- - spec/command_spec.rb
130
+ - spec/cli_spec.rb
131
+ - spec/compare_spec.rb
130
132
  - spec/computed_amounts_spec.rb
131
133
  - spec/csv_and_yml_comparison_spec.rb
132
134
  - spec/csv_parser_spec.rb
@@ -140,11 +142,14 @@ files:
140
142
  - spec/quarterly_spec.rb
141
143
  - spec/stubs/forecast.csv
142
144
  - spec/stubs/forecast.yml
145
+ - spec/stubs/output1.csv
146
+ - spec/stubs/output2.csv
143
147
  - spec/stubs/transactions_found.journal
144
148
  - spec/stubs/transactions_found_inverse.journal
145
149
  - spec/stubs/transactions_not_found.journal
146
150
  - spec/summarizer_spec.rb
147
151
  - spec/track_spec.rb
152
+ - spec/verbose_output_spec.rb
148
153
  - spec/yearly_spec.rb
149
154
  homepage: https://github.com/olimorris/hledger-forecast
150
155
  licenses:
@@ -165,12 +170,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
170
  - !ruby/object:Gem::Version
166
171
  version: '0'
167
172
  requirements: []
168
- rubygems_version: 3.4.13
173
+ rubygems_version: 3.4.19
169
174
  signing_key:
170
175
  specification_version: 4
171
176
  summary: An extended wrapper around hledger's forecasting functionality
172
177
  test_files:
173
- - spec/command_spec.rb
178
+ - spec/cli_spec.rb
179
+ - spec/compare_spec.rb
174
180
  - spec/computed_amounts_spec.rb
175
181
  - spec/csv_and_yml_comparison_spec.rb
176
182
  - spec/csv_parser_spec.rb
@@ -184,9 +190,12 @@ test_files:
184
190
  - spec/quarterly_spec.rb
185
191
  - spec/stubs/forecast.csv
186
192
  - spec/stubs/forecast.yml
193
+ - spec/stubs/output1.csv
194
+ - spec/stubs/output2.csv
187
195
  - spec/stubs/transactions_found.journal
188
196
  - spec/stubs/transactions_found_inverse.journal
189
197
  - spec/stubs/transactions_not_found.journal
190
198
  - spec/summarizer_spec.rb
191
199
  - spec/track_spec.rb
200
+ - spec/verbose_output_spec.rb
192
201
  - spec/yearly_spec.rb