diff --git a/lib/aspire_budget.rb b/lib/aspire_budget.rb index 76b6c85..8b539c5 100644 --- a/lib/aspire_budget.rb +++ b/lib/aspire_budget.rb @@ -7,6 +7,7 @@ require 'worksheets/backend_data' require 'worksheets/transactions' require 'worksheets/category_transfers' +require 'worksheets/dashboard' require 'models/transaction' require 'models/category_transfer' diff --git a/lib/worksheets/backend_data.rb b/lib/worksheets/backend_data.rb index d2bb7e0..c0bf653 100644 --- a/lib/worksheets/backend_data.rb +++ b/lib/worksheets/backend_data.rb @@ -9,8 +9,10 @@ class BackendData < WorksheetBase # @return [String] the spreadsheet version def version - version_column = ws.rows[0].index { |header| header.match?(/Update/) } - ws.rows[1][version_column] + @version ||= begin + version_column = ws.rows[0].index { |header| header.match?(/Update/) } + ws.rows[1][version_column] + end end end end diff --git a/lib/worksheets/dashboard.rb b/lib/worksheets/dashboard.rb new file mode 100644 index 0000000..122c13d --- /dev/null +++ b/lib/worksheets/dashboard.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'worksheets/worksheet_base' + +module AspireBudget + module Worksheets + class Dashboard < WorksheetBase + WS_TITLE = 'Dashboard' + + CELL_MAP_3_2_0 = { + available_to_budget: 'H2', + spent_this_month: 'I2', + budgeted_this_month: 'K2', + pending_transactions: 'O2' + }.freeze + + CELL_MAP_3_1_0 = { + available_to_budget: 'C5', + spent_this_month: 'C6', + pending_transactions: 'C7' + }.freeze + + IMMEDIATE_METHODS = (CELL_MAP_3_2_0.keys | CELL_MAP_3_1_0.keys) + + private_constant :IMMEDIATE_METHODS + + IMMEDIATE_METHODS.each do |data_name| + define_method data_name do + cell = cell_map[data_name] || raise("#{data_name} is not supported on #{spreadsheet_version}") + ws.numeric_value(cell) + end + end + + private + + def cell_map + case spreadsheet_version + when '3.2.0' then CELL_MAP_3_2_0 + when '3.1.0' then CELL_MAP_3_1_0 + else raise "version #{version} not supported" + end + end + + def ws_title + 'Dashboard' + end + end + end +end diff --git a/lib/worksheets/worksheet_base.rb b/lib/worksheets/worksheet_base.rb index 46facf4..a74510a 100644 --- a/lib/worksheets/worksheet_base.rb +++ b/lib/worksheets/worksheet_base.rb @@ -30,12 +30,16 @@ def respond_to_missing?(method_name, include_private = false) end end - # @see AspireBudget::Configuration#agent - # @return a new instance of the calling class configured with an agent + # Initializes the worksheet. To use the spreadsheet default + # +session+ / +spreadsheet_key+, just initialize without arguments. # @param session [GoogleDrive::Session] # @param spreadsheet_key [String] spreadsheet key as per its url - def initialize(session: nil, spreadsheet_key: nil) - @agent = AspireBudget.configuration.agent(session, spreadsheet_key) + # @param agent [GoogleDrive::Spreadsheet] an spreadsheet agent + # (used internally only) + def initialize(session: nil, spreadsheet_key: nil, agent: nil) + @agent = agent + @session = session + @spreadsheet_key = spreadsheet_key end # @return [Boolean] Whether the worksheet has unsaved changes @@ -43,6 +47,13 @@ def dirty? ws.dirty? end + # @return [String] the spreadsheet version + # @see AspireBudget::Worksheets::BackendData#version + def spreadsheet_version + @backend_data ||= BackendData.new(agent: agent) + @backend_data.version + end + private def ws @@ -51,7 +62,11 @@ def ws def worksheets @worksheets ||= - @agent.worksheets.reduce({}) { |h, sheet| h.merge(sheet.title => sheet) } + agent.worksheets.reduce({}) { |h, sheet| h.merge(sheet.title => sheet) } + end + + def agent + @agent ||= AspireBudget.configuration.agent(@session, @spreadsheet_key) end end end diff --git a/spec/fixtures/v3-1-0/dashboard_properties.json b/spec/fixtures/v3-1-0/dashboard_properties.json new file mode 100644 index 0000000..5d07b55 --- /dev/null +++ b/spec/fixtures/v3-1-0/dashboard_properties.json @@ -0,0 +1,7 @@ +{ + "currency": [ + [5, 3], + [6, 3], + [7, 3] + ] +} diff --git a/spec/fixtures/v3-2-0/dashboard_properties.json b/spec/fixtures/v3-2-0/dashboard_properties.json new file mode 100644 index 0000000..64a7071 --- /dev/null +++ b/spec/fixtures/v3-2-0/dashboard_properties.json @@ -0,0 +1,8 @@ +{ + "currency": [ + [2, 8], + [2, 9], + [2, 11], + [2, 15] + ] +} diff --git a/spec/worksheets/dashboard_spec.rb b/spec/worksheets/dashboard_spec.rb new file mode 100644 index 0000000..7815eaa --- /dev/null +++ b/spec/worksheets/dashboard_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +RSpec.describe AspireBudget::Worksheets::Dashboard do + context 'when on 3.2.0' do + describe 'immediate methods' do + before { use_spreadsheet_version 'v3-2-0' } + + it 'returns the expected values' do + expect(subject.available_to_budget).to eq 11_505.0 + expect(subject.spent_this_month).to eq 0.0 + expect(subject.budgeted_this_month).to eq 0.0 + expect(subject.pending_transactions).to eq 0.0 + end + end + end + + context 'when on 3.1.0' do + describe 'immediate methods' do + before { use_spreadsheet_version 'v3-1-0' } + + it 'returns the expected values' do + expect(subject.available_to_budget).to eq(-495.00) # TODO: fix inconsistency + expect(subject.spent_this_month).to eq 0.0 + expect(subject.pending_transactions).to eq 0.0 + end + + it 'raises on unavailable methods' do + expect { subject.budgeted_this_month }.to raise_error 'budgeted_this_month is not supported on 3.1.0' + end + end + end +end diff --git a/spec/worksheets/worksheet_base_spec.rb b/spec/worksheets/worksheet_base_spec.rb index 75bb4fd..1ac880f 100644 --- a/spec/worksheets/worksheet_base_spec.rb +++ b/spec/worksheets/worksheet_base_spec.rb @@ -31,21 +31,18 @@ def all end end - describe '.initialize' do - context 'when without arguments' do - it 'configures an agent without a session/key' do - allow(AspireBudget.configuration).to receive(:agent) - subject.new - expect(AspireBudget.configuration).to have_received(:agent).once.with(nil, nil) - end + describe '#spreadsheet_version' do + before do + backend_data = double + allow(AspireBudget::Worksheets::BackendData) + .to receive(:new) + .with(agent: an_instance_of(GoogleDrive::Spreadsheet)) + .and_return(backend_data) + allow(backend_data).to receive(:version).and_return('0.0.0') end - context 'when specifiying session and spreadsheet_key' do - it 'configures an agent with the specified arguments' do - allow(AspireBudget.configuration).to receive(:agent) - subject.new(session: 'foo', spreadsheet_key: 'bar') - expect(AspireBudget.configuration).to have_received(:agent).once.with('foo', 'bar') - end + it 'initializes the backenddata spreadsheet and calls #version on it' do + expect(subject.spreadsheet_version).to eq '0.0.0' end end end