lib/ohm/tallyable.rb in ohm-tallyable-0.1.4 vs lib/ohm/tallyable.rb in ohm-tallyable-0.1.5
- old
+ new
@@ -10,12 +10,18 @@
def tallies
@tallies ||= {}
end
+ def retally(attribute)
+ raise ArgumentError unless tallies.include?(attribute)
+ db.del(*_tally_keys(attribute))
+ all.each { |e| e.send(:_increment_tallies) }
+ end
+
def leaderboard(attribute, by=nil)
- raise ArgumentError if !_has_tally(attribute, by)
+ raise ArgumentError unless _has_tally(attribute, by)
_load_zset(_tally_key(attribute, by))
.map { |k, v| [k, v.to_i] }
.sort_by { |k, v| [-v, k] }
end
@@ -31,76 +37,80 @@
key = key[by.keys.first][by.values.first]
end
key
end
- if Redis::VERSION.to_i == 2
+ def _tally_keys(attribute)
+ keys = db.keys(_tally_key(attribute))
+ keys.concat(db.keys(_tally_key(attribute)["*"]))
+ end
+
+ if Redis::VERSION.to_i >= 3
def _load_zset(key)
- key.zrevrange(0, -1, with_scores: true).each_slice(2)
+ key.zrevrange(0, -1, with_scores: true)
end
else
def _load_zset(key)
- key.zrevrange(0, -1, with_scores: true)
+ key.zrevrange(0, -1, with_scores: true).each_slice(2)
end
end
end
- def self.included(model)
- unless new_callbacks?
+ if Ohm::Contrib::VERSION.to_i >= 1
+ def self.included(model)
+ model.extend(Macros)
+ end
+
+ def before_delete
+ _decrement_tallies
+ super
+ end
+ protected :before_delete
+
+ def before_update
+ _decrement_tallies
+ super
+ end
+ protected :before_update
+
+ def after_save
+ _increment_tallies
+ super
+ end
+ protected :after_save
+
+ else
+ def self.included(model)
model.before(:delete, :_decrement_tallies)
model.before(:save, :_decrement_tallies)
model.after(:save, :_increment_tallies)
+
+ model.extend(Macros)
end
- model.extend(Macros)
end
- private
- def self.new_callbacks?
- Ohm::Callbacks.protected_instance_methods.include?(:before_save)
- end
-
- protected
+ protected
def _decrement_tallies
- _update_tallies(-1) do |attribute|
- if respond_to? :read_remote
- read_remote(attribute)
- else
- # ugly, but better than using get and having
- # to save and restore the old value
- db.hget(key, attribute)
- end
- end
+ _update_tallies(-1) { |attribute| db.hget(key, attribute) }
end
def _increment_tallies
_update_tallies(1) { |attribute| send(attribute) }
end
def _update_tallies(amount, &block)
+ return if new?
+
self.class.tallies.each do |attribute, options|
by = options[:by] ? {options[:by] => yield(options[:by])} : nil
key = self.class._tally_key(attribute, by)
if (value = yield(attribute))
key.zincrby(amount, value)
# need to convert zscore to_i because older versions
# return a double encoded in a string
key.zrem(value) if key.zscore(value).to_i == 0
end
- end
- end
-
- if new_callbacks?
- def before_delete
- _decrement_tallies
- end
-
- def before_update
- _decrement_tallies
- end
-
- def after_save
- _increment_tallies
end
end
end
end