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

Introduce data builder class #14

Merged
merged 1 commit into from Apr 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/models/csv_builder.rb
@@ -0,0 +1,6 @@
class CsvBuilder < DataBuilder
def build(csv_row, user_id)
datum_as_hash = csv_row.to_h
formatter.format(datum_as_hash, user_id)
end
end
11 changes: 9 additions & 2 deletions app/models/csv_importer.rb
@@ -1,10 +1,17 @@
require "csv"

class CsvImporter < FileImporter
attr_reader :builder

def initialize(filename, user_id)
super
@builder = CsvBuilder.new
end

def import
CSV.foreach(file_path, headers: true) do |row|
formatted_datum = formatter.build_csv(row, user_id)
datum = FinancialDatum.new(formatted_datum)
raw_data = builder.build(row, user_id)
datum = FinancialDatum.new(raw_data)
datum.save
end
end
Expand Down
11 changes: 11 additions & 0 deletions app/models/data_builder.rb
@@ -0,0 +1,11 @@
class DataBuilder
attr_reader :formatter

def initialize
@formatter = FinancialDataFormatter.new
end

def build
raise "Override this method"
end
end
3 changes: 1 addition & 2 deletions app/models/file_importer.rb
@@ -1,10 +1,9 @@
class FileImporter
attr_reader :file_path, :user_id, :formatter
attr_reader :file_path, :user_id

def initialize(file_path, user_id)
@file_path = file_path
@user_id = user_id
@formatter = FinancialDataFormatter.new
end

def import
Expand Down
22 changes: 4 additions & 18 deletions app/models/financial_data_formatter.rb
@@ -1,21 +1,7 @@
class FinancialDataFormatter
def build_csv(csv_row, user_id)
datum_as_hash = csv_row.to_h
format_base_hash(datum_as_hash, user_id)
end

def build_xlsx(xlsx_row, user_id)
cells = xlsx_row.cells.map(&:value)
headers = %w[month year income expenses net_worth]
datum_as_hash = headers.zip(cells).to_h
format_base_hash(datum_as_hash, user_id)
end

private

def format_base_hash(datum_as_hash, user_id)
datum_as_hash["user_id"] = user_id
datum_as_hash["month"] = FinancialDatum::MONTHS[datum_as_hash["month"].to_i]
datum_as_hash
def format(raw_data, user_id)
raw_data[:user_id] = user_id
raw_data[:month] = FinancialDatum::MONTHS[raw_data["month"].to_i]
raw_data.symbolize_keys!
end
end
8 changes: 8 additions & 0 deletions app/models/xlsx_builder.rb
@@ -0,0 +1,8 @@
class XlsxBuilder < DataBuilder
def build(xlsx_row, user_id)
cells = xlsx_row.cells.map(&:value)
headers = %w[month year income expenses net_worth]
datum_as_hash = headers.zip(cells).to_h
formatter.format(datum_as_hash, user_id)
end
end
11 changes: 9 additions & 2 deletions app/models/xlsx_importer.rb
@@ -1,13 +1,20 @@
class XlsxImporter < FileImporter
attr_reader :builder

def initialize(filename, user_id)
super
@builder = XlsxBuilder.new
end

def import
workbook = RubyXL::Parser.parse(file_path)
worksheet = workbook.worksheets.first
worksheet.each_with_index do |row, idx|
if idx == 0
next
end
formatted_datum = formatter.build_xlsx(row, user_id)
datum = FinancialDatum.new(formatted_datum)
raw_data = builder.build(row, user_id)
datum = FinancialDatum.new(raw_data)
datum.save
end
end
Expand Down
31 changes: 31 additions & 0 deletions spec/models/csv_builder_spec.rb
@@ -0,0 +1,31 @@
require "rails_helper"
require "csv"

RSpec.describe CsvBuilder do
describe "#build" do
it "returns a hash of the data for a FinancialDatum" do
month = 1
year = 2019
expenses = 12345
income = 1000
net_worth = 999999
headers = %w[month year expenses income net_worth]
fields = [month, year, expenses, income, net_worth]
csv_row = CSV::Row.new(headers, fields)
user_id = 1
builder = CsvBuilder.new
expected_result = {
month: :february,
year: year,
expenses: expenses,
income: income,
net_worth: net_worth,
user_id: user_id,
}

result = builder.build(csv_row, user_id)

