Skip to content

Instantly share code, notes, and snippets.

@gareth
Created January 3, 2012 05:29
Show Gist options
  • Save gareth/1553656 to your computer and use it in GitHub Desktop.
Save gareth/1553656 to your computer and use it in GitHub Desktop.
BH IMPORT
source :rubygems
GEM
remote: http://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
require 'csv'
require 'json'
require 'pp'
SOLUTIONS_FILENAME = "solutions.csv"
CALCULATIONS_FILENAME = "calculations.csv"
SOLUTIONS_DATA_ATTRIBUTES = [:solution_id, :name, :type]
SOLUTIONS_PRODUCT_ATTRIBUTES = [:product_name, :provider_factsheet_url, :product_allocation, :fund_name, :fund_factsheet_url, :fund_charge, :cash_asset_allocation, :gilts_asset_allocation, :bonds_asset_allocation, :uk_equity_asset_allocation, :os_equity_asset_allocation]
SOLUTIONS_CSV_ATTRIBUTES = SOLUTIONS_DATA_ATTRIBUTES + SOLUTIONS_PRODUCT_ATTRIBUTES
CALCULATIONS_DATA_ATTRIBUTES = [:ris, :residual_fund_value, :income_guarantee, :income_lower_limit, :income_upper_limit]
CALCULATIONS_CSV_ATTRIBUTES = [:solution_id, :output_age, :annual_withdrawal_amount] + CALCULATIONS_DATA_ATTRIBUTES
class Solution < Struct.new(*SOLUTIONS_DATA_ATTRIBUTES)
attr_reader :products, :calculations
def initialize *args
super
@products = []
@calculations = {}
end
def to_hash
{
attributes: Hash[each_pair.to_a],
products: products.map(&:to_hash),
data: calculations
}
end
def to_json *args
to_hash.to_json *args
end
end
class Product < Struct.new(*SOLUTIONS_PRODUCT_ATTRIBUTES)
def to_hash
Hash[each_pair.to_a]
end
end
def data_ratio str
str = str.to_s.strip # Normalize input
num = if str =~ /%$/
# Percentage
(Float(str.gsub(/%$/, '')) / 100).round(7)
else
# Straight ratio
Float(str).round(7)
end
rescue
str unless str.to_s.empty?
end
# Initialize interim variables
solutions = {}
solutions_data = {}
SOLUTIONS_CSV_ATTRIBUTES.each { |att| solutions_data[att] = nil }
###################
# SOLUTIONS LOADING
###################
solutions_table = CSV.read(SOLUTIONS_FILENAME, headers: true, header_converters: :symbol)
solutions_table.each do |row|
remember_values = true
SOLUTIONS_CSV_ATTRIBUTES.zip(row.fields).each do |att, value|
remember_values = false unless value.nil?
solutions_data[att] = nil unless remember_values
solutions_data[att] = value if value
end
unless solution = solutions[solutions_data[:solution_id]]
solution = solutions[solutions_data[:solution_id]] = Solution.new(*row.fields(*SOLUTIONS_DATA_ATTRIBUTES))
puts "Adding solution: #{solution.to_hash}"
end
product_data = solutions_data.values_at(*SOLUTIONS_PRODUCT_ATTRIBUTES).map { |i| data_ratio(i) }
product = Product.new(*product_data)
puts " adding product: #{product.to_hash}"
solution.products << product
end
######################
# CALCULATIONS LOADING
######################
data = {}
CALCULATIONS_CSV_ATTRIBUTES.each { |att| data[att] = nil }
calculations_table = CSV.read(CALCULATIONS_FILENAME, headers: true, header_converters: lambda { |h| h.downcase.tr(" ", "_").delete("^a-z0-9_").chomp("_").to_sym })
calculations_table.each do |row|
remember_values = true
CALCULATIONS_CSV_ATTRIBUTES.zip(row.fields).each do |att, value|
remember_values = false unless value.nil?
data[att] = nil unless remember_values
data[att] = value if value
end
unless solution = solutions[data[:solution_id]]
raise "Unable to find solution #{data[:solution_id]} for calculations"
end
annual_withdrawal_amount = data_ratio data[:annual_withdrawal_amount]
data_values = data.values_at(*CALCULATIONS_DATA_ATTRIBUTES).map { |i| data_ratio(i).round(7) }
solution.calculations[data[:output_age]] ||= {}
solution.calculations[data[:output_age]][annual_withdrawal_amount] = Hash[CALCULATIONS_DATA_ATTRIBUTES.zip(data_values)]
end
File.open("data.js", "w") do |f|
str = "var data = #{JSON.pretty_generate(solutions)}"
f << str
end
# pp solutions.map { |k, s| s.to_hash }
# puts JSON.pretty_generate(solutions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment