Skip to content

Commit

Permalink
Merge pull request #15 from schwern/issue/#14
Browse files Browse the repository at this point in the history
Remove core extensions, add `until`.
  • Loading branch information
schwern committed Dec 17, 2023
2 parents 5cda4b4 + ec252ff commit 9a32aa1
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 209 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ Style/AccessModifierDeclarations:
Style/AsciiComments:
Enabled: false

Style/BlockDelimiters:
EnforcedStyle: "braces_for_chaining"

Style/FrozenStringLiteralComment:
Enabled: false

Expand Down
41 changes: 20 additions & 21 deletions lib/time_iterator.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
require "active_support"
require "active_support/core_ext/integer/time"
require_relative "time_iterator/core_ext/numeric"
require_relative "time_iterator/core_ext/time"
require "active_support/duration"

# Time iteration.
module TimeIterator
INFINITY = 1.0 / 0.0
PERIODS = {
second: :seconds,
minute: :minutes,
hour: :hours,
day: :days,
week: :weeks,
month: :months,
quarter: :quarters,
year: :years
}.freeze
ITERATE_BY = (PERIODS.keys + PERIODS.values).freeze

class << self
def iterate(start, by:, every: 1)
by = by.to_sym
def iterate(start, by:, to: nil)
raise ArgumentError, "`by` must be an ActiveSupport::Duration" unless by.is_a?(ActiveSupport::Duration)

return to ? iterate_to(start, by: by, to: to) : iterate_endless(start, by: by)
end

raise ArgumentError, "Unknown period to iterate by: #{by}" unless ITERATE_BY.include?(by)
private def iterate_endless(start, by:)
Enumerator.new do |block|
time = start
loop do
block << time
time += by
end
end
end

private def iterate_to(start, by:, to:)
Enumerator.new do |block|
(0..INFINITY).each do |num|
block << (start + (num.send(by) * every))
time = start
while time <= to
block << time
time += by
end
end
end
Expand Down
7 changes: 0 additions & 7 deletions lib/time_iterator/core_ext/numeric.rb

This file was deleted.

48 changes: 0 additions & 48 deletions lib/time_iterator/core_ext/time.rb

This file was deleted.

13 changes: 0 additions & 13 deletions spec/time_iterator/core_ext/numeric_spec.rb

This file was deleted.

102 changes: 0 additions & 102 deletions spec/time_iterator/core_ext/time_spec.rb

This file was deleted.

63 changes: 45 additions & 18 deletions spec/time_iterator_spec.rb
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
RSpec.describe TimeIterator do
let(:time) { Time.now }
let(:time) { Time.gm(2000, 1, 1, 0, 0, 0) }

describe '.iterate' do
it 'uses an Enumerator' do
expect( described_class.iterate(time, by: :day) ).to be_a(Enumerator)
expect(
described_class.iterate(time, by: ActiveSupport::Duration.days(1))
).to be_a(Enumerator)
end

it 'raises on an invalid period' do
expect do
it 'raises on an invalid `by`' do
expect {
described_class.iterate(time, by: :colors)
end.to raise_error(ArgumentError)
}.to raise_error(ArgumentError)
end

[
:second, :minute, :hour, :day, :week, :month, :quarter, :year,
:seconds, :minutes, :hours, :days, :weeks, :months, :quarter, :years
].each do |period|
it "iterates by #{period}" do
expect(
described_class.iterate(time, by: period).take(3)
).to eq [time, time + 1.send(period), time + 2.send(period)]
end
it "iterates" do
expect(
described_class.iterate(
Time.gm(2000, 1, 1), by: ActiveSupport::Duration.days(3)
).take(3)
).to eq [
Time.gm(2000, 1, 1),
Time.gm(2000, 1, 4),
Time.gm(2000, 1, 7)
]
end

it "stops before `to`" do
expect(
described_class.iterate(
Time.gm(2000, 1, 1),
by: ActiveSupport::Duration.days(3),
to: Time.gm(2000, 1, 12)
).to_a
).to eq [
Time.gm(2000, 1, 1),
Time.gm(2000, 1, 4),
Time.gm(2000, 1, 7),
Time.gm(2000, 1, 10)
]
end

it 'iterates every X periods' do
it "includes `to`" do
expect(
described_class.iterate(time, by: :day, every: 3).take(3)
).to eq [time, time + 3.days, time + 6.days]
described_class.iterate(
Time.gm(2000, 1, 1),
by: ActiveSupport::Duration.days(3),
to: Time.gm(2000, 1, 10)
).to_a
).to eq [
Time.gm(2000, 1, 1),
Time.gm(2000, 1, 4),
Time.gm(2000, 1, 7),
Time.gm(2000, 1, 10)
]
end

it 'does not alter the original time' do
orig = time.clone
described_class.iterate(time, by: :day).take(5)
described_class.iterate(time, by: ActiveSupport::Duration.weeks(2)).take(5)
expect( time ).to eq orig
end
end
Expand Down

0 comments on commit 9a32aa1

Please sign in to comment.