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