bankroll 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2fce9b108026fb88dc7010a720a419ba1c4511da3f54b4c6f227340c936b084c
4
- data.tar.gz: a565f6231e134aa9df16a44c9b99dc8fdd8154694bdf3b9be3a0e180c58e246e
3
+ metadata.gz: 3d60a1c7c561cbb9945f94a7913cb116dba1c56d050ae0f26d34543c811a1fbe
4
+ data.tar.gz: 80a97fd7345e676473515dff20c449053502a5457f653d615061ca5d27a8e508
5
5
  SHA512:
6
- metadata.gz: d9845beb9d4b8ce2fabc7a86f387e421a6c51c925304638ca0f0998291078f07a86dff5884ce7aef7a9353025b9d7fa63b2ce365c9ba085cabdd26b8ba33fec7
7
- data.tar.gz: dcf4c4f7fe1d59296669ffdc1dda48373fa228fd6909a85219823281dd671786c17d1f33e5337c8b5129a613b46f50d2d69cf4bde050edb814388841097f06b4
6
+ metadata.gz: e6fa504c7d3a0be597686abf78ac31ea7ac17d51c551d8b03737b242fd0d3eb79750d67efa430bd7d0cfa580dae50156ddd17381c410c66fdfaeb9b3d8e73275
7
+ data.tar.gz: 42793b333497660e72d893c46ab57b6ef4506c16994d34ddc17ad6d605df7b56e9160aee2826a57662e6ff2778e108202f4a39af6135e3b668f3bc06868f36de
data/.rubocop.yml CHANGED
@@ -5,6 +5,8 @@ require:
5
5
 
6
6
  # ==================== Main ==========================
7
7
  AllCops:
8
+ TargetRubyVersion: 3.1
9
+ NewCops: enable
8
10
  DisplayCopNames: true
9
11
  Exclude:
10
12
  - "bin/**/*"
@@ -68,6 +70,8 @@ Layout/LineEndStringConcatenationIndentation:
68
70
  IndentationWidth: 0
69
71
  Layout/LineLength:
70
72
  Max: 100
73
+ Exclude:
74
+ - "lib/bankroll/interest_rate.rb"
71
75
  Layout/MultilineArrayLineBreaks:
72
76
  Enabled: true
73
77
  Layout/MultilineAssignmentLayout:
@@ -118,7 +122,7 @@ Lint/ElseLayout:
118
122
  Lint/EmptyBlock:
119
123
  Enabled: true
120
124
  AllowComments: false
121
- AllowEmptyLambdas: false
125
+ AllowEmptyLambdas: true
122
126
  Lint/EmptyClass:
123
127
  Enabled: true
124
128
  Lint/EmptyConditionalBody:
@@ -199,6 +203,16 @@ Metrics/BlockLength:
199
203
  - "spec/**/*"
200
204
  Metrics/ParameterLists:
201
205
  Max: 3
206
+ Exclude:
207
+ - "lib/bankroll/interest_rate.rb"
208
+ Metrics/AbcSize:
209
+ Enabled: true
210
+ Exclude:
211
+ - "lib/bankroll/interest_rate.rb"
212
+ Metrics/MethodLength:
213
+ Enabled: true
214
+ Exclude:
215
+ - "lib/bankroll/interest_rate.rb"
202
216
  Naming/BlockForwarding:
203
217
  Enabled: true
204
218
  Naming/InclusiveLanguage:
@@ -223,8 +237,12 @@ Naming/VariableNumber:
223
237
  EnforcedStyle: snake_case
224
238
  AllowedIdentifiers:
225
239
  - capture3
240
+ Exclude:
241
+ - "lib/bankroll/interest_rate.rb"
226
242
  Naming/MethodParameterName:
227
243
  AllowNamesEndingInNumbers: false
244
+ Exclude:
245
+ - "lib/bankroll/interest_rate.rb"
228
246
  Security/IoMethods:
229
247
  Enabled: true
230
248
  Style/AccessorGrouping:
@@ -311,7 +329,7 @@ Style/MethodCallWithArgsParentheses:
311
329
  AllowParenthesesInMultilineCall: true
312
330
  IgnoreMacros: false
313
331
  Style/MethodDefParentheses:
314
- EnforcedStyle: false
332
+ EnforcedStyle: require_parentheses
315
333
  Style/MissingElse:
316
334
  Enabled: false
317
335
  Style/MultilineInPatternThen:
