financial_calculator 3.0.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f0d684ffcf8cd34cdad09576834da2057e6879b45af1484123474b6e151baad
4
- data.tar.gz: eccae432dc2cca2470cf1023871c0d9cb58620b080715c8ed00c818a62e4d2b4
3
+ metadata.gz: 7ece241c288b5547ac0946a57d3488646427c41744219e0a7f2d86a164a8e088
4
+ data.tar.gz: b8fa7e3149792486255d06c54b53998e5f1846fe013d1152d511642349e5080c
5
5
  SHA512:
6
- metadata.gz: 5715ae679ff1cc465004bf136989bdee35ce1d60c3c1a21cf6daac07ec4ecbe71f1db8f04ff26d8b3e57a525394e7508601c96be5c5923e443b6504014c94325
7
- data.tar.gz: 449cdc6640b282aea1e34a3de372717986232474310101bcf4097ecbbfac6021087aa26d1b4b429ab017239f40bd337c993f91675f3f7f9823920a1243c7bc70
6
+ metadata.gz: 880f9c1d6b98aadc025c246ba46e88b4f09928c92d395f59bfccb816796c806e2d1a9e3ce1358bf0c6ae288f4068c92bf9c466cd5d8013e68ff675a33dd0d6a4
7
+ data.tar.gz: bc10cbf71ecc8478778b46f61cbd25adbebb79dc074203200a14d31688ea6c4cf123cf728957a0f3c6a99e300648d15cf52718dee74fc395eb23128953dcd499
data/CHANGELOG.md CHANGED
@@ -6,9 +6,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.1.0] - 2018-05-20
10
+ ### Added
11
+ - New class for PMT calculation (FinancialCalculator::Pmt)
12
+
13
+ ### Removed
14
+
15
+ ### Changed
16
+
9
17
  ## [3.0.0] - 2018-05-12
10
18
  ### Added
11
- - New class for Present Value calculation (FinancialCalculator::PV)
19
+ - New class for Present Value calculation (FinancialCalculator::Pv)
12
20
 
13
21
  ### Removed
14
22
  - Monkey patched cashflow methods on Array
data/README.md CHANGED
@@ -107,11 +107,12 @@ You can also increase your payment to a specific amount:
107
107
  >> extra_payments_2 = 250000.amortize(rate){ -1500 }
108
108
 
109
109
  ## SUPPORTED STANDARD CALCUALTIONS
110
- - PV
111
- - NPV
112
- - XNPV
113
110
  - IRR
111
+ - NPV
112
+ - PMT
113
+ - PV
114
114
  - XIRR
115
+ - XNPV
115
116
 
116
117
  ## FEATURES
117
118
 
@@ -8,6 +8,7 @@ require 'flt/d'
8
8
  # * *principal* represents the outstanding balance of a loan or annuity.
9
9
  # * *rate* represents the interest rate _per period_.
10
10
  module FinancialCalculator
11
+ require 'financial_calculator/validator'
11
12
  require 'financial_calculator/amortization'
12
13
  require 'financial_calculator/rates'
13
14
  require 'financial_calculator/transaction'
@@ -16,4 +17,5 @@ module FinancialCalculator
16
17
  require 'financial_calculator/npv'
17
18
  require 'financial_calculator/xnpv'
18
19
  require 'financial_calculator/xirr'
20
+ require 'financial_calculator/pmt'
19
21
  end
