lib/pagy.rb in pagy-4.2.0 vs lib/pagy.rb in pagy-4.3.0
- old
+ new
@@ -3,11 +3,11 @@
require 'pathname'
# main class
class Pagy
- VERSION = '4.2.0'
+ VERSION = '4.3.0'
# Root pathname to get the path of Pagy files like templates or dictionaries
def self.root
@root ||= Pathname.new(__dir__).freeze
end
@@ -27,40 +27,44 @@
INSTANCE_VARS_MIN.each do |name,min|
raise VariableError.new(self), "expected :#{name} >= #{min}; got #{@vars[name].inspect}" \
unless @vars[name] && instance_variable_set(:"@#{name}", @vars[name].to_i) >= min
end
@pages = @last = [(@count.to_f / @items).ceil, 1].max
- raise OverflowError.new(self), "expected :page in 1..#{@last}; got #{@page.inspect}" if @page > @last
+ raise OverflowError.new(self), "expected :page in 1..#{@last}; got #{@page.inspect}" \
+ if @page > @last
@offset = @items * (@page - 1) + @outset
- @items = @count - ((@pages-1) * @items) if @page == @last && @count.positive?
+ @items = @count - ((@pages - 1) * @items) if @page == @last && @count.positive?
@from = @count.zero? ? 0 : @offset + 1 - @outset
@to = @count.zero? ? 0 : @offset + @items - @outset
- @prev = (@page-1 unless @page == 1)
+ @prev = (@page - 1 unless @page == 1)
@next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
end
# Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
def series(size=@vars[:size])
return [] if size.empty?
raise VariableError.new(self), "expected 4 items >= 0 in :size; got #{size.inspect}" \
- unless size.size == 4 && size.all?{ |num| num >= 0 rescue false } # rubocop:disable Style/RescueModifier
-
+ unless size.size == 4 && size.all?{ |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
+ # This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
+ left_gap_start = 1 + size[0]
+ left_gap_end = @page - size[1] - 1
+ right_gap_start = @page + size[2] + 1
+ right_gap_end = @last - size[3]
+ left_gap_end = right_gap_end if left_gap_end > right_gap_end
+ right_gap_start = left_gap_start if left_gap_start > right_gap_start
series = []
- [ *0..size[0], # initial pages from 0
- *@page-size[1]..@page+size[2], # around current page
- *@last-size[3]+1..@last+1 # final pages till @last+1
- ].sort!.each_cons(2) do |left, right| # sort and loop by 2
- next if left.negative? || left == right # skip out of range and duplicates
- break if left > @last # break if out of @last boundary
- case right
- when left+1 then series.push(left) # no gap -> no additions
- when left+2 then series.push(left, left+1) # 1 page gap -> fill with missing page
- else series.push(left, :gap) # n page gap -> add gap
- end
+ start = 1
+ if (left_gap_end - left_gap_start).positive?
+ series.push(*start..(left_gap_start - 1), :gap)
+ start = left_gap_end + 1
end
- series.shift # shift the start boundary (0)
- series[series.index(@page)] = @page.to_s # convert the current page to String
+ if (right_gap_end - right_gap_start).positive?
+ series.push(*start..(right_gap_start - 1), :gap)
+ start = right_gap_end + 1
+ end
+ series.push(*start..@last)
+ series[series.index(@page)] = @page.to_s
series
end
end