@@ -438,6 +456,10 @@ Performance/Sum:
438
456
  Enabled: true
439
457
 
440
458
  # ==================== RSpec ============================
459
+ RSpec/BeEq:
460
+ Enabled: true
461
+ RSpec/BeNil:
462
+ Enabled: true
441
463
  RSpec/ContextWording:
442
464
  Prefixes:
443
465
  - when
data/Gemfile CHANGED
@@ -7,8 +7,12 @@ gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
9
 
10
- gem "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 1.21"
13
-
14
- gem "byebug"
10
+ group :development, :test do
11
+ gem "byebug"
12
+ gem "rspec", "~> 3.0"
13
+ gem "rubocop", "~> 1.21"
14
+ gem "rubocop-performance"
15
+ gem "rubocop-rake"
16
+ gem "rubocop-rspec"
17
+ gem "solargraph"
18
+ end
data/Gemfile.lock CHANGED
@@ -1,15 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bankroll (0.1.0)
5
- dry-equalizer
6
- dry-initializer
7
- dry-types
4
+ bankroll (0.1.1)
5
+ dry-equalizer (~> 0.3.0)
6
+ dry-initializer (~> 3.1.1)
7
+ dry-types (~> 1.5.1)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
12
  ast (2.4.2)
13
+ backport (1.2.0)
14
+ benchmark (0.2.0)
13
15
  byebug (11.1.3)
14
16
  concurrent-ruby (1.1.9)
15
17
  diff-lcs (1.5.0)
@@ -33,12 +35,25 @@ GEM
33
35
  dry-core (~> 0.5, >= 0.5)
34
36
  dry-inflector (~> 0.1, >= 0.1.2)
35
37
  dry-logic (~> 1.0, >= 1.0.2)
38
+ e2mmap (0.1.0)
39
+ jaro_winkler (1.5.4)
40
+ kramdown (2.3.1)
41
+ rexml
42
+ kramdown-parser-gfm (1.1.0)
43
+ kramdown (~> 2.0)
44
+ nokogiri (1.13.3-x86_64-darwin)
45
+ racc (~> 1.4)
46
+ nokogiri (1.13.3-x86_64-linux)
47
+ racc (~> 1.4)
36
48
  parallel (1.21.0)
37
49
  parser (3.1.0.0)
38
50
  ast (~> 2.4.1)
51
+ racc (1.6.0)
39
52
  rainbow (3.1.1)
40
53
  rake (13.0.6)
41
54
  regexp_parser (2.2.0)
55
+ reverse_markdown (2.1.1)
56
+ nokogiri
42
57
  rexml (3.2.5)
43
58
  rspec (3.10.0)
44
59
  rspec-core (~> 3.10.0)
@@ -64,11 +79,39 @@ GEM
64
79
  unicode-display_width (>= 1.4.0, < 3.0)
65
80
  rubocop-ast (1.15.1)
66
81
  parser (>= 3.0.1.1)
82
+ rubocop-performance (1.13.2)
83
+ rubocop (>= 1.7.0, < 2.0)
84
+ rubocop-ast (>= 0.4.0)
85
+ rubocop-rake (0.6.0)
86
+ rubocop (~> 1.0)
87
+ rubocop-rspec (2.8.0)
88
+ rubocop (~> 1.19)
67
89
  ruby-progressbar (1.11.0)
90
+ solargraph (0.44.3)
91
+ backport (~> 1.2)
92
+ benchmark
93
+ bundler (>= 1.17.2)
94
+ diff-lcs (~> 1.4)
95
+ e2mmap
96
+ jaro_winkler (~> 1.5)
97
+ kramdown (~> 2.3)
98
+ kramdown-parser-gfm (~> 1.1)
99
+ parser (~> 3.0)
100
+ reverse_markdown (>= 1.0.5, < 3)
101
+ rubocop (>= 0.52)
102
+ thor (~> 1.0)
103
+ tilt (~> 2.0)
104
+ yard (~> 0.9, >= 0.9.24)
105
+ thor (1.2.1)
106
+ tilt (2.0.10)
68
107
  unicode-display_width (2.1.0)
108
+ webrick (1.7.0)
109
+ yard (0.9.27)
110
+ webrick (~> 1.7.0)
69
111
 
70
112
  PLATFORMS
71
113
  x86_64-darwin-20
114
+ x86_64-linux
72
115
 
73
116
  DEPENDENCIES
74
117
  bankroll!