expect(result).to eq(expected_result)
end
end
end
12 changes: 12 additions & 0 deletions spec/models/data_builder_spec.rb
@@ -0,0 +1,12 @@
require "rails_helper"
require "csv"

RSpec.describe DataBuilder do
describe "#build" do
it "raises if it is called" do
builder = DataBuilder.new

expect { builder.build }.to raise_error("Override this method")
end
end
end
9 changes: 5 additions & 4 deletions spec/models/file_importer_spec.rb
Expand Up @@ -2,13 +2,14 @@

RSpec.describe FileImporter do
describe ".new" do
it "initializes with a file path and user_id and a formatter" do
filepath = "filepath"
it "initializes with a file path and user_id and a builder" do
file_path = "filepath"
user_id = 1

importer = FileImporter.new(filepath, user_id)
importer = FileImporter.new(file_path, user_id)

expect(importer.formatter).to be_an_instance_of(FinancialDataFormatter)
expect(importer.file_path).to eq(file_path)
expect(importer.user_id).to eq(user_id)
end
end
end
69 changes: 11 additions & 58 deletions spec/models/financial_data_formatter_spec.rb
@@ -1,72 +1,25 @@
require "rails_helper"
require "csv"

RSpec.describe FinancialDataFormatter do
describe "#build_csv" do
it "returns a hash of the data for a FinancialDatum" do
month = 1
year = 2019
expenses = 12345
income = 1000
net_worth = 999999
headers = %w[month year expenses income net_worth]
fields = [month, year, expenses, income, net_worth]
csv_row = CSV::Row.new(headers, fields)
user_id = 1
formatter = FinancialDataFormatter.new
expected_result = {
month: :february,
year: year,
expenses: expenses,
income: income,
net_worth: net_worth,
user_id: user_id,
describe "#format" do
it "takes a raw data hash and formats to the correct format" do
raw_data = {
month: 1, year: 2019, expenses: 10, income: 11, net_worth: 13,
}
.stringify_keys

result = formatter.build_csv(csv_row, user_id)

expect(result).to eq(expected_result)
end
end

describe "#build_xlsx" do
it "returns a hash of the data for a FinancialDatum" do
month = 1
year = 2019
expenses = 12345
income = 1000
net_worth = 999999
cell_one = build_cell(1, 0, month)
cell_two = build_cell(1, 1, year)
cell_three = build_cell(1, 2, income)
cell_four = build_cell(1, 3, expenses)
cell_five = build_cell(1, 4, net_worth)
xlsx_row = RubyXL::Row.new
xlsx_row.cells = [cell_one, cell_two, cell_three, cell_four, cell_five]
user_id = 1
formatter = FinancialDataFormatter.new
expected_result = {
month: :february,
year: year,
expenses: expenses,
income: income,
net_worth: net_worth,
user_id: user_id,
month: :january,
year: 2019,
expenses: 10,
income: 11,
net_worth: 13,
user_id: 1,
}
.stringify_keys

result = formatter.build_xlsx(xlsx_row, user_id)
result = formatter.format(raw_data, user_id)

expect(result).to eq(expected_result)
end
end

def build_cell(row, column, value)
cell = RubyXL::Cell.new
cell.row = row
cell.column = column
allow(cell).to receive(:value).and_return(value)
cell
end
end
42 changes: 42 additions & 0 deletions spec/models/xlsx_builder_spec.rb
@@ -0,0 +1,42 @@
require "rails_helper"

RSpec.describe XlsxBuilder do
describe "#build" do
it "returns a hash of the data for a FinancialDatum" do
month = 1
year = 2019
expenses = 12345
income = 1000
net_worth = 999999
cell_one = build_cell(1, 0, month)
cell_two = build_cell(1, 1, year)
cell_three = build_cell(1, 2, income)
cell_four = build_cell(1, 3, expenses)
cell_five = build_cell(1, 4, net_worth)
xlsx_row = RubyXL::Row.new
xlsx_row.cells = [cell_one, cell_two, cell_three, cell_four, cell_five]
user_id = 1
builder = XlsxBuilder.new
expected_result = {
month: :february,
year: year,
expenses: expenses,
income: income,
net_worth: net_worth,
user_id: user_id,
}

result = builder.build(xlsx_row, user_id)

expect(result).to eq(expected_result)
end
end

def build_cell(row, column, value)
cell = RubyXL::Cell.new
cell.row = row
cell.column = column
allow(cell).to receive(:value).and_return(value)
cell
end
end