<commit_before>#
# Copyright (C) 2012 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

# This is a utility wrapper class for making custom paginated collections that
# are compatible with WillPaginate (so they can be used with Api.paginate,
# mainly).
#
# For example:
#   collection = PaginatedCollection.build do |pager|
#     pager.replace(some_custom_query(pager.current_page, pager.per_page))
#   end
#   Api.paginate(collection)
#
# The pager object passed into the block is a PaginatedCollection::Collection,
# which is a subclass of Array with the WillPaginate attributes added.
# This is similar to a WillPaginate::Collection, the primary differences
# being the way it is initialized, greater flexibility in specifying next/total
# pages, and it allows non-integer page ids.
#
# You can set pager.total_entries if you know a total count, or you can set
# pager.next_page to the id of the next page if you know there's another page,
# but don't have a total count.
#
# You can also use PaginatedCollection with an underlying collection such as an
# AR scope, if you want to do custom mapping of that scope result.
#
# For example:
#   collection = PaginatedCollection.build do |pager|
#     students = @course.students.paginate(:page => pager.current_page, :per_page => pager.per_page)
#     students.map! { |s| s = s.to_json; s['other_attr'] = some_method(s); s }
#   end
#   students = Api.paginate(collection)
#
# Note that the block needs to edit the AR collection in-place, because it's a
# subclass of Array with paging information, rather than just a raw array.
module PaginatedCollection
  def self.build(&block)
    raise(ArgumentError, "block required") unless block
    Proxy.new(block)
  end

  class Collection < Array
    # these are set before the collection is populated
    attr_accessor :current_page, :per_page
    # these can optionally be set while populating the collection
    attr_accessor :next_page, :previous_page, :first_page, :last_page, :total_entries
  end

  class Proxy < Struct.new(:block)
    def paginate(options = {})
      raise(ArgumentError, "per_page required") unless options[:per_page] && options[:per_page] > 0

      pager = PaginatedCollection::Collection.new
      pager.current_page = options[:page]
      pager.per_page = options[:per_page]
      pager.total_entries = options[:total_entries]<commit_msg>don't make PagniatedCollection::Proxy a struct<commit_after>#
# Copyright (C) 2012 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

# This is a utility wrapper class for making custom paginated collections that
# are compatible with WillPaginate (so they can be used with Api.paginate,
# mainly).
#
# For example:
#   collection = PaginatedCollection.build do |pager|
#     pager.replace(some_custom_query(pager.current_page, pager.per_page))
#   end
#   Api.paginate(collection)
#
# The pager object passed into the block is a PaginatedCollection::Collection,
# which is a subclass of Array with the WillPaginate attributes added.
# This is similar to a WillPaginate::Collection, the primary differences
# being the way it is initialized, greater flexibility in specifying next/total
# pages, and it allows non-integer page ids.
#
# You can set pager.total_entries if you know a total count, or you can set
# pager.next_page to the id of the next page if you know there's another page,
# but don't have a total count.
#
# You can also use PaginatedCollection with an underlying collection such as an
# AR scope, if you want to do custom mapping of that scope result.
#
# For example:
#   collection = PaginatedCollection.build do |pager|
#     students = @course.students.paginate(:page => pager.current_page, :per_page => pager.per_page)
#     students.map! { |s| s = s.to_json; s['other_attr'] = some_method(s); s }
#   end
#   students = Api.paginate(collection)
#
# Note that the block needs to edit the AR collection in-place, because it's a
# subclass of Array with paging information, rather than just a raw array.
module PaginatedCollection
  def self.build(&block)
    raise(ArgumentError, "block required") unless block
    Proxy.new(block)
  end

  class Collection < Array
    # these are set before the collection is populated
    attr_accessor :current_page, :per_page
    # these can optionally be set while populating the collection
    attr_accessor :next_page, :previous_page, :first_page, :last_page, :total_entries
  end

  class Proxy
    attr_accessor :block

    def initialize(block)
      @block = block
    end

    def paginate(options = {})
      raise(ArgumentError, "per_page required") unless options[:per_page] && options[:per_page] > 0

      pager = PaginatedCollection::Collection.new
      pager.current_page = options[:page]
      pager.per_page = options[:per_page]
      pager.total_entries = options[:total_entries]
{'fraction_non_alphanumeric': 0.07859754071119973, 'fraction_numerical': 0.0019940179461615153, 'mean_word_length': 4.1977547495682215, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2199538', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1686, 'n_words': 715}