lib/ohm.rb in ohm-0.0.38 vs lib/ohm.rb in ohm-0.1.0.rc1

- old
+ new

@@ -7,11 +7,11 @@ require File.join(File.dirname(__FILE__), "ohm", "compat-1.8.6") require File.join(File.dirname(__FILE__), "ohm", "key") require File.join(File.dirname(__FILE__), "ohm", "collection") module Ohm - VERSION = "0.0.38" + VERSION = "0.1.0.rc1" # Provides access to the Redis database. This is shared accross all models and instances. def redis threaded[:redis] ||= connection(*options) end @@ -147,14 +147,14 @@ # # user = User.all.sort_by(:name, :order => "ALPHA").first # user.name == "A" # # => true def sort_by(att, options = {}) - options.merge!(:by => model.key("*", att)) + options.merge!(:by => model.key("*->#{att}")) if options[:get] - raw.sort(options.merge(:get => model.key("*", options[:get]))) + raw.sort(options.merge(:get => model.key("*->#{options[:get]}"))) else sort(options) end end @@ -198,11 +198,11 @@ class Set < Collection Raw = Ohm::Set def inspect - "#<Set (#{model}): #{raw.to_a.inspect}>" + "#<Set (#{model}): #{all.inspect}>" end # Returns an intersection with the sets generated from the passed hash. # # @see Ohm::Model.find @@ -210,27 +210,28 @@ # @events = Event.find(public: true) # # # You can combine the result with sort and other set operations: # @events.sort_by(:name) def find(hash) - apply(:sinterstore, hash, "+") + apply(:sinterstore, hash, :+) end # Returns the difference between the receiver and the passed sets. # # @example # @events = Event.find(public: true).except(status: "sold_out") def except(hash) - apply(:sdiffstore, hash, "-") + apply(:sdiffstore, hash, :-) end private - # Apply a redis operation on a collection of sets. + # Apply a Redis operation on a collection of sets. def apply(operation, hash, glue) - target = key.volatile.group(glue).append(*keys(hash)) - model.db.send(operation, target, *target.sub_keys) + keys = keys(hash) + target = key.volatile.send(glue, Key[*keys]) + model.db.send(operation, target, key, *keys) Set.new(target, Wrapper.wrap(model)) end # Transform a hash of attribute/values into an array of keys. def keys(hash) @@ -263,11 +264,11 @@ def unshift(model) raw.unshift(model.id) end def inspect - "#<List (#{model}): #{raw.to_a.inspect}>" + "#<List (#{model}): #{all.inspect}>" end end class Index < Set def apply(operation, hash, glue) @@ -288,11 +289,11 @@ # @overload assert_unique :name # Validates that the name attribute is unique. # @overload assert_unique [:street, :city] # Validates that the :street and :city pair is unique. def assert_unique(attrs) - result = db.sinter(*Array(attrs).map { |att| index_key_for(att, send(att)) }) || [] + result = db.sinter(*Array(attrs).map { |att| index_key_for(att, send(att)) }) assert result.empty? || !new? && result.include?(id.to_s), [attrs, :not_unique] end end include Validations @@ -488,11 +489,11 @@ model = Wrapper.wrap(model) define_method(name) { model.unwrap.find(:"#{reference}_id" => send(:id)) } end def self.to_reference - name.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym + name.to_s.match(/^(?:.*::)*(.*)$/)[1].gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym end def self.attr_collection_reader(name, type, model) if model model = Wrapper.wrap(model) @@ -600,31 +601,28 @@ end end def delete delete_from_indices - delete_attributes(attributes) - delete_attributes(counters) - delete_attributes(collections) + delete_attributes(collections) unless collections.empty? delete_model_membership self end # Increment the counter denoted by :att. # # @param att [Symbol] Attribute to increment. - def incr(att) + def incr(att, count = 1) raise ArgumentError, "#{att.inspect} is not a counter." unless counters.include?(att) - write_local(att, db.incr(key(att))) + write_local(att, db.hincrby(key, att, count)) end # Decrement the counter denoted by :att. # # @param att [Symbol] Attribute to decrement. - def decr(att) - raise ArgumentError, "#{att.inspect} is not a counter." unless counters.include?(att) - write_local(att, db.decr(key(att))) + def decr(att, count = 1) + incr(att, -count) end def attributes self.class.attributes end @@ -693,30 +691,26 @@ def key(*args) self.class.key(id, *args) end - # Write attributes using MSET def write unless attributes.empty? - rems, adds = attributes.map { |a| [key(a), send(a)] }.partition { |t| t.last.to_s.empty? } + attributes.each_with_index do |att, index| + value = send(att).to_s - db.del(*rems.flatten.compact) unless rems.empty? - db.mapped_mset(adds.flatten) unless adds.empty? + if value.empty? + db.hdel(key, att) + else + db.hset(key, att, value) + end + end end end def self.const_missing(name) - wrapper = Wrapper.new(name) { const_get(name) } - - # Allow others to hook to const_missing. - begin - super(name) - rescue NameError - end - - wrapper + Wrapper.new(name) { const_get(name) } end private # Provides access to the Redis database. This is shared accross all models and instances. @@ -743,21 +737,20 @@ def db self.class.db end def delete_attributes(atts) - atts.each do |att| - db.del(key(att)) - end + db.del(*atts.map { |att| key(att) }) end def create_model_membership - db.sadd(self.class.key(:all), id) + self.class.all << self end def delete_model_membership - db.srem(self.class.key(:all), id) + db.del(key) + self.class.all.delete(self) end def update_indices delete_from_indices add_to_indices @@ -784,11 +777,11 @@ db.sadd(index, id) db.sadd(key(:_indices), index) end def delete_from_indices - (db.smembers(key(:_indices)) || []).each do |index| + db.smembers(key(:_indices)).each do |index| db.srem(index, id) end db.del(key(:_indices)) end @@ -801,10 +794,10 @@ @_attributes[att] = value end def read_remote(att) unless new? - value = db.get(key(att)) + value = db.hget(key, att) value.respond_to?(:force_encoding) ? value.force_encoding("UTF-8") : value end end