Permalink
Browse files

Improved the documentation

  • Loading branch information...
1 parent c5d056e commit 2558fd2f054393e32cbbcc2f49f4174a0cb5003b @ferblape committed Aug 25, 2009
Showing with 54 additions and 13 deletions.
  1. +8 −0 filtered_collections.rb
  2. +8 −1 lib/acts_as_stored_in_cache.rb
  3. +38 −12 lib/collection.rb
View
@@ -4,10 +4,18 @@
module FilteredCollections
+ # Raised when the stored object hasn't attribute <tt>:id</tt>
class MissingIdentifierAttribute < StandardError; end
+
+ # Raised when the stored object hasn't the attribute indicated to order the collection
class MissingSortByAttribute < StandardError; end
+
+ # Raised when the arguments of a function are wrong
class BadArguments < StandardError; end
+ # FIXME
+ # Defines the storage in which keep the collections.
+ # This has to be changed, in order to allow different storages (maybe with moneta project)
class << self
def storage
@@ -1,3 +1,7 @@
+# This module adds the property to store and read objects in <tt>Rails.cache</tt> whenever they change.
+#
+# It is very useful when loading a list of identifiers from a collection and we want to
+# obtain the complete object without collapsing the database.
module FilteredCollections
module ActsAsStoredInCache
@@ -8,6 +12,10 @@ def self.included(base)
module ClassMethods
def acts_as_stored_in_cache
+ if !ActionController::Base.perform_caching || !defined?(::Rails.cache)
+ ActiveRecord::Base.logger.error "Rails::cache is not defined, so acts_as_stored_in_cache is useless"
+ end
+
after_save :store_in_cache
after_destroy :delete_from_cache
@@ -38,7 +46,6 @@ def load_collection( ids )
module InstanceMethods
-
def cache_key
self.class.cache_key( self.id )
end
View
@@ -24,39 +24,46 @@ def initialize( elements_class, belongs_to, order_by_attribute, order )
self.elements = []
end
+ # Tries to load a collection or create it in other case
def self.load_or_initialize( elements_class, belongs_to, order_by_attribute, order )
self.load( elements_class, belongs_to ) || self.new( elements_class, belongs_to, order_by_attribute, order )
end
+ # Creates a collection from a Hash of attributes
def self.builder(options = {})
attributes = self.attributes.merge(options)
"#{self}.load_or_initialize( #{attributes[:elements_class]}, #{attributes[:belongs_to]}, :#{attributes[:order_by_attribute]}, :#{attributes[:order]} )"
end
-
- # keys
+ # Given the class of elements to store and the owner of the collection, returns
+ # which will be the key for that collection
def self.key_for( elements_class, belongs_to )
belongs_to = belongs_to.is_a?(Hash) ? belongs_to.map { |k,v| "#{k}_#{v}" }.sort.join('/') : belongs_to
"#{self.to_s.underscore}/#{elements_class}_#{belongs_to}"
end
+ # The identifier key of a collection
def key
self.class.key_for(self.elements_class, self.belongs_to)
end
- # /keys
+ # Returns if the collection is empty
def empty?; self.elements_ids.empty? end
+ # Given the identifier of an element, returns true if the element is included
def include?( element_id )
self.elements_ids.include?( element_id )
end
+ # Given the identifier of an element, returns which is its position
def index( element_id )
self.elements_ids.index(element_id)
end
+ # Position of the last element
def last_position; self.total_elements end
+ # Removes the given element
def delete_element( element )
element_id = element.is_a?(Fixnum) ? element : element.id
if position = self.index( element_id )
@@ -67,6 +74,8 @@ def delete_element( element )
self.save
end
+ # Store one element, and after that saves or not the collection, depending on the value of the second
+ # argument
def store_element( element, save = true )
raise FilteredCollections::MissingIdentifierAttribute unless element.respond_to?(:id)
raise FilteredCollections::MissingSortByAttribute unless element.respond_to?(self.order_by_attribute)
@@ -88,17 +97,24 @@ def store_element( element, save = true )
self.save if save
end
+ # Stores a collection of elements
def store_elements( elements )
elements.each do |element|
self.store_element( element, false )
end
self.save
end
- # allowed values for options:
- # - :limit
- # - :offset
- def find( search_type, options = {} )
+ # Returns a list of the elements from the collection, with a syntax very similar
+ # to <tt>ActiveRecord find</tt> method.
+ #
+ # ==== Parameters
+ #
+ # - <tt>type</tt>: allowed values are <tt>:all</tt> (in this case, it returns an Array of elements) or <tt>:first</tt>, which returns only the first element
+ # - <tt>options</tt>: a Hash of options. Allowed options are:
+ # - <tt>:limit</tt>: the total number of elements to return
+ # - <tt>:offset</tt>: the offset to apply
+ def find( type, options = {} )
limit = nil
if options[:limit]
limit = options[:limit].to_i
@@ -113,7 +129,7 @@ def find( search_type, options = {} )
end
limit ||= self.total_elements
offset ||= 0
- result = case search_type
+ result = case type
when :all
if options.empty?
self.elements_ids
@@ -134,9 +150,11 @@ def find( search_type, options = {} )
end
end
- # allowed values for options:
- # - :per_page: default 50
- # - :page: default 1
+ # Returns a <tt>WillPaginate::Collection</tt> of elements from the collection. The argument is
+ # a Hash of options. Only two options are allowed:
+ #
+ # - <tt>:per_page</tt>: by default 50 elements.
+ # - <tt>:page</tt>: by default page 1.
def paginate( options = {} )
page = options[:page].to_i || 1
page = 1 if page <= 0
@@ -153,14 +171,21 @@ def paginate( options = {} )
end
end
+ # Load the collection from the storage
+ #
+ # ==== Parameters
+ #
+ # * <tt>elements_class</tt>: the class of the elements in the collection
+ # * <tt>belongs_to</tt>: the owner of the collection
def self.load( elements_class, belongs_to )
if obj = FilteredCollections.storage.get(self.key_for(elements_class, belongs_to))
Marshal.load(YAML.load(obj))
else
nil
end
end
-
+
+ # Store the collection in the storage
def save
FilteredCollections.storage.set(key, Marshal.dump(self).to_yaml)
end
@@ -175,6 +200,7 @@ def self.attributes; {} end
protected
+ # Reorders a collection depending on the <tt>order</tt> value, <tt>:asc</tt> or <tt>:desc</tt>
def reorder!
if self.order == :asc
self.elements.sort!{ |a, b| a.values.first <=> b.values.first }

0 comments on commit 2558fd2

Please sign in to comment.