module MSS::Core::Collection

Provides useful methods for enumerating items in a collection.

Public Instance Methods

each(options = {}) click to toggle source

Yields once for every item in this collection.

collection.each {|item| ... }

@note If you want fewer than all items, it is generally better

to call {#page} than {#each} with a `:limit`.

@param [Hash] options

@option options [Integer] :limit (nil) The maximum number of

items to enumerate from this collection.

@option options [next_token] :next_token (nil)

Acts as an offset.  `:next_token` may be returned by {#each} and
{#each_batch} when a `:limit` is provided.

@return [nil_or_next_token] Returns nil if all items were enumerated.

If some items were excluded because of a `:limit` option then
a `next_token` is returned.  Calling an enumerable method on
the same collection with the `next_token` acts like an offset.
# File lib/mss/core/collection.rb, line 45
def each options = {}, &block
  each_batch(options) do |batch|
    batch.each(&block)
  end
end
each_batch(options = {}) click to toggle source

Yields items from this collection in batches.

collection.each_batch do |batch|
  batch.each do |item|
    # ...
  end
end

## Variable Batch Sizes

Each MSS service has its own rules on how it returns results. Because of this batch size may very based on:

  • Service limits (e.g. S3 limits keys to 1000 per response)

  • The size of response objects (SimpleDB limits responses to 1MB)

  • Time to process the request

Because of these variables, batch sizes may not be consistent for a single collection. Each batch represents all of the items returned in a single resopnse.

@note If you require fixed batch sizes, see {#in_groups_of}. @param (see each) @option (see each) @return (see each)

# File lib/mss/core/collection.rb, line 78
def each_batch options = {}, &block
  _each_batch(options.dup, &block)
end
enum(options = {}) click to toggle source

Use this method when you want to call a method provided by Enumerable, but you need to pass options:

# raises an error because collect does not accept arguments
collection.collect(:limit => 10) {|i| i.name }

# not an issue with the enum method
collection.enum(:limit => 10).collect(&:name)

@param (see each) @option (see each) @return [Enumerable::Enumerator] Returns an enumerator for this

collection.
# File lib/mss/core/collection.rb, line 96
def enum options = {}
  to_enum(:each, options)
end
Also aliased as: enumerator
enumerator(options = {})
Alias for: enum
first(options = {}) click to toggle source

Returns the first item from this collection.

@return [item_or_nil] Returns the first item from this collection or

nil if the collection is empty.
# File lib/mss/core/collection.rb, line 106
def first options = {}
  enum(options.merge(:limit => 1)).first
end
in_groups_of(size, options = {}) { |group| ... } click to toggle source

Yields items from this collection in groups of an exact size (except for perhaps the last group).

collection.in_groups_of (10, :limit => 30) do |group|

  # each group should be exactly 10 items unless
  # fewer than 30 items are returned by the service
  group.each do |item|
    #...
  end

end

@param [Integer] size Size each each group of objects

should be yielded in.

@param [Hash] options @option (see each) @return (see each)

# File lib/mss/core/collection.rb, line 128
def in_groups_of size, options = {}, &block

  group = []

  nil_or_next_token = each_batch(options) do |batch|
    batch.each do |item|
      group << item
      if group.size == size
        yield(group)
        group = []
      end
    end
  end

  yield(group) unless group.empty?

  nil_or_next_token

end
page(options = {}) click to toggle source

Returns a single page of results in a kind-of array ({PageResult}).

items = collection.page(:per_page => 10) # defaults to 10 items
items.is_a?(Array) # => true
items.size         # => 8
items.per_page     # => 10
items.last_page?   # => true

If you need to display a “next page” link in a web view you can use the more? method. Just make sure the generated link contains the `next_token`.

<% if items.more? %>
  <%= link_to('Next Page', params.merge(:next_token => items.next_token) %>
<% end %>

Then in your controller you can find the next page of results:

items = collection.page(:next_token => params[:next_token])

Given a {PageResult} you can also get more results directly:

more_items = items.next_page

@note This method does not accept a `:page` option, which means you

can only start at the begining of the collection and request
the next page of results.  You can not choose an offset
or know how many pages of results there will be.

@param [Hash] options A hash of options that modifies the

items returned in the page of results.

@option options [Integer] :per_page (10) The number of results

to return for each page.

@option options [String] :next_token (nil) A token that indicates

an offset to use when paging items.  Next tokens are returned
by {PageResult#next_token}.

Next tokens should only be consumed by the same collection that
created them.
# File lib/mss/core/collection.rb, line 190
def page options = {}

  each_opts = options.dup

  per_page = each_opts.delete(:per_page)
  per_page = [nil,''].include?(per_page) ? 10 : per_page.to_i

  each_opts[:limit] = per_page

  items = []
  next_token = each(each_opts) do |item|
    items << item
  end

  Core::PageResult.new(self, items, per_page, next_token)

end

Protected Instance Methods

_each_batch(options, &block) click to toggle source
# File lib/mss/core/collection.rb, line 210
def _each_batch options, &block
  # should be defined in the collection modules
  raise NotImplementedError
end
_each_item(next_token, options = {}) click to toggle source
# File lib/mss/core/collection.rb, line 215
def _each_item next_token, options = {}, &block
  # should be defined in classes included the collection modules
  raise NotImplementedError
end
_extract_batch_size(options) click to toggle source
# File lib/mss/core/collection.rb, line 226
def _extract_batch_size options
  batch_size = options.delete(:batch_size)
  batch_size = nil if batch_size == ''
  batch_size = batch_size.to_i if batch_size
  batch_size
end
_extract_limit(options) click to toggle source
# File lib/mss/core/collection.rb, line 233
def _extract_limit options
  limit = options.delete(:limit) || _limit
  limit = nil if limit == ''
  limit = limit.to_i if limit
  limit
end
_extract_next_token(options) click to toggle source
# File lib/mss/core/collection.rb, line 220
def _extract_next_token options
  next_token = options.delete(:next_token)
  next_token = nil if next_token == ''
  next_token
end
_limit() click to toggle source

Override this method in collection classes that provide an alternative way to provide the limit than passinging it to the enumerable method as :limit.

An example of when this would be useful:

collection.limit(10).each {|item| ... }

The collection class including this module should define _limit and return the cached limit value (of 10 from this example). This value may still be overridden by a locally passed `:limit` option:

# limit 5 wins out
collection.limit(10).each(:limit => 5) {|item| ... }
# File lib/mss/core/collection.rb, line 256
def _limit
  nil
end