Skip to content

Instantly share code, notes, and snippets.

@Boztown
Last active August 29, 2015 14:27
Show Gist options
  • Save Boztown/98878bf84d2559e33213 to your computer and use it in GitHub Desktop.
Save Boztown/98878bf84d2559e33213 to your computer and use it in GitHub Desktop.
#!/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