Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/rrule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ module RRule
autoload :Humanizer, 'rrule/humanizer'

autoload :Frequency, 'rrule/frequencies/frequency'
autoload :Secondly, 'rrule/frequencies/secondly'
autoload :Minutely, 'rrule/frequencies/minutely'
autoload :Hourly, 'rrule/frequencies/hourly'
autoload :Daily, 'rrule/frequencies/daily'
autoload :Weekly, 'rrule/frequencies/weekly'
autoload :SimpleWeekly, 'rrule/frequencies/simple_weekly'
Expand Down
6 changes: 6 additions & 0 deletions lib/rrule/frequencies/frequency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ def next_occurrences

def self.for_options(options)
case options[:freq]
when 'SECONDLY'
Secondly
when 'MINUTELY'
Minutely
when 'HOURLY'
Hourly
when 'DAILY'
Daily
when 'WEEKLY'
Expand Down
19 changes: 19 additions & 0 deletions lib/rrule/frequencies/hourly.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module RRule
class Hourly < Frequency
def possible_days
[current_date.yday - 1] # convert to 0-indexed
end

def timeset
super.map { |time| time.merge(hour: current_date.hour) }
end

private

def advance_by
{ hours: context.options[:interval] }
end
end
end
19 changes: 19 additions & 0 deletions lib/rrule/frequencies/minutely.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module RRule
class Minutely < Frequency
def possible_days
[current_date.yday - 1] # convert to 0-indexed
end

def timeset
super.map { |time| time.merge(hour: current_date.hour, minute: current_date.min) }
end

private

def advance_by
{ minutes: context.options[:interval] }
end
end
end
19 changes: 19 additions & 0 deletions lib/rrule/frequencies/secondly.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module RRule
class Secondly < Frequency
def possible_days
[current_date.yday - 1] # convert to 0-indexed
end

def timeset
super.map { |time| time.merge(hour: current_date.hour, minute: current_date.min, second: current_date.sec) }
end

private

def advance_by
{ seconds: context.options[:interval] }
end
end
end
2 changes: 1 addition & 1 deletion lib/rrule/rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def parse_options(rule)
# when the associated "DTSTART" property has a DATE value type.
# These rule parts MUST be ignored in RECUR value that violate the
# above requirement
options[:timeset] = [{ hour: (options[:byhour].presence || dtstart.hour), minute: (options[:byminute].presence || dtstart.min), second: (options[:bysecond].presence || dtstart.sec) }] unless dtstart.is_a?(Date)
options[:timeset] = [{ hour: options[:byhour].presence || dtstart.hour, minute: options[:byminute].presence || dtstart.min, second: options[:bysecond].presence || dtstart.sec }] unless dtstart.is_a?(Date)

options
end
Expand Down
54 changes: 54 additions & 0 deletions spec/frequencies/hourly_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

require 'spec_helper'

describe RRule::Hourly do
let(:interval) { 1 }
let(:context) do
RRule::Context.new(
{ interval: interval },
date,
'America/Los_Angeles'
)
end
let(:filters) { [] }
let(:generator) { RRule::AllOccurrences.new(context) }
let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }

before { context.rebuild(date.year, date.month) }

describe '#next_occurrences' do
subject(:frequency) { described_class.new(context, filters, generator, timeset) }

context 'with an interval of one' do
let(:date) { Time.zone.local(1997, 1, 1, 0, 0) }

it 'returns sequential hours' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 1, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 2, 0)]
end
end

context 'with an interval of two' do
let(:interval) { 2 }
let(:date) { Time.zone.local(1997, 1, 1, 0, 0) }

it 'returns every other hour' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 2, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 4, 0)]
end
end

context 'at the end of the day' do
let(:date) { Time.zone.local(1997, 1, 1, 23, 0) }

it 'goes into the next day' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 23, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 2, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 2, 1, 0)]
end
end
end
end
54 changes: 54 additions & 0 deletions spec/frequencies/minutely_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

require 'spec_helper'

describe RRule::Minutely do
let(:interval) { 1 }
let(:context) do
RRule::Context.new(
{ interval: interval },
date,
'America/Los_Angeles'
)
end
let(:filters) { [] }
let(:generator) { RRule::AllOccurrences.new(context) }
let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }

before { context.rebuild(date.year, date.month) }

describe '#next_occurrences' do
subject(:frequency) { described_class.new(context, filters, generator, timeset) }

context 'with an interval of one' do
let(:date) { Time.zone.local(1997, 1, 1, 0, 0) }

it 'returns sequential minutes' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 1)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 2)]
end
end

context 'with an interval of two' do
let(:interval) { 2 }
let(:date) { Time.zone.local(1997, 1, 1, 0, 0) }

it 'returns every other minute' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 2)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 4)]
end
end

context 'at the end of the hour' do
let(:date) { Time.zone.local(1997, 1, 1, 0, 59) }

it 'goes into the next hour' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 59)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 1, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 1, 1)]
end
end
end
end
54 changes: 54 additions & 0 deletions spec/frequencies/secondly_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

require 'spec_helper'

describe RRule::Secondly do
let(:interval) { 1 }
let(:context) do
RRule::Context.new(
{ interval: interval },
date,
'America/Los_Angeles'
)
end
let(:filters) { [] }
let(:generator) { RRule::AllOccurrences.new(context) }
let(:timeset) { [{ hour: date.hour, minute: date.min, second: date.sec }] }

before { context.rebuild(date.year, date.month) }

describe '#next_occurrences' do
subject(:frequency) { described_class.new(context, filters, generator, timeset) }

context 'with an interval of one' do
let(:date) { Time.zone.local(1997, 1, 1, 0, 0, 0) }

it 'returns sequential seconds' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 1)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 2)]
end
end

context 'with an interval of two' do
let(:interval) { 2 }
let(:date) { Time.zone.local(1997, 1, 1, 0, 0, 0) }

it 'returns every other second' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 2)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 4)]
end
end

context 'at the end of the minute' do
let(:date) { Time.zone.local(1997, 1, 1, 0, 0, 59) }

it 'goes into the next minute' do
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 0, 59)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 1, 0)]
expect(frequency.next_occurrences).to eql [Time.zone.local(1997, 1, 1, 0, 1, 1)]
end
end
end
end
Loading