Skip to content

Commit

Permalink
refactor: timing calculations into own class
Browse files Browse the repository at this point in the history
  • Loading branch information
weedySeaDragon committed Aug 15, 2019
1 parent fc82c8c commit a93dd69
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 0 deletions.
54 changes: 54 additions & 0 deletions app/services/timing_calculator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#--------------------------
#
# @class ConditionScheduleCalculator
#
# @desc Responsibility: calculates time between two dates, giving a :timing_direction:
# The :timing_direction is whether we are calculating the number of days
# _before_, _after_, or _on_ this day, starting from today.
#
# @author Ashley Engelund (ashley.engelund@gmail.com weedySeaDragon @ github)
# @date 2019-08-14
#
#--------------------------
#
class TimingCalculator


# Determine the number of days today is _away_from_ this date.
#
# @param this_date [Date] - the date to compare to today
# @param timing_direction [Symbol] - which 'direction' (before, after, on) to compare to today
# @return [Integer] - the number of days away from today, based on our :timing_direction
def self.days_today_is_away_from(this_date, timing_direction)
days_1st_date_is_from_2nd(Date.current, this_date, timing_direction)
end


# Determine the number of days :a_date is _away_from_ :second_date.
# The :timing_direction is whether we are calculating the number of days
# _before_, _after_, or _on_ this day, starting from :a_date.
#
# @param a_date [Date] - the starting date
# @param second_date [Date] - the date to compare to :a_date
# @param timing_direction [Symbol] - which 'direction' (before, after, on) to compare to :a_date
# @return [Integer] - the number of days separating the two dates, based on the :timing_direction
def self.days_1st_date_is_from_2nd(a_date, second_date, timing_direction)

day_num_to_check = 0 # default value

# We use .to_date to ensure that we're comparing and working with Dates, not Times, etc.
# If calling .to_date throws an exception, that's an exception that should be raised.

if timing_direction == ConditionSchedule.timing_before
# number of days that a_date is _before_ second_date
day_num_to_check = second_date.to_date - a_date.to_date

elsif timing_direction == ConditionSchedule.timing_after
# number of days that a_date is _after_ second_date
day_num_to_check = a_date.to_date - second_date.to_date
end

day_num_to_check.to_i
end

end
28 changes: 28 additions & 0 deletions spec/factories/condition_schedules.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FactoryBot.define do

factory :condition_schedule do
timing { :on }
end


trait :after do
timing { :after }
end

trait :before do
timing { :before }
end

trait :on do
timing { :on }
end

trait :every_day do
timing { :every_day }
end

trait :monthly do
timing { :on_month_day }
end

end
130 changes: 130 additions & 0 deletions spec/services/timing_calculator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
require 'rails_helper'

RSpec.describe TimingCalculator do


let(:timing_before) { ConditionSchedule.timing_before }
let(:timing_after) { ConditionSchedule.timing_after }
let(:timing_on) { ConditionSchedule.timing_on }


let(:nov_30) { Date.new(2018, 11, 30) }
let(:dec_1) { Date.new(2018, 12, 1) }
let(:dec_2) { Date.new(2018, 12, 2) }


around(:each) do |example|
Timecop.freeze(dec_1)
example.run
Timecop.return
end


describe '.days_a_date_is_away_from is the number of days today is _away_from_ this date.' do

describe 'timing_direction is before' do

it '1st is 1 day before 2nd date = 1' do
expect(described_class.days_1st_date_is_from_2nd(nov_30, dec_1, timing_before)).to eq 1
end

it '1st = 2nd date == 0' do
expect(described_class.days_1st_date_is_from_2nd(dec_1, dec_1, timing_before)).to eq 0
end

it '1st date is 1 day after 2nd date = -1' do
expect(described_class.days_1st_date_is_from_2nd(dec_2, dec_1, timing_before)).to eq -1
end

end

context 'timing_direction is after' do

it '1st is 1 day before 2nd date = -1' do
expect(described_class.days_1st_date_is_from_2nd(nov_30, dec_1, timing_after)).to eq -1
end

it '1st = 2nd date == 0' do
expect(described_class.days_1st_date_is_from_2nd(dec_1, dec_1, timing_after)).to eq 0
end

it '1st date is 1 day after 2nd date = 1' do
expect(described_class.days_1st_date_is_from_2nd(dec_2, dec_1, timing_after)).to eq 1
end

end


context 'timing_direction is on (always returns 0 days away; this means always check on the 2nd date no matter how many days away)' do

it '2nd date is 1 day before the date = 0' do
expect(described_class.days_1st_date_is_from_2nd(dec_1, nov_30, timing_on)).to eq 0
end

it '2nd date is == the date = 0' do
expect(described_class.days_1st_date_is_from_2nd(dec_1, dec_1, timing_on)).to eq 0
end

it '2nd date is 1 day after the date = 0' do
expect(described_class.days_1st_date_is_from_2nd(dec_1, dec_2, timing_on)).to eq 0
end

end

end


describe '.days_today_is_away_from(timing, some_date)' do

context 'timing_direction is before' do

it 'today is 1 day before the date = described_class.days_1st_date_is_from_2nd(Date.current, nov_30, timing_before)' do
expect(described_class.days_today_is_away_from(nov_30, timing_before)).to eq described_class.days_1st_date_is_from_2nd(dec_1, nov_30, timing_before)
end

it 'today = the date = described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_before)' do
expect(described_class.days_today_is_away_from(dec_1, timing_before)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_before)
end

it 'today is 1 day after the date = described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_before)' do
expect(described_class.days_today_is_away_from(dec_2, timing_before)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_before)
end

end

context 'timing_direction is after' do

it 'today is 1 day after the date = described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_after)' do
expect(described_class.days_today_is_away_from(dec_2, timing_after)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_after)
end

it 'date is on today = described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_after)' do
expect(described_class.days_today_is_away_from(dec_1, timing_after)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_after)
end

it 'today is 1 day before the date = described_class.days_1st_date_is_from_2nd(Date.current, nov_30, timing_after)' do
expect(described_class.days_today_is_away_from(nov_30, timing_after)).to eq described_class.days_1st_date_is_from_2nd(Date.current, nov_30, timing_after)
end

end


context 'timing_direction is on (always returns 0 days away; this means always check on today)' do

it 'date is 1 day before today = described_class.days_1st_date_is_from_2nd(Date.current, nov_30, timing_on)' do
expect(described_class.days_today_is_away_from(nov_30, timing_on)).to eq described_class.days_1st_date_is_from_2nd(Date.current, nov_30, timing_on)
end

it 'date is on today = described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_on)' do
expect(described_class.days_today_is_away_from(dec_1, timing_on)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_1, timing_on)
end

it 'date is 1 day after today = described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_on)' do
expect(described_class.days_today_is_away_from(dec_2, timing_on)).to eq described_class.days_1st_date_is_from_2nd(Date.current, dec_2, timing_on)
end

end

end

end

0 comments on commit a93dd69

Please sign in to comment.