class Pagy::Calendar
Paginate a Time period by units (year, month, week or day)
def bump_month(time, months = 1)
def bump_month(time, months = 1) months += months(time) year = months / 12 month = months % 12 month.zero? ? new_time(year - 1, 12) : new_time(year, month) end
def current_page_label(format = nil)
def current_page_label(format = nil) page_label(@page, format) end
def initialize(vars) # rubocop:disable Lint/MissingSuper
Merge and validate the options, do some simple arithmetic and set a few instance variables
def initialize(vars) # rubocop:disable Lint/MissingSuper normalize_vars(vars) setup_vars(page: 1, week_offset: 0) setup_unit_vars raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last @prev = (@page - 1 unless @page == 1) @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1 end
def months(time)
def months(time) (time.year * 12) + time.month end
def new_time(year, month = 1, day = 1)
def new_time(year, month = 1, day = 1) Time.new(year, month, day, 0, 0, 0, @utc_offset) end
def page_label(num = @page, format = nil)
def page_label(num = @page, format = nil) snap = snap(num.to_i) format ||= @vars[:"#{@unit}_format"] case @unit when :year then new_time(@initial.year + snap) when :month then bump_month(@initial, snap) when :week then @initial + (snap * WEEK) when :day then @initial + (snap * DAY) else raise InternalError, "expected @unit to be in [:year, :month, :week, :day]; got #{@unit.inspect}" end.strftime(format) end
def setup_day_vars(min, max)
def setup_day_vars(min, max) @initial = new_time(min.year, min.month, min.day) @final = new_time(max.year, max.month, max.day) + DAY @pages = @last = (@final - @initial).to_i / DAY @utc_from = (@initial + (snap * DAY)).utc @utc_to = @utc_from + DAY end
def setup_month_vars(min, max)
def setup_month_vars(min, max) @initial = new_time(min.year, min.month) @final = bump_month(max) @pages = @last = months(@final) - months(@initial) @utc_from = bump_month(@initial, snap).utc @utc_to = bump_month(@initial, snap + 1).utc end
def setup_unit_vars
def setup_unit_vars (units = %i[year month week day]).each do |unit| raise VariableError.new(self, :format, 'to be a strftime format', @vars[:"#{unit}_format"]) \ unless @vars[:"#{unit}_format"].is_a?(String) end raise VariableError.new(self, :unit, "to be in #{units.inspect}", @unit) \ unless units.include?(@unit = @vars[:unit]) raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \ unless %i[asc desc].include?(@order = @vars[:order]) min, max = @vars[:local_minmax] raise VariableError.new(self, :local_minmax, 'to be a an Array of min and max local Time instances', @vars[:local_minmax]) \ unless min.is_a?(Time) && max.is_a?(Time) && !min.utc? && !min.utc? && min <= max \ && (@utc_offset = min.utc_offset) == max.utc_offset send :"setup_#{@unit}_vars", min, max end
def setup_week_vars(min, max)
def setup_week_vars(min, max) @initial = week_start(min) @final = week_start(max) + WEEK @pages = @last = (@final - @initial).to_i / WEEK @utc_from = (@initial + (snap * WEEK)).utc @utc_to = @utc_from + WEEK end
def setup_year_vars(min, max)
def setup_year_vars(min, max) @initial = new_time(min.year) @final = new_time(max.year + 1) @pages = @last = @final.year - @initial.year @utc_from = new_time(@initial.year + snap).utc @utc_to = new_time(@initial.year + snap + 1).utc end
def snap(page = @page)
Simple trick to snap the page into its ordered position,
def snap(page = @page) @order == :asc ? page - 1 : @pages - page end
def week_start(time)
def week_start(time) start = time - (((time.wday - @week_offset) * DAY) % WEEK) new_time(start.year, start.month, start.day) end