Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jonathanmartindell #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions JonsGame/controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require_relative 'view'
require_relative 'retirement_account_scenario'

class GameController
include GameView

def run!
sample_values = {name: "Sample Scenario", beginning_age: 23}
scenario1 = RetirementAccountScenario.new sample_values
scenario2 = RetirementAccountScenario.new sample_values

Print::run_spinner
Print::title_screen

loop do
Print::menu
case Print::fetch_user_input
when "V"
Print::print_retirement_comparison(scenario1, scenario2)
when "S1"
scenario1 = RetirementAccountScenario.new Print::serialize_scenario
when "S2"
scenario2 = RetirementAccountScenario.new Print::serialize_scenario
when "Q"
puts "We're done"
exit
else
Print::error_message
end
end
end
end

GameController.new.run!
63 changes: 63 additions & 0 deletions JonsGame/retirement_account_scenario.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require 'faker'
require 'pry'

class RetirementAccountScenario
attr_reader :name, :beginning_age, :retirement_age, :death_age
attr_reader :ira_type, :annual_contribution
attr_reader :accumulation_market_return_rate, :accumulation_tax_rate
attr_reader :retirement_tax_rate

VALID_IRA_TYPES = [ :roth, :regular]

def initialize args
@name = args.fetch(:name, "UNNAMED")
@beginning_age = args.fetch(:beginning_age, 25).to_f
@retirement_age = args.fetch(:retirement_age, 65).to_f
@death_age = args.fetch(:death_age, 100).to_f
@annual_contribution = args.fetch(:annual_contribution, 500).to_f
@accumulation_market_return_rate = args.fetch(:accumulation_market_return_rate, 0.01).to_f
@accumulation_tax_rate = args.fetch(:accumulation_tax_rate, 0).to_f
@retirement_tax_rate = args.fetch(:retirement_tax_rate, 0).to_f
@ira_type = args.fetch(:ira_type, :regular)

raise ArguementError "Retirement must be after beginning age" unless retirement_age > beginning_age
raise ArguementError "Death must be after retirement" unless death_age > retirement_age
raise ArguementError "Must earn interest" unless accumulation_market_return_rate > 0
raise ArguementError "Must contribute" unless annual_contribution > 0
raise ArguementError unless VALID_IRA_TYPES.include?(ira_type)
end

def retirement_income
yearly_withdraw = (balance_at_retirement / years_in_retirement).round
if ira_type == :roth
yearly_withdraw
else #Must take out taxes
(yearly_withdraw * (1.0 - retirement_tax_rate)).round
end
end

private

def balance_at_retirement
# http://www.moneychimp.com/articles/finworks/fmbasinv.htm
z = 1 + accumulation_market_return_rate
if ira_type == :roth
c = annual_contribution * (1.0 - accumulation_tax_rate)
else
c = annual_contribution
end
y = years_in_accumulation

c * ( ( z**(y + 1) - z ) / ( z - 1 ))
end

def years_in_retirement
death_age - retirement_age
end

def years_in_accumulation
retirement_age - beginning_age
end

end

86 changes: 86 additions & 0 deletions JonsGame/spec/retirement_account_scenario_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
require_relative '../retirement_account_scenario'

describe RetirementAccountScenario do
describe "#retirement_income" do
context "when given valid parameters" do
subject(:valid_scenario) {
setup_values = {}
setup_values[:name] = "Valid Account"
setup_values[:beginning_age] = 35
setup_values[:retirement_age] = 65
setup_values[:death_age] = 95
setup_values[:annual_contribution] = 5000
setup_values[:accumulation_market_return_rate] = 0.08
setup_values[:ira_type] = :roth
RetirementAccountScenario.new setup_values
}

it "correctly calculates income" do
expect(valid_scenario.retirement_income).to eq(20391)
end
end

context "when roth is given accumulation tax rate" do
subject() {
setup_values = {}
setup_values[:name] = "Valid with Tax Rate"
setup_values[:beginning_age] = 35
setup_values[:retirement_age] = 65
setup_values[:death_age] = 95
setup_values[:annual_contribution] = 5000
setup_values[:accumulation_market_return_rate] = 0.08
setup_values[:accumulation_tax_rate] = 0.28
setup_values[:ira_type] = :roth
RetirementAccountScenario.new setup_values
}
it "reduces contributions by tax rate" do
expect(subject.retirement_income).to eq(14682)
end
end

context "when roth is given retirement tax rate" do
subject() {
setup_values = {}
setup_values[:name] = "Valid with Tax Rate"
setup_values[:beginning_age] = 35
setup_values[:retirement_age] = 65
setup_values[:death_age] = 95
setup_values[:annual_contribution] = 5000
setup_values[:accumulation_market_return_rate] = 0.08
setup_values[:accumulation_tax_rate] = 0.28
setup_values[:retirement_tax_rate] = 0.20
setup_values[:ira_type] = :roth
RetirementAccountScenario.new setup_values
}
it "does not reduce retirement income" do
expect(subject.retirement_income).to eq(14682)
end
end

