lib/ohm.rb in ohm-0.0.11 vs lib/ohm.rb in ohm-0.0.12

- old
+ new

@@ -2,11 +2,11 @@ require File.join(File.dirname(__FILE__), "ohm", "redis") require File.join(File.dirname(__FILE__), "ohm", "validations") module Ohm - # Provides access to the redis database. This is shared accross all models and instances. + # Provides access to the Redis database. This is shared accross all models and instances. def redis @redis end # Connect to a redis database. @@ -36,22 +36,61 @@ module Attributes class Collection include Enumerable - attr_accessor :key, :db + attr_accessor :key, :db, :model - def initialize(db, key) + def initialize(db, key, model = nil) self.db = db self.key = key + self.model = model end def each(&block) all.each(&block) end - def all(model = nil) + # Return instances of model for all the ids contained in the collection. + def all + instantiate(raw) + end + + # Return the values as model instances, ordered by the options supplied. + # Check redis documentation to see what values you can provide to each option. + # + # @param options [Hash] options to sort the collection. + # @option options [#to_s] :by Model attribute to sort the instances by. + # @option options [#to_s] :order (ASC) Sorting order, which can be ASC or DESC. + # @option options [Integer] :limit (all) Number of items to return. + # @option options [Integer] :start (0) An offset from where the limit will be applied. + # @example Get the first ten users sorted alphabetically by name: + # @event.attendees.sort(User, :by => :name, :order => "ALPHA", :limit => 10) + # + # @example Get five posts sorted by number of votes and starting from the number 5 (zero based): + # @blog.posts.sort(Post, :by => :votes, :start => 5, :limit => 10") + def sort(options = {}) + options[:start] ||= 0 + options[:limit] = [options[:start], options[:limit]] if options[:limit] + instantiate(db.sort(key, options)) + end + + def sort_by(att, options = {}) + sort(options.merge(:by => model.key("*", att))) + end + + def to_ary + all + end + + def ==(other) + to_ary == other + end + + private + + def instantiate(raw) model ? raw.collect { |id| model[id] } : raw end end # Represents a Redis list. @@ -72,11 +111,13 @@ # @param value [#to_s] Pushes value to the list. def << value db.rpush(key, value) end - private + def empty? + db.llen(key).zero? + end def raw db.list(key) end end @@ -111,18 +152,20 @@ def delete(value) db.srem(key, value) end + def empty? + db.scard(key).zero? + end + def include?(value) db.sismember(key, value) end - private - def raw - db.smembers(key).sort + db.smembers(key) end end end class Model @@ -183,22 +226,22 @@ # Defines a list attribute for the model. It can be accessed only after the model instance # is created. # # @param name [Symbol] Name of the list. - def self.list(name) - attr_list_reader(name) + def self.list(name, model = nil) + attr_list_reader(name, model) collections << name end # Defines a set attribute for the model. It can be accessed only after the model instance # is created. Sets are recommended when insertion and retrival order is irrelevant, and # operations like union, join, and membership checks are important. # # @param name [Symbol] Name of the set. - def self.set(name) - attr_set_reader(name) + def self.set(name, model = nil) + attr_set_reader(name, model) collections << name end # Creates an index (a set) that will be used for finding instances. # @@ -223,32 +266,30 @@ # Creates a composite index for street and city. def self.index(attrs) indices << Array(attrs) end - def self.attr_list_reader(name) - class_eval <<-EOS - def #{name} - @#{name} ||= Attributes::List.new(db, key("#{name}")) - end - EOS + def self.attr_list_reader(name, model = nil) + define_method(name) do + instance_variable_get("@#{name}") || + instance_variable_set("@#{name}", Attributes::List.new(db, key(name), model)) + end end - def self.attr_set_reader(name) - class_eval <<-EOS - def #{name} - @#{name} ||= Attributes::Set.new(db, key("#{name}")) - end - EOS + def self.attr_set_reader(name, model) + define_method(name) do + instance_variable_get("@#{name}") || + instance_variable_set("@#{name}", Attributes::Set.new(db, key(name), model)) + end end def self.[](id) new(:id => id) if exists?(id) end def self.all - filter(:all) + @all ||= Attributes::Set.new(db, key(:all), self) end def self.attributes @@attributes[self] end @@ -270,11 +311,11 @@ model.create model end def self.find(attribute, value) - filter(Ohm.key(attribute, encode(value))) + Attributes::Set.new(db, key(attribute, encode(value)), self) end def self.encode(value) Base64.encode64(value.to_s).chomp end @@ -372,15 +413,9 @@ Ohm.redis end def self.key(*args) Ohm.key(*args.unshift(self)) - end - - def self.filter(name) - db.smembers(key(name)).map do |id| - new(:id => id) - end end def self.exists?(id) db.sismember(key(:all), id) end