@@ -76,6 +119,10 @@ DEPENDENCIES
76
119
  rake (~> 13.0)
77
120
  rspec (~> 3.0)
78
121
  rubocop (~> 1.21)
122
+ rubocop-performance
123
+ rubocop-rake
124
+ rubocop-rspec
125
+ solargraph
79
126
 
80
127
  BUNDLED WITH
81
128
  2.2.32
data/README.md CHANGED
@@ -46,8 +46,9 @@ puts payment #=> Bankroll::Decimal["3_216.40"]
46
46
  original_amount = Bankroll.present_value(
47
47
  periods: 360, # 30 years
48
48
  monthly_payment: 3_216.40,
49
- interest_rate: 0.01 / 12.0, # 2.5%
49
+ interest_rate: 0.01 / 12.0, # 1% APR
50
50
  ).round
51
+
51
52
  puts original_amount #=> Bankroll::Decimal["1_000_001.49"]
52
53
 
53
54
  # What does the balance look like after a single mortgage payment?
@@ -58,6 +59,7 @@ unpaid_balance = Bankroll.unpaid_balance(
58
59
  period: 1,
59
60
  payment: 3_216.40
60
61
  ).round
62
+
61
63
  puts unpaid_balance #=> Bankroll::Decimal["997_616.94"]
62
64
 
63
65
  # What was the interest rate?
@@ -66,6 +68,7 @@ interest_rate = Bankroll.interest_rate(
66
68
  periods: 360,
67
69
  payment: -3_216.40,
68
70
  ).round(3)
71
+
69
72
  puts interest_rate #=> Bankroll::Decimal["0.833e-3"]
70
73
 
71
74
  # What is the annuity factor of a rate for n periods?
@@ -73,6 +76,7 @@ annuity_factor = Bankroll.annuity_factor(
73
76
  interest_rate: 0.01,
74
77
  periods: 2
75
78
  ).round(4)
79
+
76
80
  puts annuity_factor #=> Bankroll::Decimal["1.9704"]
77
81
 
78
82
  # What is the total interest paid on a 500_000 1% mortgage
@@ -82,6 +86,7 @@ interest_paid = Bankroll.cumulative_interest(
82
86
  payment: 1_608.20,
83
87
  present_value: 500_000
84
88
  ).round
89
+
85
90
  puts interest_paid #=> Bankroll::Decimal["832.34"]
86
91
 
87
92
  # What is the total cost of a 500_000 1% loan with interest?
@@ -91,6 +96,7 @@ total_amount = Bankroll.future_value(
91
96
  periods: 360,
92
97
  payment: 1_608.20
93
98
  ).round
99
+
94
100
  puts total_amount #=> Bankroll::Decimal["647_846.10"]
95
101
 
96
102
  # What is the interest payment on the 17th period of a $165,000 3% mortgage?
@@ -100,6 +106,7 @@ interest_payment = Bankroll.interest_payment(
100
106
  period: 17,
101
107
  present_value: 165_000
102
108
  ).round
109
+
103
110
  puts interest_payment #=> Bankroll::Decimal["400.96"]
104
111
 
105
112
  # How many periods until a -$1000 account with -$100/month reaches $10_000 with
@@ -110,6 +117,7 @@ total_periods = Bankroll.total_periods(
110
117
  present_value: -1_000,
111
118
  future_value: 10_000
112
119
  )
120
+
113
121
  puts total_periods #=> Bankroll::Decimal["59.67"]
114
122
 
115
123
  # What is the amortization schedule of a $165_000 3% 30 year mortgage?
@@ -118,6 +126,7 @@ amortization_schedule = Bankroll.amortization_schedule(
118
126
  interest_rate: 0.03 / 12.0,
119
127
  periods: 360
120
128
  )
129
+
121
130
  puts amortization_schedule.payments #=> [
122
131
  # Bankroll::AmortizationSchedule::Payment.new(
123
132
  # payment: Bankroll::Decimal["695.65"],
data/bankroll.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Mortgage and refinance calculations for ruby"
13
13
  spec.homepage = "https://github.com/nolantait/bankroll"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.6.0"
15
+ spec.required_ruby_version = ">= 3.1.0"
16
16
 
17
17
  spec.metadata["homepage_uri"] = spec.homepage
18
18
  spec.metadata["source_code_uri"] = "https://github.com/nolantait/bankroll"
@@ -22,18 +22,20 @@ Gem::Specification.new do |spec|
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
23
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
24
  `git ls-files -z`.split("\x0").reject do |f|
