class Pagy

def initialize(opts)

merge and validate the options, do some simple aritmetic and set the instance variables
def initialize(opts)
  @opts        = Opts.to_h.merge!(opts)                                 # global opts + instance opts (bang faster)
  @opts[:page] = (@opts[:page]||1).to_i                                 # set page to 1 if nil
  [:count, :limit, :offset, :initial, :before, :page, :after, :final].each do |k|
    @opts[k] >= 0 rescue nil || raise(ArgumentError, "expected #{k} >= 0; got #{@opts[k].inspect}")
    instance_variable_set(:"@#{k}", @opts.delete(k))                    # set all the metrics variables
  end
  @pages   = @last = [(@count.to_f / @limit).ceil, 1].max               # cardinal and ordinal meanings
  (1..@last).cover?(@page) || raise(OutOfRangeError, "expected :page in 1..#{last}; got #{@page.inspect}")
  @offset += @limit * (@page - 1)                                       # initial offset + offset for pagination
  @limit   = @count % @limit if @page == @last                          # adjust limit for last page (for pre-limit(ed) collection)
  @from    = @count.zero? ? 0 : @offset+1                               # page begins from item
  @to      = @offset + @limit                                           # page ends to item
  @prev    = (@page-1 unless @page == 1)                                # nil if no prev page
  @next    = (@page+1 unless @page == @last)                            # nil if no next page
  @series  = []                                                         # e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
  all      = (0..@last+1)                                               # page range with boundaries
  arund    = ([@page-@before, 1].max .. [@page+@after, @last].min).to_a # before..after pages
  row      = (all.first(@initial+1) | arund | all.last(@final+1)).sort  # pages with boundaries
  row.each_cons(2) do |a, b|                                            # loop in consecutive pairs
    if    a+1 == b; @series.push(a)                                     # no gap     -> no additions
    elsif a+2 == b; @series.push(a, a+1)                                # 1 page gap -> fill with next page
    else            @series.push(a, :gap)                               # larger gap -> add :gap
    end                                                                 # skip the right boundary (last+1)
  end
  @series.shift                                                         # remove the left boundary (0)
  @series[@series.index(@page)] = @page.to_s                            # convert the current page to String
end