@@ -0,0 +1,67 @@
1
+ module FinancialCalculator
2
+ # Calculates the payment of an ordinary annuity
3
+ class Pmt
4
+ include ::Validator
5
+
6
+ # @return [Numeric] The rate used for calculating the payment amount
7
+ # @api public
8
+ attr_reader :rate
9
+
10
+ # @return [Numeric] The number of payments to be made
11
+ # @api public
12
+ attr_reader :num_periods
13
+
14
+ # @return [Numeric] The current value of the annuity
15
+ # @api public
16
+ attr_reader :present_value
17
+
18
+ # @return [Numeric] The ending value of the annuity. Defaults to 0
19
+ # @api public
20
+ attr_reader :future_value
21
+
22
+ # @return [Boolean] Whether the payment is made at the beginning of the
23
+ # period (true) or end of the period (false)
24
+ # @api public
25
+ attr_reader :pay_at_beginning
26
+
27
+ # @return [DecNum] Result of the PMT calculation
28
+ # @api public
29
+ attr_reader :result
30
+
31
+ # Create a new object for calculating the periodic payment of an ordinary annuity
32
+ # @param [Numeric] rate The discount (interest) rate
33
+ # @param [Numeric] num_periods The number of payments to be made
34
+ # @param [Numeric] present_value The current value of the annuity
35
+ # @param [Numeric] future_value The ending value of the annuity
36
+ # @param [Boolean] pay_at_beginning. Whether the payment is made at the beginning
37
+ # of the period (true) or end of the period (false)
38
+ # @return [FinancialCalculator::Npv] An instance of a PMT calculation
39
+ def initialize(rate, num_periods, present_value, future_value = 0, pay_at_beginning = false)
40
+ validate_numerics(rate: rate, num_periods: num_periods, present_value: present_value, future_value: future_value)
41
+
42
+ @rate = Flt::DecNum(rate.to_s)
43
+ @num_periods = Flt::DecNum(num_periods.to_s)
44
+ @present_value = Flt::DecNum(present_value.to_s)
45
+ @future_value = Flt::DecNum(future_value || "0")
46
+ @pay_at_beginning = pay_at_beginning || false
47
+ @result = solve(@rate, @num_periods, @present_value, @future_value, @pay_at_beginning)
48
+ end
49
+
50
+ # @return [Boolean] Whether the payments are made at the beginning of each period
51
+ # @api public
52
+ def pays_at_beginning?
53
+ @pay_at_beginning
54
+ end
55
+
56
+ def inspect
57
+ "PMT(#{result})"
58
+ end
59
+
60
+ private
61
+
62
+ def solve(i, nper, pv, fv, pay_at_beginning)
63
+ type = pay_at_beginning ? 1 : 0
64
+ @result = ((pv * (1 + i) ** nper) + fv) * i / ((1 + i * type) * (1 - (1 + i) ** nper))
65
+ end
66
+ end
67
+ end
@@ -1,6 +1,7 @@
1
1
  module FinancialCalculator
2
2
  # Calculate the future value of a series of equal of payments
3
3
  class Pv
4
+ include ::Validator
4
5
 
5
6
  # @return [Numeric] The discount rate used in the calculation
6
7
  attr_reader :rate
@@ -71,14 +72,6 @@ module FinancialCalculator
71
72
  return 0 if amount.zero?
72
73
  amount / (1 + rate) ** periods
73
74
  end
74
-
75
- def validate_numerics(numerics)
76
- numerics.each do |key, value|
77
- unless value.is_a? Numeric
78
- raise ArgumentError.new("#{key} must be a type of Numeric. Got #{value.class} instead.")
79
- end
80
- end
81
- end
82
75
  end
83
76
 
84
77
  PresentValue = Pv
@@ -0,0 +1,10 @@
1
+ module Validator
2
+ protected
3
+ def validate_numerics(numerics)
4
+ numerics.each do |key, value|
5
+ unless value.is_a? Numeric
6
+ raise ArgumentError.new("#{key} must be a type of Numeric. Got #{value.class} instead.")
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module FinancialCalculator
2
- VERSION = '3.0.0'
2
+ VERSION = '3.1.0'
3
3
  end
data/spec/pmt_spec.rb ADDED
@@ -0,0 +1,71 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "Pmt" do
4
+ let(:rate) { 0.1 }
5
+ let(:present_value) { 1000 }
6
+ let(:num_periods) { 20 }
7
+ let(:future_value) { 0 }
8
+ let(:pay_at_beginning) { false }
9
+ let(:pmt) { Pmt.new(rate, num_periods, present_value, future_value, pay_at_beginning) }
10
+
11
+ subject { pmt }
12
+
13
+ it 'has a rate attribute' do
14
+ expect(subject).to have_attributes(rate: rate)
15
+ end
16
+
17
+ it 'has a num_periods attribute' do
18
+ expect(subject).to have_attributes(num_periods: num_periods)
19
+ end
20
+
21
+ it 'has a present_value attribute' do
22
+ expect(subject).to have_attributes(present_value: present_value)
23
+ end
24
+
25
+ it 'has a future_value attribute' do
26
+ expect(subject).to have_attributes(future_value: future_value)
27
+ end
28
+
29
+ it 'has a pays_at_beginning? attribute that defaults to false' do
30
+ expect(subject).to have_attributes(pays_at_beginning?: false)
31
+ end
32
+
33
+ it 'has a result attribute' do
34
+ expect(subject.result).to be_a Numeric
35
+ end
36
+
37
+ context 'when payments occur at the beginning of each period' do
38
+ let(:pay_at_beginning) { true }
39
+ it { is_expected.to have_attributes(pays_at_beginning?: true) }
40
+ end
41
+
42
+ context 'when given a non-numeric rate' do
43
+ let(:rate) { 'string' }
44
+ it_behaves_like 'it has invalid arguments'
45
+ end
46
+
47
+ context 'when given a non-numeric number of periods' do
48
+ let(:num_periods) { 'string' }
49
+ it_behaves_like 'it has invalid arguments'
50
+ end
51
+
52
+ context 'when given a non-numeric present value' do
53
+ let(:present_value) { 'string' }
54
+ it_behaves_like 'it has invalid arguments'
55
+ end
56
+
57
+ context 'when give a non-numeric future value' do
58
+ let(:future_value) { 'string' }
59
+ it_behaves_like 'it has invalid arguments'
60
+ end
61
+
62
+ describe '#inspect' do
63
+ subject { pmt.inspect }
64
+
65
+ it { is_expected.to be_a String }
66
+ it { is_expected.to include 'PMT' }
67
+ it 'includes the result of the PMT calculation' do
68
+ expect(subject).to include pmt.result.to_s
69
+ end
70
+ end
71
+ end
data/spec/pv_spec.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require_relative 'spec_helper'
2
2
 