25
- (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ (f == __FILE__) ||
26
+ f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
27
  end
27
28
  end
28
29
  spec.bindir = "exe"
29
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.executables = spec.files.grep(%r(\Aexe/)) { |f| File.basename(f) }
30
31
  spec.require_paths = ["lib"]
31
32
 
32
33
  # Uncomment to register a new dependency of your gem
33
- spec.add_dependency "dry-types"
34
- spec.add_dependency "dry-initializer"
35
- spec.add_dependency "dry-equalizer"
34
+ spec.add_dependency "dry-equalizer", "~> 0.3.0"
35
+ spec.add_dependency "dry-initializer", "~> 3.1.1"
36
+ spec.add_dependency "dry-types", "~> 1.5.1"
36
37
 
37
38
  # For more information and examples about making a new gem, checkout our
38
39
  # guide at: https://bundler.io/guides/creating_gem.html
40
+ spec.metadata["rubygems_mfa_required"] = "true"
39
41
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class AmortizationSchedule
3
5
  extend Dry::Initializer
@@ -18,22 +20,14 @@ module Bankroll
18
20
 
19
21
  def each
20
22
  Enumerator.new do |yielder|
21
- total_interest = Decimal["0"]
22
- balance = @present_value
23
+ current_payment = Payment.new(
24
+ payment: monthly_payment.round,
25
+ total_interest: Decimal["0"],
26
+ balance: @present_value
27
+ )
23
28
 
24
29
  periods.times do |period|
25
- interest = interest_payment(period + 1)
26
- principal = payment - interest
27
- total_interest += interest
28
- balance -= principal
29
-
30
- yielder << Payment.new(
31
- payment: payment.round,
32
- principal: principal.round,
33
- interest: interest.round,
34
- total_interest: total_interest.round,
35
- balance: balance.round
36
- )
30
+ yielder << current_payment = payment_for_period(period, current_payment)
37
31
  end
38
32
  end
39
33
  end
@@ -48,18 +42,31 @@ module Bankroll
48
42
 
49
43
  private
50
44
 
45
+ def payment_for_period(period, last_payment)
46
+ interest = interest_payment(period + 1)
47
+ principal = last_payment.payment - interest
48
+
49
+ Payment.new(
50
+ payment: last_payment.payment,
51
+ principal: principal.round,
52
+ interest: interest.round,
53
+ total_interest: (last_payment.total_interest + interest).round,
54
+ balance: (last_payment.balance - principal).round
55
+ )
56
+ end
57
+
51
58
  def interest_payment(period)
52
59
  InterestPayment.call(
53
60
  interest_rate: @interest_rate,
54
61
  periods: @periods,
55
- period: period,
62
+ period:,
56
63
  present_value: @present_value,
57
- payment: -payment
64
+ payment: -monthly_payment
58
65
  )
59
66
  end
60
67
 
61
- def payment
62
- @payment ||= Bankroll::Payment.call(
68
+ def monthly_payment
69
+ @monthly_payment ||= Bankroll::Payment.call(
63
70
  present_value: @present_value,
64
71
  interest_rate: @interest_rate,
65
72
  periods: @periods
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class AnnuityFactor
3
5
  extend Callable
4
6
  extend Dry::Initializer
5
7
 
6
- ONE = Decimal['1'].freeze
8
+ ONE = Decimal["1"].freeze
7
9
 
8
10
  option :periods, Types["bankroll.decimal"]
9
11
  option :interest_rate, Types["bankroll.decimal"]
@@ -19,7 +21,7 @@ module Bankroll
19
21
  end
20
22
 
21
23
  def interest_contribution_per_period
22
- (ONE + @interest_rate) ** -@periods
24
+ (ONE + @interest_rate)**-@periods
23
25
  end
24
26
  end
25
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  module Callable
3
5
  def call(**kwargs)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class CumulativeInterest
3
5
  # Calculate the total interest paid at any period
@@ -11,7 +13,7 @@ module Bankroll
11
13
  option :present_value, Types["bankroll.decimal"]
12
14
 
13
15
  def call
14
- payments_made +
16
+ payments_made +
15
17
  ((total_interest - @payment) * percentage_of_interest_per_period)
16
18
  end
17
19
 
@@ -26,7 +28,7 @@ module Bankroll
26
28
  end
27
29
 
28
30
  def compound_rate
29
- (ONE + @interest_rate) ** @periods
31
+ (ONE + @interest_rate)**@periods
30
32
  end
31
33
 
32
34
  def total_interest
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
- class Decimal < Delegator
4
+ class Decimal < SimpleDelegator
3
5
  include Dry::Equalizer.new(:value)
4
6
 
5
7
  ROUNDING = :half_even
@@ -13,17 +15,19 @@ module Bankroll
13
15
  end
14
16
 
15
17
  attr_reader :value
16
- alias_method :__getobj__, :value
18
+
19
+ alias __getobj__ value
17
20
 
18
21
  def initialize(value)
19
22
  decimal = case value
20
- when self.class
21
- value.value.to_s
22
- else
23
- value.to_s
24
- end
23
+ when self.class
24
+ value.value.to_s
25
+ else
26
+ value.to_s
27
+ end
25
28
 
26
29
  @value = BigDecimal(Types["string"][decimal])
30
+ super(@value)
27
31
  end
28
32
 
29
33
  def round(precision = 2, rounding = ROUNDING)
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class FutureValue
3
- # Future value is the value to which an investment will grow
4
- # after one or more periods. Usage is with a fixed payment
5
+ # Future value is the value to which an investment will grow
6
+ # after one or more periods. Usage is with a fixed payment
5
7
 
6
8
  extend Callable
7
9
  extend Dry::Initializer
@@ -13,13 +15,13 @@ module Bankroll
13
15
 
14
16
  def call
15
17
  (effective_rate * present_value) +
16
- (@payment * (1 + @interest_rate * 0) * (effective_rate - 1) / @interest_rate)
18
+ (@payment * (1 + (@interest_rate * 0)) * (effective_rate - 1) / @interest_rate)
17
19
  end
18
20
 
19
21
  private
20
22
 
21
23
  def effective_rate
22
- (ONE + @interest_rate) ** @periods
24
+ (ONE + @interest_rate)**@periods
23
25
  end
24
26
  end
25
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class InterestPayment
3
5
  # The interest portion of a payment at period N
@@ -9,7 +11,7 @@ module Bankroll
9
11
  option :periods, Types["bankroll.decimal"]
10
12
  option :period, Types["integer"]
11
13
  option :present_value, Types["bankroll.decimal"]
12
- option :payment, Types["bankroll.decimal"] | Types["nil"], default: -> { nil }
14
+ option :payment, Types["bankroll.decimal"] | Types["nil"], default: -> {}
13
15
 
14
16
  def call
15
17
  future_loan_balance * @interest_rate
@@ -20,7 +22,7 @@ module Bankroll
20
22
  def future_loan_balance
21
23
  FutureValue.call(
22
24
  periods: @period - 1,
23
- payment: payment,
25
+ payment:,
24
26
  present_value: @present_value,
25
27
  interest_rate: @interest_rate
26
28
  )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class InterestRate
3
5
  extend Dry::Initializer
@@ -15,7 +17,9 @@ module Bankroll
15
17
  significance_required = 1e-6
16
18
  stop = false
17
19
 
18
- begin
20
+ next_guess = 0
21
+
22
+ loop do
19
23
  temp = newton_iteration(
20
24
  guess,
21
25
  @periods,
@@ -28,20 +32,20 @@ module Bankroll
28
32
  difference = (next_guess - guess).abs
29
33
  stop = difference < significance_required
30
34
  guess = next_guess
31
- end while !stop
35
+ break if stop
36
+ end
32
37
 
33
38
  next_guess
34
39
  end
35
40
 
36
41
  private
37
42
 
38
-
39
43
  # This method was borrowed from the NumPy rate formula
40
44
  # which was generated by Sage
41
45
  def newton_iteration(r, n, p, x, y, w)
42
- t1 = (r+1)**n
43
- t2 = (r+1)**(n-1)
44
- ((y + t1*x + p*(t1 - 1)*(r*w + 1)/r) / (n*t2*x - p*(t1 - 1)*(r*w + 1)/(r**2) + n*p*t2*(r*w + 1)/r + p*(t1 - 1)*w/r))
46
+ t1 = (r + 1)**n
47
+ t2 = (r + 1)**(n - 1)
48
+ ((y + (t1 * x) + (p * (t1 - 1) * ((r * w) + 1) / r)) / ((n * t2 * x) - (p * (t1 - 1) * ((r * w) + 1) / (r**2)) + (n * p * t2 * ((r * w) + 1) / r) + (p * (t1 - 1) * w / r)))
45
49
  end
46
50
  end
47
51
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class Payment
3
5
  extend Callable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class PresentValue
3
5
  extend Callable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class TotalPeriods
3
5
  extend Callable
@@ -28,16 +30,16 @@ module Bankroll
28
30
  end
29
31
 
30
32
  def percentage_of_total_interest_on_principal
31
- (-@future_value + initial_payment_interest) /
33
+ (-@future_value + initial_payment_interest) /
32
34
  (@present_value + initial_payment_interest)
33
35
  end
34
36
 
35
37
  def initial_payment_interest
36
38
  case type
37
- when :ordinary
38
- (@payment * (1 + @interest_rate)) / @interest_rate
39
- else
40
- 0
39
+ when :ordinary
40
+ (@payment * (1 + @interest_rate)) / @interest_rate
41
+ else
42
+ 0
41
43
  end
42
44
  end
43
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  module Types
3
5
  include Dry.Types()
@@ -13,11 +15,9 @@ module Bankroll
13
15
  end
14
16
 
15
17
  ConvertToDecimal = lambda do |value|
16
- if value.is_a? Bankroll::Decimal
17
- return value
18
- else
19
- Bankroll::Decimal[value.to_s]
20
- end
18
+ return value if value.is_a? Bankroll::Decimal
19
+
20
+ Bankroll::Decimal[value.to_s]
21
21
  end
22
22
 
23
23
  register("bankroll.decimal", Constructor[Bankroll::Decimal, fn: ConvertToDecimal])
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bankroll
2
4
  class UnpaidBalance
3
5
  extend Callable
4
6
  extend Dry::Initializer
5
7
 
6
- ONE = Decimal['1'].freeze
8
+ ONE = Decimal["1"].freeze
7
9
 
8
10
  option :present_value, Types["bankroll.decimal"]
9
11
  option :interest_rate, Types["bankroll.decimal"]
@@ -30,7 +32,7 @@ module Bankroll
30
32
 
31
33
  def annuity_factor
32
34
  AnnuityFactor.call(
33
- interest_rate: @interest_rate,
35
+ interest_rate: @interest_rate,
34
36
  periods: remaining
35
37
  )
36
38
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bankroll
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/bankroll.rb CHANGED
@@ -25,9 +25,8 @@ require_relative "bankroll/interest_rate"
25
25
  BigDecimal.mode(BigDecimal::ROUND_MODE, Bankroll::Decimal::ROUNDING)
26
26
 
27
27
  module Bankroll
28
- ZERO = Decimal['0'].freeze
29
- ONE = Decimal['1'].freeze
30
-
28
+ ZERO = Decimal["0"].freeze
29
+ ONE = Decimal["1"].freeze
31
30
 
32
31
  class Error < StandardError; end
33
32
  # Your code goes here...
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bankroll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nolan J Tait
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-16 00:00:00.000000000 Z
11
+ date: 2022-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: dry-types
14
+ name: dry-equalizer
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.3.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 0.3.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dry-initializer
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 3.1.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 3.1.1
41
41
  - !ruby/object:Gem::Dependency
42
- name: dry-equalizer
42
+ name: dry-types
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 1.5.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 1.5.1
55
55
  description: Mortgage and refinance calculations for ruby
56
56
  email:
57
57
  - nolanjtait@gmail.com
@@ -94,6 +94,7 @@ metadata:
94
94
  homepage_uri: https://github.com/nolantait/bankroll
95
95
  source_code_uri: https://github.com/nolantait/bankroll
96
96
  changelog_uri: https://github.com/nolantait/bankroll/CHANGELOG.md
97
+ rubygems_mfa_required: 'true'
97
98
  post_install_message:
98
99
  rdoc_options: []
99
100
  require_paths:
@@ -102,14 +103,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
103
  requirements:
103
104
  - - ">="
104
105
  - !ruby/object:Gem::Version
105
- version: 2.6.0
106
+ version: 3.1.0
106
107
  required_rubygems_version: !ruby/object:Gem::Requirement
107
108
  requirements:
108
109
  - - ">="
109
110
  - !ruby/object:Gem::Version
110
111
  version: '0'
111
112
  requirements: []
112
- rubygems_version: 3.2.32
113
+ rubygems_version: 3.3.3
113
114
  signing_key:
114
115
  specification_version: 4
115
116
  summary: Mortgage and refinance calculations for ruby