context "when a regular retirement account" do
subject() {
setup_values = {}
setup_values[:name] = "Regular retirement account"
setup_values[:beginning_age] = 35
setup_values[:retirement_age] = 65
setup_values[:death_age] = 95
setup_values[:annual_contribution] = 5000
setup_values[:accumulation_market_return_rate] = 0.08
setup_values[:accumulation_tax_rate] = 0.28
setup_values[:retirement_tax_rate] = 0.20
setup_values[:ira_type] = :regular
RetirementAccountScenario.new setup_values
}
it "gets taxed in retirement" do
expect(subject.retirement_income).to eq (16313)
end

end
end

describe "#initialize" do
context "when a required parameter is missing" do
it { expect { RetirementAccountScenario.new nothing: "yes" }.to_not raise_error() }
end
end
end
129 changes: 129 additions & 0 deletions JonsGame/view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
module GameView

module Print

class << self
def run_spinner
print "Loading (please wait) "
#5.times { print "."; sleep 1; }
5.times { print "."; }
print "\n"
end

def error_message
puts "That's not a command key. Try again!"
end

def title_screen
title = <<TITLE

***************** || ******************
* Retirement Comparer *
***************** || ******************

TITLE
puts title
end

def menu
menu = <<EOS

************** Welcome **************
- (S1)etup retirement scenario 1
- (S2)etup retirement scenario 2
- (V)iew retirement incomes
- (Q)uit program
************** **************

EOS
puts menu
end

def print_retirement_comparison(scenario1, scenario2)
output = Array.new(14, "")
add_frame output
add_row_header output

add_scenario_output(output, scenario1)
add_frame output
add_scenario_output(output, scenario2)
puts output
puts results_output(scenario1, scenario2)
end

def add_scenario_output(output, scenario)
output[1] += sprintf("%-32s", scenario.name)
output[3] += sprintf("%-11d", scenario.beginning_age)
output[4] += sprintf("%-11d", scenario.retirement_age)
output[5] += sprintf("%-11d", scenario.death_age)
output[6] += sprintf("$%-10d", scenario.annual_contribution)
output[7] += sprintf("%-11.2f", scenario.accumulation_market_return_rate)
output[8] += sprintf("%-11.2f", scenario.accumulation_tax_rate)
output[9] += sprintf("%-11.2f", scenario.retirement_tax_rate)
output[10] += sprintf("%-11s", scenario.ira_type.to_s)
output[12] += sprintf("$%-10d", scenario.retirement_income)
end

def add_frame(output)
output[0] += "******************************* "
output[1] += ""
output[2] += "******************************* "
output[3] += ""
output[4] += ""
output[5] += ""
output[6] += ""
output[7] += ""
output[8] += ""
output[9] += ""
output[10] += ""
output[11] += "******************************* "
output[12] += ""
output[13] += "******************************* "
end

def add_row_header(output)
output[0] += ""
output[1] += ""
output[2] += ""
output[3] += sprintf("%-21s", "Beginning Age:")
output[4] += sprintf("%-21s", "Retirement Age:")
output[5] += sprintf("%-21s", "Age of Death:")
output[6] += sprintf("%-21s", "Annual Contribution:")
output[7] += sprintf("%-21s", "Market Return:")
output[8] += sprintf("%-21s", "Accum. Tax Rate:")
output[9] += sprintf("%-21s", "Retir. Tax Rate:")
output[10] += sprintf("%-21s", "Account Type:")
output[11] += ""
output[12] += sprintf("%-21s", "Retirement Income:")
output[13] += ""
end

def results_output(scenario1, scenario2)
difference = (scenario1.retirement_income - scenario2.retirement_income).abs
return "Result: both scenarios generate the same income in retirement." if difference == 0
return "Result: #{scenario1.name} generates $#{difference} more income in retirement!" if scenario1.retirement_income > scenario2.retirement_income
return "Result: #{scenario2.name} generates $#{difference} more income in retirement!" if scenario2.retirement_income > scenario1.retirement_income
end

def serialize_scenario
{}.tap do |args|
args[:name] = fetch_user_input("\nEnter the name:")
args[:beginning_age] = fetch_user_input("\nEnter beginning age:")
args[:retirement_age] = fetch_user_input("\nEnter retirement age:")
args[:death_age] = fetch_user_input("\nEnter age of death:")
args[:annual_contribution] = fetch_user_input("\nEnter annual contribution:")
args[:accumulation_market_return_rate] = fetch_user_input("\nEnter accumulation market return rate:")
args[:accumulation_tax_rate] = fetch_user_input("\nEnter accumulation tax rate:")
args[:retirement_tax_rate] = fetch_user_input("\nEnter retirement tax rate:")
args[:ira_type] = fetch_user_input("\nEnter retirement type (roth, regular):").to_sym
end
end

def fetch_user_input(question=nil)
puts question if question
print "> "
gets.chomp
end
end
end
end