bouch 1.2.0 → 2.0.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 +4 -4
- data/.gitlab-ci.yml +8 -0
- data/.rubocop.yml +13 -14
- data/.simplecov +2 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +52 -35
- data/README.md +44 -12
- data/Rakefile +5 -0
- data/bouch.gemspec +8 -8
- data/lib/bouch/calc.rb +16 -11
- data/lib/bouch/cli.rb +12 -4
- data/lib/bouch/example.rb +43 -0
- data/lib/bouch/version.rb +1 -1
- data/lib/bouch.rb +68 -35
- data/spec/bouch_calc_spec.rb +10 -22
- data/spec/bouch_cli_spec.rb +64 -3
- data/spec/bouch_pouch_yaml_spec.rb +2 -2
- data/spec/bouch_spec.rb +42 -4
- data/spec/spec_helper.rb +10 -0
- metadata +25 -21
- data/pouch.example.yml +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1703d82906883118087626db522e171f841ca1b3bfa9792731da9e05ebbbf08c
|
|
4
|
+
data.tar.gz: 8a956f18ac52e62a4648172743eb9ecbcd0e846913abc9ac6dac1f615b0e7a9d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f8eee437173dc3411bd5378553995c633a266d4ebdbe1539cd9eb26dc10ee148c13c85190c90516ebd8d9304810804f93923c13535db87224c5e81e6a1ee6adc
|
|
7
|
+
data.tar.gz: be2a6e3cd8771180dcd430bd931326af2c8a261f9333c340be766cfc2ab85bce7475a18e97ceb596a57df2a59fd4471123c11314a9855009bf6fd4cb3d645b56
|
data/.gitlab-ci.yml
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
image: ruby:4.0
|
|
3
|
+
|
|
2
4
|
rspec:
|
|
3
5
|
script:
|
|
4
6
|
- bundle install
|
|
@@ -8,4 +10,10 @@ rubocop:
|
|
|
8
10
|
script:
|
|
9
11
|
- bundle install
|
|
10
12
|
- bundle exec rubocop
|
|
13
|
+
|
|
14
|
+
integration:
|
|
15
|
+
script:
|
|
16
|
+
- bundle install
|
|
17
|
+
- bundle exec bouch example > /tmp/my_budget.yml
|
|
18
|
+
- bundle exec bouch /tmp/my_budget.yml
|
|
11
19
|
...
|
data/.rubocop.yml
CHANGED
|
@@ -3,16 +3,24 @@ AllCops:
|
|
|
3
3
|
- 'vendor/**/*'
|
|
4
4
|
- 'spec/fixtures/**/*'
|
|
5
5
|
- 'tmp/**/*'
|
|
6
|
-
|
|
6
|
+
NewCops: disable
|
|
7
|
+
TargetRubyVersion: 4.0
|
|
8
|
+
SuggestExtensions: false
|
|
9
|
+
|
|
10
|
+
#################### Gemspec #########################
|
|
11
|
+
|
|
12
|
+
Gemspec/RequiredRubyVersion:
|
|
13
|
+
Enabled: false
|
|
7
14
|
|
|
8
15
|
#################### Layout #############################
|
|
9
16
|
Layout/IndentationWidth:
|
|
10
17
|
Width: 2
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
Layout/LineLength:
|
|
20
|
+
Max: 140
|
|
21
|
+
AllowURI: true
|
|
22
|
+
URISchemes:
|
|
23
|
+
- https
|
|
16
24
|
|
|
17
25
|
#################### Metrics ############################
|
|
18
26
|
|
|
@@ -31,12 +39,6 @@ Metrics/ClassLength:
|
|
|
31
39
|
Metrics/CyclomaticComplexity:
|
|
32
40
|
Enabled: false
|
|
33
41
|
|
|
34
|
-
Metrics/LineLength:
|
|
35
|
-
Max: 120
|
|
36
|
-
AllowURI: true
|
|
37
|
-
URISchemes:
|
|
38
|
-
- https
|
|
39
|
-
|
|
40
42
|
Metrics/MethodLength:
|
|
41
43
|
Enabled: false
|
|
42
44
|
|
|
@@ -53,9 +55,6 @@ Naming/FileName:
|
|
|
53
55
|
|
|
54
56
|
#################### Style ###########################
|
|
55
57
|
|
|
56
|
-
Style/BracesAroundHashParameters:
|
|
57
|
-
Enabled: false
|
|
58
|
-
|
|
59
58
|
Style/CommentAnnotation:
|
|
60
59
|
Enabled: false
|
|
61
60
|
|
data/.simplecov
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,48 +1,65 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
bouch (
|
|
4
|
+
bouch (2.0.0)
|
|
5
|
+
paint (~> 2.3)
|
|
5
6
|
|
|
6
7
|
GEM
|
|
7
8
|
remote: https://rubygems.org/
|
|
8
9
|
specs:
|
|
9
|
-
ast (2.4.
|
|
10
|
-
diff-lcs (1.
|
|
11
|
-
docile (1.
|
|
12
|
-
json (2.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
rspec
|
|
10
|
+
ast (2.4.3)
|
|
11
|
+
diff-lcs (1.6.2)
|
|
12
|
+
docile (1.4.1)
|
|
13
|
+
json (2.18.1)
|
|
14
|
+
language_server-protocol (3.17.0.5)
|
|
15
|
+
lint_roller (1.1.0)
|
|
16
|
+
paint (2.3.0)
|
|
17
|
+
parallel (1.27.0)
|
|
18
|
+
parser (3.3.10.2)
|
|
19
|
+
ast (~> 2.4.1)
|
|
20
|
+
racc
|
|
21
|
+
prism (1.9.0)
|
|
22
|
+
racc (1.8.1)
|
|
23
|
+
rainbow (3.1.1)
|
|
24
|
+
rake (13.3.1)
|
|
25
|
+
regexp_parser (2.11.3)
|
|
26
|
+
rspec (3.13.2)
|
|
27
|
+
rspec-core (~> 3.13.0)
|
|
28
|
+
rspec-expectations (~> 3.13.0)
|
|
29
|
+
rspec-mocks (~> 3.13.0)
|
|
30
|
+
rspec-core (3.13.6)
|
|
31
|
+
rspec-support (~> 3.13.0)
|
|
32
|
+
rspec-expectations (3.13.5)
|
|
26
33
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
27
|
-
rspec-support (~> 3.
|
|
28
|
-
rspec-mocks (3.
|
|
34
|
+
rspec-support (~> 3.13.0)
|
|
35
|
+
rspec-mocks (3.13.7)
|
|
29
36
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
30
|
-
rspec-support (~> 3.
|
|
31
|
-
rspec-support (3.
|
|
32
|
-
rubocop (
|
|
37
|
+
rspec-support (~> 3.13.0)
|
|
38
|
+
rspec-support (3.13.7)
|
|
39
|
+
rubocop (1.84.2)
|
|
40
|
+
json (~> 2.3)
|
|
41
|
+
language_server-protocol (~> 3.17.0.2)
|
|
42
|
+
lint_roller (~> 1.1.0)
|
|
33
43
|
parallel (~> 1.10)
|
|
34
|
-
parser (>= 2
|
|
35
|
-
powerpack (~> 0.1)
|
|
44
|
+
parser (>= 3.3.0.2)
|
|
36
45
|
rainbow (>= 2.2.2, < 4.0)
|
|
46
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
47
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
37
48
|
ruby-progressbar (~> 1.7)
|
|
38
|
-
unicode-display_width (
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
50
|
+
rubocop-ast (1.49.0)
|
|
51
|
+
parser (>= 3.3.7.2)
|
|
52
|
+
prism (~> 1.7)
|
|
53
|
+
ruby-progressbar (1.13.0)
|
|
54
|
+
simplecov (0.22.0)
|
|
41
55
|
docile (~> 1.1)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
simplecov-html (0.
|
|
45
|
-
|
|
56
|
+
simplecov-html (~> 0.11)
|
|
57
|
+
simplecov_json_formatter (~> 0.1)
|
|
58
|
+
simplecov-html (0.13.2)
|
|
59
|
+
simplecov_json_formatter (0.1.4)
|
|
60
|
+
unicode-display_width (3.2.0)
|
|
61
|
+
unicode-emoji (~> 4.1)
|
|
62
|
+
unicode-emoji (4.2.0)
|
|
46
63
|
|
|
47
64
|
PLATFORMS
|
|
48
65
|
ruby
|
|
@@ -52,11 +69,11 @@ DEPENDENCIES
|
|
|
52
69
|
bundler
|
|
53
70
|
rake
|
|
54
71
|
rspec
|
|
55
|
-
rubocop (
|
|
72
|
+
rubocop (~> 1.72)
|
|
56
73
|
simplecov
|
|
57
74
|
|
|
58
75
|
RUBY VERSION
|
|
59
|
-
|
|
76
|
+
ruby 4.0.1
|
|
60
77
|
|
|
61
78
|
BUNDLED WITH
|
|
62
|
-
|
|
79
|
+
4.0.6
|
data/README.md
CHANGED
|
@@ -23,35 +23,67 @@ gem 'bouch'
|
|
|
23
23
|
|
|
24
24
|
Bouch takes a simple YAML file as its primary data input. This will be referred to as a budget pouch file.
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Generate an example budget pouch file and run it:
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
```
|
|
29
|
+
bouch example > my_budget.yml
|
|
30
|
+
bouch my_budget.yml
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Generate an Example Pouch File
|
|
34
|
+
|
|
35
|
+
You can generate an example budget pouch YAML file to get started:
|
|
29
36
|
|
|
30
37
|
```
|
|
31
|
-
bouch
|
|
38
|
+
bouch example > my_budget.yml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Edit `my_budget.yml` with your own data, then run:
|
|
42
|
+
|
|
32
43
|
```
|
|
44
|
+
bouch my_budget.yml
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### CLI Flags
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
bouch [YAML_FILE] # Calculate and display budget
|
|
51
|
+
bouch example # Print an example budget pouch YAML
|
|
52
|
+
bouch --version / -v # Print version
|
|
53
|
+
bouch --help / -h # Print usage help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Example Output
|
|
33
57
|
|
|
34
|
-
You should see the example budget summary output:
|
|
58
|
+
You should see the example budget summary output (with colorized sections):
|
|
35
59
|
|
|
36
60
|
```
|
|
37
|
-
|
|
61
|
+
──────────────────────────────────────────
|
|
62
|
+
BUDGET
|
|
63
|
+
──────────────────────────────────────────
|
|
38
64
|
Quarter 1: 3025.00
|
|
39
65
|
Quarter 2: 3025.00
|
|
40
66
|
Quarter 3: 3025.00
|
|
41
67
|
Quarter 4: 3025.00
|
|
42
|
-
----------------------
|
|
43
68
|
Budget Annual Total: 12100.00
|
|
69
|
+
──────────────────────────────────────────
|
|
70
|
+
INCOME
|
|
71
|
+
──────────────────────────────────────────
|
|
44
72
|
Budget Annual Income: 28808.00
|
|
45
73
|
Budget Income Percent: 42.00%
|
|
46
|
-
|
|
74
|
+
──────────────────────────────────────────
|
|
75
|
+
ASSETS
|
|
76
|
+
──────────────────────────────────────────
|
|
47
77
|
Assets Total: 500.00
|
|
48
78
|
Equity Total: 500.00
|
|
49
79
|
Net Worth: 1000.00
|
|
50
|
-
|
|
80
|
+
──────────────────────────────────────────
|
|
81
|
+
DEBTS
|
|
82
|
+
──────────────────────────────────────────
|
|
51
83
|
Debt Total: 420.00
|
|
52
84
|
Debt Ratio: 0.4200
|
|
53
85
|
Debt Ratio Percent: 42.00%
|
|
54
|
-
|
|
86
|
+
──────────────────────────────────────────
|
|
55
87
|
```
|
|
56
88
|
|
|
57
89
|
### Pouch Schema
|
|
@@ -65,9 +97,9 @@ Budget pouch files are written in Ruby friendly YAML and currently use the follo
|
|
|
65
97
|
* Primary hash keys:
|
|
66
98
|
* **Budget**
|
|
67
99
|
* **Salary**
|
|
68
|
-
* **Assets**
|
|
69
|
-
* **Equity**
|
|
70
|
-
* **Debts**
|
|
100
|
+
* **Assets** (optional)
|
|
101
|
+
* **Equity** (optional)
|
|
102
|
+
* **Debts** (optional)
|
|
71
103
|
* **Budget** nested keys and values:
|
|
72
104
|
* **Q1**
|
|
73
105
|
* foo
|
data/Rakefile
CHANGED
data/bouch.gemspec
CHANGED
|
@@ -5,7 +5,6 @@ require 'bouch/version'
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = 'bouch'
|
|
8
|
-
s.date = '2018-06-09'
|
|
9
8
|
s.version = Bouch::VERSION
|
|
10
9
|
s.authors = ['Shane R. Sofos']
|
|
11
10
|
s.email = ['ssofos@gmail.com']
|
|
@@ -13,21 +12,22 @@ Gem::Specification.new do |s|
|
|
|
13
12
|
s.license = 'GPL-3.0'
|
|
14
13
|
s.description = 'The Budget Pouch. Fast annual budget projections.'
|
|
15
14
|
s.summary =
|
|
16
|
-
'A simple tool to calculate and project your '
|
|
17
|
-
'annual personal budget based on fiscal quarters '
|
|
15
|
+
'A simple tool to calculate and project your ' \
|
|
16
|
+
'annual personal budget based on fiscal quarters ' \
|
|
18
17
|
'expenditures, income, assets, and debts.'
|
|
19
18
|
|
|
20
|
-
s.files = %x(git ls-files).split(
|
|
21
|
-
s.bindir =
|
|
19
|
+
s.files = %x(git ls-files).split("\n")
|
|
20
|
+
s.bindir = 'bin'
|
|
22
21
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
23
|
-
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
|
24
22
|
s.require_paths = ['lib']
|
|
25
23
|
|
|
24
|
+
s.add_dependency 'paint', '~> 2.3'
|
|
25
|
+
|
|
26
26
|
s.add_development_dependency 'bundler'
|
|
27
27
|
s.add_development_dependency 'rake'
|
|
28
28
|
s.add_development_dependency 'rspec'
|
|
29
|
-
s.add_development_dependency 'rubocop', '
|
|
29
|
+
s.add_development_dependency 'rubocop', '~> 1.72'
|
|
30
30
|
s.add_development_dependency 'simplecov'
|
|
31
31
|
|
|
32
|
-
s.required_ruby_version = '>= 2
|
|
32
|
+
s.required_ruby_version = '>= 3.2'
|
|
33
33
|
end
|
data/lib/bouch/calc.rb
CHANGED
|
@@ -4,31 +4,35 @@
|
|
|
4
4
|
module BouchCalculate
|
|
5
5
|
# Calculate asset value aggregate amount
|
|
6
6
|
def calc_assets(assets, type = 'assets')
|
|
7
|
+
return if assets.nil?
|
|
8
|
+
|
|
7
9
|
assets.each_value do |value|
|
|
8
10
|
case type
|
|
9
11
|
when 'assets'
|
|
10
|
-
@assets
|
|
12
|
+
@assets << value
|
|
11
13
|
when 'equity'
|
|
12
|
-
@equity
|
|
14
|
+
@equity << value
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
# Calculate the percentage of budget of a salary/income
|
|
18
20
|
def calc_budget_percentage(total, salary)
|
|
19
|
-
((total.to_f / salary
|
|
21
|
+
((total.to_f / salary) * 100).round(2)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# Calculate debt/liability aggregate amount
|
|
23
25
|
def calc_debts(debts)
|
|
26
|
+
return if debts.nil?
|
|
27
|
+
|
|
24
28
|
debts.each_value do |value|
|
|
25
|
-
@debts
|
|
29
|
+
@debts << value
|
|
26
30
|
end
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
# Calculate a debt ratio: total debts divided by total assets
|
|
30
34
|
def calc_debt_ratio(debts, assets)
|
|
31
|
-
(debts.to_f / assets
|
|
35
|
+
(debts.to_f / assets).round(4)
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
# Calculate a debt ratio percentage
|
|
@@ -36,7 +40,7 @@ module BouchCalculate
|
|
|
36
40
|
(debt_ratio.to_f * 100).round(2)
|
|
37
41
|
end
|
|
38
42
|
|
|
39
|
-
#
|
|
43
|
+
# Calculate a Net Worth sum
|
|
40
44
|
def calc_net_worth(assets = [], equity = [])
|
|
41
45
|
@net_worth = (assets + equity).sum.to_f.round(2)
|
|
42
46
|
end
|
|
@@ -48,21 +52,22 @@ module BouchCalculate
|
|
|
48
52
|
|
|
49
53
|
# Calculate an annual income based on a weekly frequency salary
|
|
50
54
|
def calc_salary(amount, freq)
|
|
51
|
-
(amount.to_f * (52 / freq)).round(2)
|
|
55
|
+
(amount.to_f * (52.0 / freq)).round(2)
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# Calculate each financial quarters budget items, including repeating ones
|
|
55
59
|
def calc_quarters_raw(budget)
|
|
56
60
|
budget.each_value do |items|
|
|
57
|
-
@quarters
|
|
61
|
+
idx = @quarters.length
|
|
62
|
+
@quarters[idx] = []
|
|
58
63
|
items.each_value do |value|
|
|
59
64
|
case value
|
|
60
65
|
when Hash
|
|
61
66
|
if value.key?('repeat')
|
|
62
|
-
@quarters[
|
|
67
|
+
@quarters[idx] << calc_repeating(value['cost'])
|
|
63
68
|
end
|
|
64
69
|
else
|
|
65
|
-
@quarters[
|
|
70
|
+
@quarters[idx] << value
|
|
66
71
|
end
|
|
67
72
|
end
|
|
68
73
|
end
|
|
@@ -70,6 +75,6 @@ module BouchCalculate
|
|
|
70
75
|
|
|
71
76
|
# Calculate all financial quarter budget into an aggregate annual budget
|
|
72
77
|
def calc_quarters_raw_total
|
|
73
|
-
@quarters[
|
|
78
|
+
@quarters[0].sum + @quarters[1].sum + @quarters[2].sum + @quarters[3].sum
|
|
74
79
|
end
|
|
75
80
|
end
|
data/lib/bouch/cli.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'bouch'
|
|
4
4
|
require 'bouch/version'
|
|
5
|
+
require 'bouch/example'
|
|
6
|
+
require 'paint'
|
|
5
7
|
|
|
6
8
|
class Bouch
|
|
7
9
|
# Parse the command line
|
|
@@ -13,20 +15,26 @@ class Bouch
|
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def start
|
|
16
|
-
if @yaml_file.
|
|
17
|
-
puts 'Please supply budget pouch YAML file path and rerun bouch.'
|
|
18
|
+
if @yaml_file.nil? || %w[--help -h].include?(@yaml_file)
|
|
18
19
|
usage
|
|
20
|
+
elsif %w[--version -v].include?(@yaml_file)
|
|
21
|
+
puts Paint["bouch #{Bouch::VERSION}", :magenta, :bold]
|
|
22
|
+
elsif @yaml_file == 'example'
|
|
23
|
+
puts Bouch::EXAMPLE_POUCH
|
|
19
24
|
elsif File.exist?(@yaml_file)
|
|
20
25
|
budget = Bouch.new(@yaml_file)
|
|
21
26
|
budget.show_budget
|
|
22
27
|
else
|
|
23
|
-
puts "Whoops. The budget pouch file specified: #{@yaml_file} ; does not exist!"
|
|
28
|
+
puts Paint["Whoops. The budget pouch file specified: #{@yaml_file} ; does not exist!", :red]
|
|
24
29
|
usage
|
|
25
30
|
end
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def usage
|
|
29
|
-
puts "<<bouch #{Bouch::VERSION}
|
|
34
|
+
puts Paint["<<bouch #{Bouch::VERSION}>>", :magenta, :bold]
|
|
35
|
+
puts "Usage: #{Paint[File.basename($PROGRAM_NAME), :green]} #{Paint['[YAML_FILE]', :faint]}"
|
|
36
|
+
puts " #{Paint[File.basename($PROGRAM_NAME), :green]} #{Paint['example', :magenta]} # Print an example budget pouch YAML"
|
|
37
|
+
puts " #{Paint[File.basename($PROGRAM_NAME), :green]} #{Paint['--version', :magenta]} # Print version"
|
|
30
38
|
end
|
|
31
39
|
end
|
|
32
40
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Bouch
|
|
4
|
+
EXAMPLE_POUCH = <<~YAML
|
|
5
|
+
---
|
|
6
|
+
Budget:
|
|
7
|
+
Q1:
|
|
8
|
+
Rent:
|
|
9
|
+
cost: 1000
|
|
10
|
+
repeat: true
|
|
11
|
+
foo: 20
|
|
12
|
+
bar: 5
|
|
13
|
+
Q2:
|
|
14
|
+
Rent:
|
|
15
|
+
cost: 1000
|
|
16
|
+
repeat: true
|
|
17
|
+
fizz: 20
|
|
18
|
+
buzz: 5
|
|
19
|
+
Q3:
|
|
20
|
+
Rent:
|
|
21
|
+
cost: 1000
|
|
22
|
+
repeat: true
|
|
23
|
+
bubble: 20
|
|
24
|
+
sort: 5
|
|
25
|
+
Q4:
|
|
26
|
+
Rent:
|
|
27
|
+
cost: 1000
|
|
28
|
+
repeat: true
|
|
29
|
+
baz: 20
|
|
30
|
+
qax: 5
|
|
31
|
+
Salary:
|
|
32
|
+
quantity: 1108.00
|
|
33
|
+
frequency: 2
|
|
34
|
+
Assets:
|
|
35
|
+
foo: 500
|
|
36
|
+
Equity:
|
|
37
|
+
bar: 500
|
|
38
|
+
Debts:
|
|
39
|
+
baz: 120
|
|
40
|
+
qax: 300
|
|
41
|
+
...
|
|
42
|
+
YAML
|
|
43
|
+
end
|
data/lib/bouch/version.rb
CHANGED
data/lib/bouch.rb
CHANGED
|
@@ -1,35 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'yaml'
|
|
4
|
+
require 'paint'
|
|
4
5
|
require 'bouch/calc'
|
|
5
6
|
|
|
6
7
|
# Calculate and create simple financial budgets
|
|
7
8
|
# by parsing a single YAML file as input
|
|
8
9
|
class Bouch
|
|
9
10
|
attr_accessor :assets, :debts, :equity, :net_worth, :pouch, :quarters
|
|
11
|
+
|
|
10
12
|
include BouchCalculate
|
|
11
13
|
|
|
14
|
+
SEPARATOR = Paint["\u2500" * 42, :faint]
|
|
15
|
+
|
|
12
16
|
def initialize(file)
|
|
13
|
-
@assets =
|
|
14
|
-
@debts =
|
|
15
|
-
@equity =
|
|
17
|
+
@assets = []
|
|
18
|
+
@debts = []
|
|
19
|
+
@equity = []
|
|
16
20
|
@net_worth = nil
|
|
17
|
-
@pouch = YAML.safe_load(
|
|
18
|
-
@quarters =
|
|
21
|
+
@pouch = YAML.safe_load(File.read(file))
|
|
22
|
+
@quarters = {}
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
# Summarize and show aggregate asset totals
|
|
22
26
|
def show_assets_total
|
|
23
27
|
calc_assets(@pouch['Assets'], 'assets') if @assets.empty?
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
label = Paint[format('%-30s', 'Assets Total:'), :green]
|
|
29
|
+
value = Paint[format('%.2f', @assets.sum), :green, :bright]
|
|
30
|
+
puts "#{label} #{value}"
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
# Summarize and show aggregate liabilities totals
|
|
29
34
|
def show_debts_total
|
|
30
35
|
calc_debts(@pouch['Debts']) if @debts.empty?
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
label = Paint[format('%-30s', 'Debt Total:'), :red]
|
|
37
|
+
value = Paint[format('%.2f', @debts.sum), :red, :bright]
|
|
38
|
+
puts "#{label} #{value}"
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
# Summarize and show debt ratio
|
|
@@ -38,70 +44,97 @@ class Bouch
|
|
|
38
44
|
calc_assets(@pouch['Equity'], 'equity') if @equity.empty?
|
|
39
45
|
calc_net_worth(@assets, @equity) if @net_worth.nil?
|
|
40
46
|
calc_debts(@pouch['Debts']) if @debts.empty?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
ratio = calc_debt_ratio(@debts.sum, @net_worth)
|
|
48
|
+
label1 = Paint[format('%-30s', 'Debt Ratio:'), :red]
|
|
49
|
+
value1 = Paint[format('%.4f', ratio), :red, :bright]
|
|
50
|
+
puts "#{label1} #{value1}"
|
|
51
|
+
label2 = Paint[format('%-30s', 'Debt Ratio Percent:'), :red]
|
|
52
|
+
value2 = Paint[format('%.2f%s', calc_debt_ratio_percent(ratio), '%'), :red, :bright]
|
|
53
|
+
puts "#{label2} #{value2}"
|
|
46
54
|
end
|
|
47
55
|
|
|
48
56
|
# Summarize and show aggregate equity totals
|
|
49
57
|
def show_equity_total
|
|
50
58
|
calc_assets(@pouch['Equity'], 'equity') if @equity.empty?
|
|
51
|
-
|
|
59
|
+
label = Paint[format('%-30s', 'Equity Total:'), :green]
|
|
60
|
+
value = Paint[format('%.2f', @equity.sum), :green, :bright]
|
|
61
|
+
puts "#{label} #{value}"
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
# Summarize and show Net Worth
|
|
55
65
|
def show_net_worth
|
|
56
66
|
calc_net_worth(@assets, @equity) if @net_worth.nil?
|
|
57
|
-
|
|
67
|
+
label = Paint[format('%-30s', 'Net Worth:'), :green]
|
|
68
|
+
value = Paint[format('%.2f', @net_worth), :green, :bright]
|
|
69
|
+
puts "#{label} #{value}"
|
|
58
70
|
end
|
|
59
71
|
|
|
60
72
|
# Summarize and show all financial quarter budgets
|
|
61
73
|
def show_quarters
|
|
62
74
|
calc_quarters_raw(@pouch['Budget']) if @quarters.empty?
|
|
63
|
-
puts
|
|
75
|
+
puts SEPARATOR
|
|
76
|
+
puts Paint['BUDGET', :magenta, :bold]
|
|
77
|
+
puts SEPARATOR
|
|
64
78
|
4.times do |n|
|
|
65
|
-
|
|
79
|
+
label = Paint[format('%-30s', "Quarter #{n + 1}:"), :magenta]
|
|
80
|
+
value = Paint[format('%.2f', @quarters[n].sum), :magenta, :bright]
|
|
81
|
+
puts "#{label} #{value}"
|
|
66
82
|
end
|
|
67
|
-
puts '----------------------'
|
|
68
83
|
end
|
|
69
84
|
|
|
70
85
|
# Summarize and show the aggregate annual budget totals
|
|
71
86
|
def show_annual_total
|
|
72
87
|
calc_quarters_raw(@pouch['Budget']) if @quarters.empty?
|
|
73
|
-
|
|
88
|
+
label = Paint[format('%-30s', 'Budget Annual Total:'), :magenta]
|
|
89
|
+
value = Paint[format('%.2f', calc_quarters_raw_total), :magenta, :bright]
|
|
90
|
+
puts "#{label} #{value}"
|
|
74
91
|
end
|
|
75
92
|
|
|
76
93
|
# Summarize and show the aggregate annual budget as a percentage of income
|
|
77
94
|
def show_budget_percentage
|
|
78
95
|
calc_quarters_raw(@pouch['Budget']) if @quarters.empty?
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
label = Paint[format('%-30s', 'Budget Income Percent:'), :magenta]
|
|
97
|
+
value = Paint[format('%.2f%s',
|
|
98
|
+
calc_budget_percentage(
|
|
99
|
+
calc_quarters_raw_total,
|
|
100
|
+
calc_salary(@pouch['Salary']['quantity'], @pouch['Salary']['frequency'])
|
|
101
|
+
),
|
|
102
|
+
'%'), :magenta, :bright]
|
|
103
|
+
puts "#{label} #{value}"
|
|
86
104
|
end
|
|
87
105
|
|
|
88
106
|
# Summarize and show annual income
|
|
89
107
|
def show_annual_income
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
label = Paint[format('%-30s', 'Budget Annual Income:'), :magenta]
|
|
109
|
+
value = Paint[format('%.2f',
|
|
110
|
+
calc_salary(@pouch['Salary']['quantity'], @pouch['Salary']['frequency'])), :magenta, :bright]
|
|
111
|
+
puts "#{label} #{value}"
|
|
93
112
|
end
|
|
94
113
|
|
|
95
114
|
# Summarize and show all aggregate components of the quarterly, annual budgets, assets
|
|
96
115
|
def show_budget
|
|
97
116
|
show_quarters
|
|
98
117
|
show_annual_total
|
|
118
|
+
puts SEPARATOR
|
|
119
|
+
puts Paint['INCOME', :magenta, :bold]
|
|
120
|
+
puts SEPARATOR
|
|
99
121
|
show_annual_income
|
|
100
122
|
show_budget_percentage
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
if @pouch['Assets'] || @pouch['Equity']
|
|
124
|
+
puts SEPARATOR
|
|
125
|
+
puts Paint['ASSETS', :green, :bold]
|
|
126
|
+
puts SEPARATOR
|
|
127
|
+
show_assets_total if @pouch['Assets']
|
|
128
|
+
show_equity_total if @pouch['Equity']
|
|
129
|
+
show_net_worth
|
|
130
|
+
end
|
|
131
|
+
if @pouch['Debts']
|
|
132
|
+
puts SEPARATOR
|
|
133
|
+
puts Paint['DEBTS', :red, :bold]
|
|
134
|
+
puts SEPARATOR
|
|
135
|
+
show_debts_total
|
|
136
|
+
show_debt_ratio if @net_worth
|
|
137
|
+
end
|
|
138
|
+
puts SEPARATOR
|
|
106
139
|
end
|
|
107
140
|
end
|
data/spec/bouch_calc_spec.rb
CHANGED
|
@@ -6,8 +6,12 @@ require 'bouch/calc'
|
|
|
6
6
|
|
|
7
7
|
describe BouchCalculate do
|
|
8
8
|
before :all do
|
|
9
|
-
@
|
|
10
|
-
@bouch = Bouch.new(@
|
|
9
|
+
@tempfile = create_example_pouch_tempfile
|
|
10
|
+
@bouch = Bouch.new(@tempfile.path)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after :all do
|
|
14
|
+
@tempfile.unlink
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
describe '.calc_assets' do
|
|
@@ -15,8 +19,6 @@ describe BouchCalculate do
|
|
|
15
19
|
expect(@bouch.calc_assets(@bouch.pouch['Assets'])).to be_a_kind_of(Hash)
|
|
16
20
|
end
|
|
17
21
|
it 'creates array of assets greater than zero' do
|
|
18
|
-
# Uncomment line below for Debug
|
|
19
|
-
# puts @bouch.assets.inspect
|
|
20
22
|
expect(@bouch.assets.length).to be > 0
|
|
21
23
|
end
|
|
22
24
|
end
|
|
@@ -34,8 +36,6 @@ describe BouchCalculate do
|
|
|
34
36
|
expect(@bouch.calc_debts(@bouch.pouch['Debts'])).to be_a_kind_of(Hash)
|
|
35
37
|
end
|
|
36
38
|
it 'creates an array of debts greater than zero' do
|
|
37
|
-
# Uncomment line below for Debug
|
|
38
|
-
# puts @bouch.debts.inspect
|
|
39
39
|
expect(@bouch.debts.length).to be > 0
|
|
40
40
|
end
|
|
41
41
|
end
|
|
@@ -55,14 +55,10 @@ describe BouchCalculate do
|
|
|
55
55
|
context 'given a debt ratio' do
|
|
56
56
|
it 'returns a Float number' do
|
|
57
57
|
debt_ratio = @bouch.calc_debt_ratio(420.00, 1000.00)
|
|
58
|
-
# Uncomment line below for Debug
|
|
59
|
-
# puts debt_ratio
|
|
60
58
|
expect(@bouch.calc_debt_ratio_percent(debt_ratio)).to be_a_kind_of(Float)
|
|
61
59
|
end
|
|
62
60
|
it 'returns a debt ratio percentage' do
|
|
63
61
|
debt_ratio = @bouch.calc_debt_ratio(420.00, 1000.00)
|
|
64
|
-
# Uncomment line below for Debug
|
|
65
|
-
# puts debt_ratio
|
|
66
62
|
expect(@bouch.calc_debt_ratio_percent(debt_ratio)).to eq(42.00)
|
|
67
63
|
end
|
|
68
64
|
end
|
|
@@ -107,24 +103,16 @@ describe BouchCalculate do
|
|
|
107
103
|
expect(@bouch.calc_quarters_raw(@bouch.pouch['Budget'])).to be_a_kind_of(Hash)
|
|
108
104
|
end
|
|
109
105
|
it 'creates an array of financial quarter one budget items greater than zero' do
|
|
110
|
-
|
|
111
|
-
# puts @bouch.quarters['0'].inspect
|
|
112
|
-
expect(@bouch.quarters['0'].length).to be > 0
|
|
106
|
+
expect(@bouch.quarters[0].length).to be > 0
|
|
113
107
|
end
|
|
114
108
|
it 'creates an array of financial quarter two budget items greater than zero' do
|
|
115
|
-
|
|
116
|
-
# puts @bouch.quarters['1'].inspect
|
|
117
|
-
expect(@bouch.quarters['1'].length).to be > 0
|
|
109
|
+
expect(@bouch.quarters[1].length).to be > 0
|
|
118
110
|
end
|
|
119
111
|
it 'creates an array of financial quarter three budget items greater than zero' do
|
|
120
|
-
|
|
121
|
-
# puts @bouch.quarters['2'].inspect
|
|
122
|
-
expect(@bouch.quarters['2'].length).to be > 0
|
|
112
|
+
expect(@bouch.quarters[2].length).to be > 0
|
|
123
113
|
end
|
|
124
114
|
it 'creates an array of financial quarter four budget items greater than zero' do
|
|
125
|
-
|
|
126
|
-
# puts @bouch.quarters['3'].inspect
|
|
127
|
-
expect(@bouch.quarters['3'].length).to be > 0
|
|
115
|
+
expect(@bouch.quarters[3].length).to be > 0
|
|
128
116
|
end
|
|
129
117
|
end
|
|
130
118
|
end
|
data/spec/bouch_cli_spec.rb
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'stringio'
|
|
4
|
+
require 'yaml'
|
|
3
5
|
require 'bouch/cli'
|
|
4
6
|
|
|
5
7
|
describe 'Bouch::CLI' do
|
|
6
8
|
before :all do
|
|
7
|
-
@
|
|
9
|
+
@tempfile = create_example_pouch_tempfile
|
|
10
|
+
@cli = Bouch::CLI.new(@tempfile.path)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after :all do
|
|
14
|
+
@tempfile.unlink
|
|
8
15
|
end
|
|
9
16
|
|
|
10
17
|
it 'is a Bouch::CLI object' do
|
|
@@ -25,15 +32,56 @@ describe 'Bouch::CLI' do
|
|
|
25
32
|
end
|
|
26
33
|
end
|
|
27
34
|
|
|
35
|
+
context 'when --help flag is supplied' do
|
|
36
|
+
it 'outputs usage help message' do
|
|
37
|
+
@cli.yaml_file = '--help'
|
|
38
|
+
expect { @cli.start }.to output(/Usage:/).to_stdout
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'when -h flag is supplied' do
|
|
43
|
+
it 'outputs usage help message' do
|
|
44
|
+
@cli.yaml_file = '-h'
|
|
45
|
+
expect { @cli.start }.to output(/Usage:/).to_stdout
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'when --version flag is supplied' do
|
|
50
|
+
it 'outputs the version' do
|
|
51
|
+
@cli.yaml_file = '--version'
|
|
52
|
+
expect { @cli.start }.to output(/bouch #{Bouch::VERSION}/).to_stdout
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'when -v flag is supplied' do
|
|
57
|
+
it 'outputs the version' do
|
|
58
|
+
@cli.yaml_file = '-v'
|
|
59
|
+
expect { @cli.start }.to output(/bouch #{Bouch::VERSION}/).to_stdout
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context 'when example subcommand is supplied' do
|
|
64
|
+
it 'outputs valid YAML with expected top-level keys' do
|
|
65
|
+
@cli.yaml_file = 'example'
|
|
66
|
+
output = capture_stdout { @cli.start }
|
|
67
|
+
parsed = YAML.safe_load(output)
|
|
68
|
+
expect(parsed).to have_key('Budget')
|
|
69
|
+
expect(parsed).to have_key('Salary')
|
|
70
|
+
expect(parsed).to have_key('Assets')
|
|
71
|
+
expect(parsed).to have_key('Equity')
|
|
72
|
+
expect(parsed).to have_key('Debts')
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
28
76
|
context 'when an existent file is supplied as the first CLI argument' do
|
|
29
77
|
it 'calculates a budget from a budget pouch file and outputs it' do
|
|
30
|
-
@cli.yaml_file =
|
|
78
|
+
@cli.yaml_file = @tempfile.path
|
|
31
79
|
expect { @cli.start }.to output.to_stdout
|
|
32
80
|
end
|
|
33
81
|
end
|
|
34
82
|
|
|
35
83
|
context 'when a non-existent file is supplied as the first CLI argument' do
|
|
36
|
-
it '
|
|
84
|
+
it 'outputs a warning and usage help messages' do
|
|
37
85
|
@cli.yaml_file = 'foobar.yml'
|
|
38
86
|
expect { @cli.start }.to output.to_stdout
|
|
39
87
|
end
|
|
@@ -44,5 +92,18 @@ describe 'Bouch::CLI' do
|
|
|
44
92
|
it 'outputs a bouch usage help message' do
|
|
45
93
|
expect { @cli.usage }.to output.to_stdout
|
|
46
94
|
end
|
|
95
|
+
|
|
96
|
+
it 'includes example subcommand in usage' do
|
|
97
|
+
expect { @cli.usage }.to output(/example/).to_stdout
|
|
98
|
+
end
|
|
47
99
|
end
|
|
48
100
|
end
|
|
101
|
+
|
|
102
|
+
def capture_stdout
|
|
103
|
+
original_stdout = $stdout
|
|
104
|
+
$stdout = StringIO.new
|
|
105
|
+
yield
|
|
106
|
+
$stdout.string
|
|
107
|
+
ensure
|
|
108
|
+
$stdout = original_stdout
|
|
109
|
+
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'yaml'
|
|
4
|
+
require 'bouch/example'
|
|
4
5
|
|
|
5
6
|
describe 'Pouch YAML Schema' do
|
|
6
7
|
before :all do
|
|
7
|
-
@
|
|
8
|
-
@pouch = YAML.safe_load(IO.read(@yaml))
|
|
8
|
+
@pouch = YAML.safe_load(Bouch::EXAMPLE_POUCH)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
it 'has four major Hash keys' do
|
data/spec/bouch_spec.rb
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'tempfile'
|
|
3
4
|
require 'bouch'
|
|
4
5
|
|
|
5
6
|
describe Bouch do
|
|
6
7
|
before :all do
|
|
7
|
-
@
|
|
8
|
-
@bouch = Bouch.new(@
|
|
8
|
+
@tempfile = create_example_pouch_tempfile
|
|
9
|
+
@bouch = Bouch.new(@tempfile.path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
after :all do
|
|
13
|
+
@tempfile.unlink
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
it 'is a Bouch object' do
|
|
@@ -38,7 +43,7 @@ describe Bouch do
|
|
|
38
43
|
|
|
39
44
|
describe '#pouch' do
|
|
40
45
|
it 'loads the budget pouch YAML file' do
|
|
41
|
-
expect(@bouch.pouch).to eq(YAML.safe_load(
|
|
46
|
+
expect(@bouch.pouch).to eq(YAML.safe_load(Bouch::EXAMPLE_POUCH))
|
|
42
47
|
end
|
|
43
48
|
end
|
|
44
49
|
|
|
@@ -49,7 +54,7 @@ describe Bouch do
|
|
|
49
54
|
end
|
|
50
55
|
|
|
51
56
|
describe '.show_assets_total' do
|
|
52
|
-
it 'outputs financial budget
|
|
57
|
+
it 'outputs financial budget assets sum' do
|
|
53
58
|
expect { @bouch.show_assets_total }.to output.to_stdout
|
|
54
59
|
end
|
|
55
60
|
end
|
|
@@ -107,4 +112,37 @@ describe Bouch do
|
|
|
107
112
|
expect { @bouch.show_budget }.to output.to_stdout
|
|
108
113
|
end
|
|
109
114
|
end
|
|
115
|
+
|
|
116
|
+
describe 'missing YAML sections' do
|
|
117
|
+
before :all do
|
|
118
|
+
minimal = <<~YAML
|
|
119
|
+
---
|
|
120
|
+
Budget:
|
|
121
|
+
Q1:
|
|
122
|
+
foo: 100
|
|
123
|
+
Q2:
|
|
124
|
+
bar: 200
|
|
125
|
+
Q3:
|
|
126
|
+
baz: 300
|
|
127
|
+
Q4:
|
|
128
|
+
qax: 400
|
|
129
|
+
Salary:
|
|
130
|
+
quantity: 1000
|
|
131
|
+
frequency: 2
|
|
132
|
+
...
|
|
133
|
+
YAML
|
|
134
|
+
@minimal_yaml = Tempfile.new(['pouch', '.yml'])
|
|
135
|
+
@minimal_yaml.write(minimal)
|
|
136
|
+
@minimal_yaml.close
|
|
137
|
+
@minimal_bouch = Bouch.new(@minimal_yaml.path)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
after :all do
|
|
141
|
+
@minimal_yaml.unlink
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'does not crash when Assets, Equity, and Debts are missing' do
|
|
145
|
+
expect { @minimal_bouch.show_budget }.to output.to_stdout
|
|
146
|
+
end
|
|
147
|
+
end
|
|
110
148
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'simplecov'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'bouch/example'
|
|
4
6
|
|
|
5
7
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
|
6
8
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
|
@@ -79,3 +81,11 @@ RSpec.configure do |config|
|
|
|
79
81
|
# as the one that triggered the failure.
|
|
80
82
|
Kernel.srand config.seed
|
|
81
83
|
end
|
|
84
|
+
|
|
85
|
+
# Write the embedded example pouch to a tempfile for use across specs
|
|
86
|
+
def create_example_pouch_tempfile
|
|
87
|
+
tempfile = Tempfile.new(['pouch', '.yml'])
|
|
88
|
+
tempfile.write(Bouch::EXAMPLE_POUCH)
|
|
89
|
+
tempfile.close
|
|
90
|
+
tempfile
|
|
91
|
+
end
|
metadata
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bouch
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shane R. Sofos
|
|
8
|
-
|
|
9
|
-
bindir:
|
|
10
|
-
- bin
|
|
8
|
+
bindir: bin
|
|
11
9
|
cert_chain: []
|
|
12
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: paint
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.3'
|
|
14
26
|
- !ruby/object:Gem::Dependency
|
|
15
27
|
name: bundler
|
|
16
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -57,16 +69,16 @@ dependencies:
|
|
|
57
69
|
name: rubocop
|
|
58
70
|
requirement: !ruby/object:Gem::Requirement
|
|
59
71
|
requirements:
|
|
60
|
-
- - "
|
|
72
|
+
- - "~>"
|
|
61
73
|
- !ruby/object:Gem::Version
|
|
62
|
-
version:
|
|
74
|
+
version: '1.72'
|
|
63
75
|
type: :development
|
|
64
76
|
prerelease: false
|
|
65
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
78
|
requirements:
|
|
67
|
-
- - "
|
|
79
|
+
- - "~>"
|
|
68
80
|
- !ruby/object:Gem::Version
|
|
69
|
-
version:
|
|
81
|
+
version: '1.72'
|
|
70
82
|
- !ruby/object:Gem::Dependency
|
|
71
83
|
name: simplecov
|
|
72
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -104,8 +116,8 @@ files:
|
|
|
104
116
|
- lib/bouch.rb
|
|
105
117
|
- lib/bouch/calc.rb
|
|
106
118
|
- lib/bouch/cli.rb
|
|
119
|
+
- lib/bouch/example.rb
|
|
107
120
|
- lib/bouch/version.rb
|
|
108
|
-
- pouch.example.yml
|
|
109
121
|
- spec/bouch_calc_spec.rb
|
|
110
122
|
- spec/bouch_cli_spec.rb
|
|
111
123
|
- spec/bouch_pouch_yaml_spec.rb
|
|
@@ -116,7 +128,6 @@ homepage: https://gitlab.com/ssofos/bouch
|
|
|
116
128
|
licenses:
|
|
117
129
|
- GPL-3.0
|
|
118
130
|
metadata: {}
|
|
119
|
-
post_install_message:
|
|
120
131
|
rdoc_options: []
|
|
121
132
|
require_paths:
|
|
122
133
|
- lib
|
|
@@ -124,22 +135,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
124
135
|
requirements:
|
|
125
136
|
- - ">="
|
|
126
137
|
- !ruby/object:Gem::Version
|
|
127
|
-
version: 2
|
|
138
|
+
version: '3.2'
|
|
128
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
140
|
requirements:
|
|
130
141
|
- - ">="
|
|
131
142
|
- !ruby/object:Gem::Version
|
|
132
143
|
version: '0'
|
|
133
144
|
requirements: []
|
|
134
|
-
rubygems_version:
|
|
135
|
-
signing_key:
|
|
145
|
+
rubygems_version: 4.0.3
|
|
136
146
|
specification_version: 4
|
|
137
147
|
summary: A simple tool to calculate and project your annual personal budget based
|
|
138
148
|
on fiscal quarters expenditures, income, assets, and debts.
|
|
139
|
-
test_files:
|
|
140
|
-
- spec/bouch_calc_spec.rb
|
|
141
|
-
- spec/bouch_cli_spec.rb
|
|
142
|
-
- spec/bouch_pouch_yaml_spec.rb
|
|
143
|
-
- spec/bouch_spec.rb
|
|
144
|
-
- spec/bouch_version_spec.rb
|
|
145
|
-
- spec/spec_helper.rb
|
|
149
|
+
test_files: []
|
data/pouch.example.yml
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
Budget:
|
|
3
|
-
Q1:
|
|
4
|
-
Rent:
|
|
5
|
-
cost: 1000
|
|
6
|
-
repeat: true
|
|
7
|
-
foo: 20
|
|
8
|
-
bar: 5
|
|
9
|
-
Q2:
|
|
10
|
-
Rent:
|
|
11
|
-
cost: 1000
|
|
12
|
-
repeat: true
|
|
13
|
-
fizz: 20
|
|
14
|
-
buzz: 5
|
|
15
|
-
Q3:
|
|
16
|
-
Rent:
|
|
17
|
-
cost: 1000
|
|
18
|
-
repeat: true
|
|
19
|
-
bubble: 20
|
|
20
|
-
sort: 5
|
|
21
|
-
Q4:
|
|
22
|
-
Rent:
|
|
23
|
-
cost: 1000
|
|
24
|
-
repeat: true
|
|
25
|
-
baz: 20
|
|
26
|
-
qax: 5
|
|
27
|
-
Salary:
|
|
28
|
-
quantity: 1108.00
|
|
29
|
-
frequency: 2
|
|
30
|
-
Assets:
|
|
31
|
-
foo: 500
|
|
32
|
-
Equity:
|
|
33
|
-
bar: 500
|
|
34
|
-
Debts:
|
|
35
|
-
baz: 120
|
|
36
|
-
qax: 300
|
|
37
|
-
...
|