require 'hiccup/enumerable/schedule_enumerator' module Hiccup module Enumerable class MonthlyEnumerator < ScheduleEnumerator def self.for(schedule) if schedule.monthly_pattern.all? { |occurrence| Fixnum === occurrence } MonthlyDateEnumerator else self end end def started? !@position.nil? end protected attr_reader :year, :month, :cycle, :last_day_of_month def advance! @position += 1 next_month if @position >= cycle.length day = cycle[@position] return self.next if day > last_day_of_month Date.new(year, month, day) end def rewind! @position -= 1 prev_month if @position < 0 day = cycle[@position] return self.prev if day > last_day_of_month Date.new(year, month, day) end def first_occurrence_on_or_after(date) @year, @month = date.year, date.month get_context @position = cycle.index { |day| day >= date.day } next_month unless @position day = cycle[@position] return self.next if day > last_day_of_month Date.new(year, month, day) end def first_occurrence_on_or_before(date) @year, @month = date.year, date.month get_context @position = cycle.index { |day| day <= date.day } prev_month unless @position day = cycle[@position] return self.prev if day > last_day_of_month Date.new(year, month, day) end def occurrences_in_month(year, month) wday_of_first_of_month = Date.new(year, month, 1).wday monthly_pattern.map do |occurrence| if occurrence.is_a?(Array) ordinal, weekday = occurrence wday = Date::DAYNAMES.index(weekday) day = wday day = day + 7 if (wday < wday_of_first_of_month) day = day - wday_of_first_of_month day = day + (ordinal * 7) - 6 day else occurrence end end end def next_month @position = 0 @month += skip @year, @month = year + 1, month - 12 if month > 12 get_context end def prev_month @position = @cycle.length - 1 @month -= skip @year, @month = year - 1, month + 12 if month < 1 get_context end def get_context @last_day_of_month = [4, 6, 9, 11].member?(month) ? 30 : 31 @last_day_of_month = leap_year?(year) ? 29 : 28 if month == 2 @cycle = occurrences_in_month(year, month).sort end end end end require "hiccup/enumerable/monthly_date_enumerator"