diff --git a/app/models/csv_builder.rb b/app/models/csv_builder.rb new file mode 100644 index 0000000..9d830d6 --- /dev/null +++ b/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 diff --git a/app/models/csv_importer.rb b/app/models/csv_importer.rb index dfd546d..8047ae5 100644 --- a/app/models/csv_importer.rb +++ b/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 diff --git a/app/models/data_builder.rb b/app/models/data_builder.rb new file mode 100644 index 0000000..66f6ffb --- /dev/null +++ b/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 diff --git a/app/models/file_importer.rb b/app/models/file_importer.rb index 1bdc1e9..aaf01f6 100644 --- a/app/models/file_importer.rb +++ b/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 diff --git a/app/models/financial_data_formatter.rb b/app/models/financial_data_formatter.rb index a33d367..b548fc8 100644 --- a/app/models/financial_data_formatter.rb +++ b/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 diff --git a/app/models/xlsx_builder.rb b/app/models/xlsx_builder.rb new file mode 100644 index 0000000..6802680 --- /dev/null +++ b/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 diff --git a/app/models/xlsx_importer.rb b/app/models/xlsx_importer.rb index 7824fc1..c31211a 100644 --- a/app/models/xlsx_importer.rb +++ b/app/models/xlsx_importer.rb @@ -1,4 +1,11 @@ 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 @@ -6,8 +13,8 @@ def import 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 diff --git a/spec/models/csv_builder_spec.rb b/spec/models/csv_builder_spec.rb new file mode 100644 index 0000000..886b655 --- /dev/null +++ b/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 diff --git a/spec/models/data_builder_spec.rb b/spec/models/data_builder_spec.rb new file mode 100644 index 0000000..046c02d --- /dev/null +++ b/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 diff --git a/spec/models/file_importer_spec.rb b/spec/models/file_importer_spec.rb index 0aa6041..2b7d64a 100644 --- a/spec/models/file_importer_spec.rb +++ b/spec/models/file_importer_spec.rb @@ -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 diff --git a/spec/models/financial_data_formatter_spec.rb b/spec/models/financial_data_formatter_spec.rb index e920314..ad04664 100644 --- a/spec/models/financial_data_formatter_spec.rb +++ b/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 diff --git a/spec/models/xlsx_builder_spec.rb b/spec/models/xlsx_builder_spec.rb new file mode 100644 index 0000000..71a6f7a --- /dev/null +++ b/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