Skip to content

Commit

Permalink
Merge pull request #61 from zendesk/craig/zero-calculation
Browse files Browse the repository at this point in the history
Support zero scalar for-duration calculations
  • Loading branch information
craiglittle committed Apr 12, 2016
2 parents 7c43f3b + 324fe55 commit 9775661
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 8 deletions.
25 changes: 21 additions & 4 deletions lib/biz/calculation/for_duration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,40 @@ def unit
self.class.unit
end

def moment_before(time)
schedule.periods.before(time).first.end_time
end

def moment_after(time)
schedule.periods.after(time).first.start_time
end

[
*%i[second seconds minute minutes hour hours].map { |unit|
const_set(
unit.to_s.capitalize,
Class.new(self) do
def before(time)
timeline(:before, time).last.start_time
return moment_before(time) if scalar.zero?

advanced_periods(:before, time).last.start_time
end

def after(time)
timeline(:after, time).last.end_time
return moment_after(time) if scalar.zero?

advanced_periods(:after, time).last.end_time
end

private

def timeline(direction, time)
def advanced_periods(direction, time)
schedule
.periods
.public_send(direction, time)
.timeline
.for(Duration.public_send(unit, scalar)).to_a
.for(Duration.public_send(unit, scalar))
.to_a
end
end
)
Expand All @@ -68,10 +81,14 @@ def timeline(direction, time)
unit.to_s.capitalize,
Class.new(self) do
def before(time)
return moment_before(time) if scalar.zero?

periods(:before, time).first.end_time
end

def after(time)
return moment_after(time) if scalar.zero?

periods(:after, time).first.start_time
end

Expand Down
88 changes: 84 additions & 4 deletions spec/calculation/for_duration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,25 @@

%i[second seconds].each do |unit|
describe ".#{unit}" do
subject(:calculation) { described_class.send(unit, schedule, 90) }
let(:scalar) { 90 }

subject(:calculation) { described_class.send(unit, schedule, scalar) }

describe '#before' do
let(:time) { Time.utc(2006, 1, 4, 16, 1, 30) }

it 'returns the backward time after the elapsed duration' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 4, 16)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment backward in time' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 2, 17)
end
end
end

describe '#after' do
Expand All @@ -89,20 +100,40 @@
it 'returns the forward time after the elapsed duration' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 4, 16)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment forward in time' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 3, 10)
end
end
end
end
end

%i[minute minutes].each do |unit|
describe ".#{unit}" do
subject(:calculation) { described_class.send(unit, schedule, 90) }
let(:scalar) { 90 }

subject(:calculation) { described_class.send(unit, schedule, scalar) }

describe '#before' do
let(:time) { Time.utc(2006, 1, 4, 16, 30) }

it 'returns the backward time after the elapsed duration' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 4, 15)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment backward in time' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 2, 17)
end
end
end

describe '#after' do
Expand All @@ -111,20 +142,40 @@
it 'returns the forward time after the elapsed duration' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 4, 17)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment forward in time' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 3, 10)
end
end
end
end
end

%i[hour hours].each do |unit|
describe ".#{unit}" do
subject(:calculation) { described_class.send(unit, schedule, 3) }
let(:scalar) { 3 }

subject(:calculation) { described_class.send(unit, schedule, scalar) }

describe '#before' do
let(:time) { Time.utc(2006, 1, 4, 17) }

it 'returns the backward time after the elapsed duration' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 4, 14)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment backward in time' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 2, 17)
end
end
end

describe '#after' do
Expand All @@ -133,13 +184,24 @@
it 'returns the forward time after the elapsed duration' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 4, 17)
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 3) }

it 'returns the first active moment forward in time' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 3, 10)
end
end
end
end
end

%i[day days].each do |unit|
describe ".#{unit}" do
subject(:calculation) { described_class.send(unit, schedule, 2) }
let(:scalar) { 2 }

subject(:calculation) { described_class.send(unit, schedule, scalar) }

describe '#before' do
context 'when the advanced time is within a period' do
Expand Down Expand Up @@ -175,6 +237,15 @@
)
end
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 2, 14) }

it 'returns the first active moment backward in time' do
expect(calculation.before(time)).to eq Time.utc(2006, 1, 2, 14)
end
end
end

describe '#after' do
Expand Down Expand Up @@ -211,6 +282,15 @@
)
end
end

context 'when the scalar is zero' do
let(:scalar) { 0 }
let(:time) { Time.utc(2006, 1, 2, 13) }

it 'returns the first active moment forward in time' do
expect(calculation.after(time)).to eq Time.utc(2006, 1, 2, 13)
end
end
end
end
end
Expand Down

0 comments on commit 9775661

Please sign in to comment.