3
- shared_examples_for 'it has invalid present value arguments' do
4
- it 'raises an ArgumentError' do
5
- expect { subject }.to raise_error ArgumentError
6
- end
7
- end
3
+ # shared_examples_for 'it has invalid arguments' do
4
+ # it 'raises an ArgumentError' do
5
+ # expect { subject }.to raise_error ArgumentError
6
+ # end
7
+ # end
8
8
 
9
9
  describe "Pv" do
10
10
  let(:rate) { 0.1 }
@@ -58,22 +58,22 @@ describe "Pv" do
58
58
 
59
59
  context 'when the number of periods is negative' do
60
60
  let(:num_periods) { -1 }
61
- it_behaves_like 'it has invalid present value arguments'
61
+ it_behaves_like 'it has invalid arguments'
62
62
  end
63
63
 
64
64
  context 'when rate is non-numeric' do
65
65
  let(:rate) { 'string' }
66
- it_behaves_like 'it has invalid present value arguments'
66
+ it_behaves_like 'it has invalid arguments'
67
67
  end
68
68
 
69
69
  context 'when num_periods is non-numeric' do
70
70
  let(:num_periods) { 'string' }
71
- it_behaves_like 'it has invalid present value arguments'
71
+ it_behaves_like 'it has invalid arguments'
72
72
  end
73
73
 
74
74
  context 'when payment is non-numeric' do
75
75
  let(:payment) { 'string' }
76
- it_behaves_like 'it has invalid present value arguments'
76
+ it_behaves_like 'it has invalid arguments'
77
77
  end
78
78
 
79
79
  context 'when future_values non-numeric' do
@@ -81,7 +81,7 @@ describe "Pv" do
81
81
 
82
82
  subject { Pv.new(rate, num_periods, payment, future_value) }
83
83
 
84
- it_behaves_like 'it has invalid present value arguments'
84
+ it_behaves_like 'it has invalid arguments'
85
85
  end
86
86
 
87
87
  context 'when the number of periods is 0' do
data/spec/spec_helper.rb CHANGED
@@ -21,4 +21,10 @@ shared_examples_for 'the values do not converge' do
21
21
  it 'should raise an ArgumentError' do
22
22
  expect { subject }.to raise_error ArgumentError
23
23
  end
24
+ end
25
+
26
+ shared_examples_for 'it has invalid arguments' do
27
+ it 'raises an ArgumentError' do
28
+ expect { subject }.to raise_error ArgumentError
29
+ end
24
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: financial_calculator
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Falzone
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-12 00:00:00.000000000 Z
11
+ date: 2018-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: flt
@@ -162,15 +162,18 @@ files:
162
162
  - lib/financial_calculator/amortization.rb
163
163
  - lib/financial_calculator/irr.rb
164
164
  - lib/financial_calculator/npv.rb
165
+ - lib/financial_calculator/pmt.rb
165
166
  - lib/financial_calculator/pv.rb
166
167
  - lib/financial_calculator/rates.rb
167
168
  - lib/financial_calculator/transaction.rb
169
+ - lib/financial_calculator/validator.rb
168
170
  - lib/financial_calculator/version.rb
169
171
  - lib/financial_calculator/xirr.rb
170
172
  - lib/financial_calculator/xnpv.rb
171
173
  - spec/amortization_spec.rb
172
174
  - spec/irr_spec.rb
173
175
  - spec/npv_spec.rb
176
+ - spec/pmt_spec.rb
174
177
  - spec/pv_spec.rb
175
178
  - spec/rates_spec.rb
176
179
  - spec/spec_helper.rb
@@ -207,6 +210,7 @@ test_files:
207
210
  - spec/amortization_spec.rb
208
211
  - spec/irr_spec.rb
209
212
  - spec/npv_spec.rb
213
+ - spec/pmt_spec.rb
210
214
  - spec/pv_spec.rb
211
215
  - spec/rates_spec.rb
212
216
  - spec/spec_helper.rb