Last active
August 29, 2015 14:27
-
-
Save Boztown/98878bf84d2559e33213 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# So, first thing: normally I'd use (or even create) some kind of framework. If we were using | |
# Rails for example we'd have functions and libraries like ActiveRecord that would make this look | |
# like nothing at all. I know whoever is reading this knows that; but I thought I'd state it. | |
require 'csv' | |
# So this is going to be main class. | |
class GrantGainsCalculator | |
@employees | |
@market_price_date | |
@market_price | |
# Contructor here. In this case I chose to have the contructor accept the data (a CSV in this case) | |
# and start parsing it right after initialization. That might not always be the right move but it's | |
# what I chose here. | |
def initialize(data) | |
@data = data | |
@employees = Array.new | |
CSV.parse(data) do |row| | |
new_employee = false | |
# First line is row count; disregard for now | |
next if row.count == 1 | |
# If there's only two columns in the row let's assume it's the last line | |
# that includes the market price, date, etc. | |
# note: given the time I would spend the extra time to make this more robust | |
if row.count == 2 | |
self.market_price_date = row[0] | |
self.market_price = row[1] | |
next | |
end | |
# Here I'm just doing some kind of custom "find_by_or_create" method. With an ORM or | |
# any type of framework this would be one line. Basically, I'm searching my @employees array | |
# by property and creating one only if nescessary. | |
unless @employees.any?{|a| a.id == row[1]} | |
employee = Employee.new(row[1]) | |
new_employee = true | |
else | |
employee = @employees.find {|s| s.id == row[1] } | |
end | |
#Ok, let's create the investment objects | |
investment = Investment.new | |
# Populate that bad boy. I'm handling data types in the class setters (this is Ruby afterall... | |
# not so strict by default) | |
investment.investment_type = row[0] | |
investment.investment_date = row[2] | |
investment.units = row[3] | |
investment.grant_price = row[4] | |
# Push that invesmtent to the employee (would likely be a DB association in real prodcution) | |
employee.investments << investment | |
# Push this guy to the @employees array if we know he's a new one | |
@employees << employee if new_employee | |
end | |
end | |
# Call this method to crunch the numbers | |
def calculate | |
# A bit of a sloppy Ruby closure scenario here. Could be more elegant. | |
output = Array.new | |
# Let's go through those employees | |
@employees.each do |employee| | |
# So here we do the calculations as described in the requirements. One again, this isn't very slick | |
# but more so my train of thought expressed in code a tight set of time. | |
row = Array.new | |
last_employee_id = nil | |
total_value = 0 | |
employee.investments.each do |investment| | |
last_employee_id = employee.id | |
grant_value = investment.units * investment.grant_price | |
market_value = investment.units * @market_price | |
diff_value = market_value - grant_value | |
total_value += diff_value | |
end | |
row[0] = last_employee_id | |
row[1] = total_value | |
output << row | |
end | |
# Quick and dirty array sort to meet the requirement of the employee order. | |
# Normally this would be done at a DB level. | |
output.sort! do |a, b| | |
a[0] <=> b[0] | |
end | |
# And let's turn that back into a CSV using some good old Ruby libraries. | |
csv_string = CSV.generate do |csv| | |
output.each do |o| | |
csv << o | |
end | |
end | |
# return the sweet results | |
csv_string | |
end | |
# Setter to handle market price data property | |
def market_price= market_price | |
@market_price = market_price.to_f | |
end | |
# Setter to handle market price date data property | |
def market_price_date= market_price_date | |
@market_price_date = Date.parse market_price_date | |
end | |
end | |
# An employee (has many investments) | |
class Employee | |
attr_accessor :id, :investments | |
@id | |
@investments | |
def initialize(id) | |
@id = id | |
@investments = Array.new | |
end | |
end | |
# An investment (belongs to an employee) | |
class Investment | |
attr_accessor :investment_type, | |
:customer_id, :investment_date, | |
:units, :grant_price | |
@investment_type | |
@customer_id | |
@investment_date | |
@units | |
@grant_price | |
def investment_date= investment_date | |
@investment_date = Date.parse investment_date | |
end | |
def units= units | |
@units = units.to_i | |
end | |
def grant_price= grant_price | |
@grant_price = grant_price.to_f | |
end | |
end | |
# read in that input | |
input = ARGF.read | |
# send it to the calculator | |
calculator = GrantGainsCalculator.new(input) | |
# run the method and spit out the results | |
puts calculator.calculate | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment