mortgage_calculations 0.1.10 → 0.2.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.
- data/README.rdoc +12 -9
- data/VERSION +1 -1
- data/features/step_definitions/apr_steps.rb +2 -1
- data/lib/mortgage_calc/mortgage_util.rb +4 -15
- data/mortgage_calculations.gemspec +2 -2
- data/spec/mortgage_calc/mortgage_util_spec.rb +22 -43
- metadata +29 -29
data/README.rdoc
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
-
=
|
1
|
+
= mortgage_calculations
|
2
2
|
|
3
3
|
http://www.pathf.com/blogs/2010/02/mortcalc-gem/
|
4
4
|
|
5
|
-
Calculates mortgage APR
|
5
|
+
Calculates mortgage APR and monthly payments.
|
6
6
|
|
7
7
|
== INSTALL
|
8
|
-
$ sudo gem install
|
9
|
-
|
10
|
-
|
8
|
+
$ sudo gem install mortgage_calculations
|
9
|
+
|
10
|
+
or add following to your Gemfile
|
11
|
+
|
12
|
+
gem "mortgage_calculations", :require => "mortgage_calc"
|
13
|
+
|
11
14
|
or add the following to your <b>environment.rb</b>
|
12
|
-
|
15
|
+
|
16
|
+
config.gem 'mortgage_calculations', :lib => "mortgage_calc"
|
13
17
|
|
14
18
|
==Example:
|
15
19
|
loan_amount = 350000
|
@@ -18,12 +22,11 @@ or add the following to your <b>environment.rb</b>
|
|
18
22
|
lender_fee = 800
|
19
23
|
points = 1.0
|
20
24
|
|
21
|
-
mort_calc = MortgageCalc::MortgageUtil.new(loan_amount, interest_rate,
|
25
|
+
mort_calc = MortgageCalc::MortgageUtil.new(loan_amount, interest_rate, total_fees, period)
|
22
26
|
|
23
27
|
mort_calc.apr
|
24
28
|
mort_calc.monthly_payment
|
25
29
|
mort_calc.monthly_payment_with_fees
|
26
|
-
mort_calc.total_fees
|
27
30
|
|
28
31
|
==Formulas used
|
29
32
|
===Monthly payment with fees
|
@@ -46,4 +49,4 @@ or add the following to your <b>environment.rb</b>
|
|
46
49
|
|
47
50
|
===Total fees
|
48
51
|
Total fees are calculated simply by adding Lender fees to the points paid by borrower.
|
49
|
-
T = E + P(C)
|
52
|
+
T = E + P(C)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.2.1
|
@@ -1,5 +1,6 @@
|
|
1
1
|
Given /^(.*), (.*), (.*), (.*), (.*)$/ do |loan_amount, fees, points, rate, period|
|
2
|
-
|
2
|
+
fee = Float(fees) + Float(loan_amount) * Float(points)/100
|
3
|
+
@mortgage_util = MortgageCalc::MortgageUtil.new(Integer(loan_amount), Float(rate), fee, Integer(period))
|
3
4
|
end
|
4
5
|
|
5
6
|
Then /^the resultant apr should be (.*)$/ do |apr_expected|
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module MortgageCalc
|
2
2
|
class MortgageUtil
|
3
|
-
attr_accessor :loan_amount, :interest_rate, :period, :
|
3
|
+
attr_accessor :loan_amount, :interest_rate, :period, :fee
|
4
4
|
|
5
|
-
def initialize(loan_amount, interest_rate, period=360
|
5
|
+
def initialize(loan_amount, interest_rate, fee, period=360)
|
6
6
|
self.loan_amount = Float(loan_amount.to_s)
|
7
7
|
self.interest_rate = Float(interest_rate.to_s)
|
8
8
|
self.period = Integer(period.to_s)
|
9
|
-
self.
|
10
|
-
self.points = Float(points.to_s)
|
9
|
+
self.fee = Float(fee.to_s)
|
11
10
|
end
|
12
11
|
|
13
12
|
def apr
|
@@ -19,13 +18,7 @@ module MortgageCalc
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def monthly_payment_with_fees
|
22
|
-
@monthly_payment_with_fees ||= calculate_monthly_payment(self.loan_amount +
|
23
|
-
end
|
24
|
-
|
25
|
-
def total_fees(negative_allowed = true)
|
26
|
-
#fees may not be negative (borrower is not paid)
|
27
|
-
total_fees = calculate_total_fees
|
28
|
-
!negative_allowed && total_fees < 0 ? 0 : total_fees
|
21
|
+
@monthly_payment_with_fees ||= calculate_monthly_payment(self.loan_amount + fee, monthly_interest_rate, self.period)
|
29
22
|
end
|
30
23
|
|
31
24
|
private
|
@@ -37,10 +30,6 @@ module MortgageCalc
|
|
37
30
|
amount * (monthly_rate/(1 - (1 + monthly_rate)**(-period)))
|
38
31
|
end
|
39
32
|
|
40
|
-
def calculate_total_fees
|
41
|
-
self.fees + (self.loan_amount * points/100)
|
42
|
-
end
|
43
|
-
|
44
33
|
# solves APR
|
45
34
|
# [a (1 + a)^N] / [(1 + a)^N - 1] - P/C = 0
|
46
35
|
# where a = APR/1200, N = period, P = monthly payment, C = loan_amount
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mortgage_calculations}
|
8
|
-
s.version = "0.1
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Perry Hertler"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-02-14}
|
13
13
|
s.description = %q{Utilities for Mortgage related calculations (APR and Monthly Payments)}
|
14
14
|
s.email = %q{perry@hertler.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -1,17 +1,20 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
module MortgageCalc
|
3
3
|
describe MortgageUtil do
|
4
|
-
def assert_monthly_apr_payment_matches(loan_amount, rate,
|
5
|
-
mortgage_util = MortgageUtil.new(loan_amount, rate,
|
4
|
+
def assert_monthly_apr_payment_matches(loan_amount, rate, fee, period)
|
5
|
+
mortgage_util = MortgageUtil.new(loan_amount, rate, fee, period)
|
6
6
|
monthly_payment_with_fees = mortgage_util.monthly_payment_with_fees
|
7
|
-
monthly_payment_from_apr = MortgageUtil.new(loan_amount, mortgage_util.apr,
|
7
|
+
monthly_payment_from_apr = MortgageUtil.new(loan_amount, mortgage_util.apr, calc_total_fee(loan_amount, 0, 0), period).monthly_payment
|
8
8
|
monthly_payment_with_fees.should be_within(0.01).of(monthly_payment_from_apr)
|
9
9
|
end
|
10
10
|
|
11
|
+
def calc_total_fee(loan_amount, points, fee)
|
12
|
+
loan_amount * points/100 + fee
|
13
|
+
end
|
14
|
+
|
11
15
|
context "with valid MortgageUtil" do
|
12
16
|
before(:all) do
|
13
|
-
@mortgage_util = MortgageUtil.new(
|
14
|
-
@mortgage_util_with_apr_as_rate = MortgageUtil.new(100000, @mortgage_util.apr, 360, 1200, 1.25)
|
17
|
+
@mortgage_util = MortgageUtil.new(100_000, 6.0, calc_total_fee(100_000, 1.25, 1200), 360)
|
15
18
|
end
|
16
19
|
it "should have proper monthly interest rate" do
|
17
20
|
@mortgage_util.send(:monthly_interest_rate).should == 0.005
|
@@ -20,68 +23,44 @@ module MortgageCalc
|
|
20
23
|
@mortgage_util.monthly_payment.should be_within(0.001).of(599.55)
|
21
24
|
end
|
22
25
|
it "should have proper total fees" do
|
23
|
-
@mortgage_util.
|
26
|
+
@mortgage_util.fee.should be_within(0.001).of(2450)
|
24
27
|
end
|
25
28
|
it "should have proper APR" do
|
26
29
|
@mortgage_util.apr.should be_within(0.00001).of(6.22726)
|
27
30
|
end
|
28
31
|
end
|
32
|
+
|
29
33
|
it "should calculate original monthly payment from APR" do
|
30
|
-
assert_monthly_apr_payment_matches(
|
31
|
-
assert_monthly_apr_payment_matches(
|
32
|
-
assert_monthly_apr_payment_matches(
|
33
|
-
assert_monthly_apr_payment_matches(
|
34
|
-
assert_monthly_apr_payment_matches(
|
34
|
+
assert_monthly_apr_payment_matches(300_000, 6.5, calc_total_fee(300_000, 1.25, 1200), 360)
|
35
|
+
assert_monthly_apr_payment_matches(300_000, 6.5, calc_total_fee(300_000, 0, 0), 360)
|
36
|
+
assert_monthly_apr_payment_matches(400_000, 1.1, calc_total_fee(400_000, 1.25, 1200), 180)
|
37
|
+
assert_monthly_apr_payment_matches(300_000, 6.5, calc_total_fee(300_000, 7.25, 0), 360)
|
38
|
+
assert_monthly_apr_payment_matches(300_000, 6.5, calc_total_fee(300_000, 7.25, 10000), 360)
|
35
39
|
end
|
36
40
|
|
37
|
-
# context "with very small loan amount" do
|
38
|
-
# it "should calculate proper apr when loan_amount is very small" do
|
39
|
-
# @mortgage_util = MortgageUtil.new(5000, 6.0, 360, 1200, 1.25)
|
40
|
-
# puts "@mortgage_util.apr = #{@mortgage_util.apr}"
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
|
44
41
|
# APR calculations from following web site are assumed to be accurate:
|
45
42
|
# http://www.debtconsolidationcare.com/calculator/apr.html
|
46
43
|
context "test apr calculation" do
|
47
44
|
it "should calculate proper apr" do
|
48
|
-
@mortgage_util = MortgageUtil.new(125000, 6.5,
|
45
|
+
@mortgage_util = MortgageUtil.new(125000, 6.5, calc_total_fee(125_000, 0, 5000))
|
49
46
|
@mortgage_util.apr.should be_within(0.001).of(6.881)
|
50
47
|
end
|
51
|
-
it "should calculate
|
52
|
-
@mortgage_util =
|
53
|
-
@mortgage_util.
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context "net negative fees" do
|
58
|
-
before(:all) do
|
59
|
-
@mortgage_util = MortgageUtil.new(100000, 6.0, 360, 1200, -11.25)
|
60
|
-
@mortgage_util.total_fees.should eql -10050.0
|
61
|
-
end
|
62
|
-
it "calculate total fees should return actual total fees is less than 0" do
|
63
|
-
@mortgage_util.send(:calculate_total_fees).should eql -10050.0
|
64
|
-
end
|
65
|
-
it "total fees should return 0 if total fees is less than 0" do
|
66
|
-
@mortgage_util.total_fees(false).should eql 0
|
67
|
-
end
|
68
|
-
it "total fees should return actual fees if negative parameter is true" do
|
69
|
-
@mortgage_util.total_fees(true).should eql -10050.0
|
70
|
-
end
|
71
|
-
it "should not return APR less than interest rate" do
|
48
|
+
it "should calculate APR less than interest rate" do
|
49
|
+
@mortgage_util = MortgageUtil.new(100_000, 6.0, calc_total_fee(100_000, -11.25, 1200))
|
50
|
+
@mortgage_util.fee.should eql -10050.0
|
72
51
|
@mortgage_util.apr.should be_within(0.00001).of(5.04043)
|
73
52
|
end
|
74
53
|
end
|
75
54
|
|
76
55
|
context "initialize convert to best types" do
|
77
56
|
before(:all) do
|
78
|
-
@mortgage_util = MortgageUtil.new('
|
57
|
+
@mortgage_util = MortgageUtil.new('100_000', '6.0', calc_total_fee(100_000, -1.25, 1200))
|
79
58
|
end
|
80
59
|
it "should convert rate to float if necessary" do
|
81
60
|
@mortgage_util.interest_rate.class.should == Float
|
82
61
|
end
|
83
|
-
it "should convert
|
84
|
-
@mortgage_util.
|
62
|
+
it "should convert fee to float if necessary" do
|
63
|
+
@mortgage_util.fee.class.should == Float
|
85
64
|
end
|
86
65
|
it "should convert loan_amount to float if necessary" do
|
87
66
|
@mortgage_util.loan_amount.class.should == Float
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mortgage_calculations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 2
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.10
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Perry Hertler
|
@@ -15,11 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-02-14 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
22
|
+
prerelease: false
|
23
|
+
type: :development
|
24
|
+
name: rspec
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
26
|
none: false
|
24
27
|
requirements:
|
25
28
|
- - ~>
|
@@ -30,12 +33,12 @@ dependencies:
|
|
30
33
|
- 1
|
31
34
|
- 0
|
32
35
|
version: 2.1.0
|
33
|
-
|
34
|
-
name: rspec
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: *id001
|
36
|
+
requirement: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
|
-
|
38
|
+
prerelease: false
|
39
|
+
type: :development
|
40
|
+
name: cucumber
|
41
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
42
|
none: false
|
40
43
|
requirements:
|
41
44
|
- - ">="
|
@@ -44,12 +47,12 @@ dependencies:
|
|
44
47
|
segments:
|
45
48
|
- 0
|
46
49
|
version: "0"
|
47
|
-
|
48
|
-
name: cucumber
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: *id002
|
50
|
+
requirement: *id002
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
-
|
52
|
+
prerelease: false
|
53
|
+
type: :development
|
54
|
+
name: bundler
|
55
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
53
56
|
none: false
|
54
57
|
requirements:
|
55
58
|
- - ~>
|
@@ -60,12 +63,12 @@ dependencies:
|
|
60
63
|
- 0
|
61
64
|
- 0
|
62
65
|
version: 1.0.0
|
63
|
-
|
64
|
-
name: bundler
|
65
|
-
prerelease: false
|
66
|
-
version_requirements: *id003
|
66
|
+
requirement: *id003
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
-
|
68
|
+
prerelease: false
|
69
|
+
type: :development
|
70
|
+
name: jeweler
|
71
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
69
72
|
none: false
|
70
73
|
requirements:
|
71
74
|
- - ~>
|
@@ -76,12 +79,12 @@ dependencies:
|
|
76
79
|
- 5
|
77
80
|
- 1
|
78
81
|
version: 1.5.1
|
79
|
-
|
80
|
-
name: jeweler
|
81
|
-
prerelease: false
|
82
|
-
version_requirements: *id004
|
82
|
+
requirement: *id004
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
|
84
|
+
prerelease: false
|
85
|
+
type: :development
|
86
|
+
name: rcov
|
87
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
85
88
|
none: false
|
86
89
|
requirements:
|
87
90
|
- - ">="
|
@@ -90,10 +93,7 @@ dependencies:
|
|
90
93
|
segments:
|
91
94
|
- 0
|
92
95
|
version: "0"
|
93
|
-
|
94
|
-
name: rcov
|
95
|
-
prerelease: false
|
96
|
-
version_requirements: *id005
|
96
|
+
requirement: *id005
|
97
97
|
description: Utilities for Mortgage related calculations (APR and Monthly Payments)
|
98
98
|
email: perry@hertler.org
|
99
99
|
executables: []
|