class Redis::Counter
Class representing a Redis
counter. This functions like a proxy class, in that you can say @object.counter_name to get the value and then @object.counter_name.increment to operate on it. You can use this directly, or you can use the counter :foo class method in your class to define a counter.
Public Class Methods
Redis::BaseObject::new
# File lib/redis/counter.rb, line 12 def initialize(key, *args) super(key, *args) @options[:start] ||= @options[:default] || 0 raise ArgumentError, "Marshalling redis counters does not make sense" if @options[:marshal] redis.setnx(key, @options[:start]) unless @options[:start] == 0 || @options[:init] === false end
Public Instance Methods
Decrement a floating point counter atomically. Redis
uses separate API’s to interact with integers vs floats.
# File lib/redis/counter.rb, line 102 def decrbyfloat(by=1.0, &block) allow_expiration do val = redis.incrbyfloat(key, -by).to_f block_given? ? rewindable_block(:incrbyfloat, by, val, &block) : val end end
Decrement the counter atomically and return the new value. If passed a block, that block will be evaluated with the new value of the counter as an argument. If the block returns nil or throws an exception, the counter will automatically be incremented to its previous value. This method is aliased as decr() for brevity.
# File lib/redis/counter.rb, line 82 def decrement(by=1, &block) allow_expiration do val = redis.decrby(key, by).to_i block_given? ? rewindable_block(:increment, by, val, &block) : val end end
Reset the counter to its starting value, and return previous value. Use this to “reap” the counter and save it somewhere else. This is atomic in that no increments or decrements are lost if you process the returned value.
# File lib/redis/counter.rb, line 34 def getset(to=options[:start]) redis.getset(key, to.to_i).to_i end
Increment a floating point counter atomically. Redis
uses separate API’s to interact with integers vs floats.
# File lib/redis/counter.rb, line 93 def incrbyfloat(by=1.0, &block) allow_expiration do val = redis.incrbyfloat(key, by).to_f block_given? ? rewindable_block(:decrbyfloat, by, val, &block) : val end end
Increment the counter atomically and return the new value. If passed a block, that block will be evaluated with the new value of the counter as an argument. If the block returns nil or throws an exception, the counter will automatically be decremented to its previous value. This method is aliased as incr() for brevity.
# File lib/redis/counter.rb, line 68 def increment(by=1, &block) allow_expiration do val = redis.incrby(key, by).to_i block_given? ? rewindable_block(:decrement, by, val, &block) : val end end
# File lib/redis/counter.rb, line 114 def nil? !redis.exists?(key) end
Reset the counter to its starting value. Not atomic, so use with care. Normally only useful if you’re discarding all sub-records associated with a parent and starting over (for example, restarting a game and disconnecting all players).
# File lib/redis/counter.rb, line 23 def reset(to=options[:start]) allow_expiration do redis.set key, to.to_i true # hack for redis-rb regression end end
Like .value but casts to float since Redis
addresses these differently.
# File lib/redis/counter.rb, line 59 def to_f redis.get(key).to_f end
Proxy methods to help make @object.counter == 10 work
# File lib/redis/counter.rb, line 111 def to_s; value.to_s; end
Returns the current value of the counter. Normally just calling the counter will lazily fetch the value, and only update it if increment or decrement is called. This forces a network call to redis-server to get the current value.
# File lib/redis/counter.rb, line 42 def value redis.get(key).to_i end
# File lib/redis/counter.rb, line 47 def value=(val) allow_expiration do if val.nil? delete else redis.set key, val end end end
Private Instance Methods
Implements atomic increment/decrement blocks
# File lib/redis/counter.rb, line 132 def rewindable_block(rewind, by, value, &block) raise ArgumentError, "Missing block to rewindable_block somehow" unless block_given? ret = nil begin ret = yield value rescue send(rewind, by) raise end send(rewind, by) if ret.nil? ret end