Permalink
Browse files

add "current" counter

  • Loading branch information...
1 parent ed05f81 commit 9dbe228750c2e5e5bedd78c3f3858296be868431 @blahed committed Feb 1, 2013
Showing with 148 additions and 2 deletions.
  1. +6 −0 lib/von.rb
  2. +6 −0 lib/von/config.rb
  3. +20 −2 lib/von/counter.rb
  4. +43 −0 lib/von/counters/current.rb
  5. +4 −0 lib/von/period.rb
  6. +14 −0 test/counter_test.rb
  7. +55 −0 test/counters/current_test.rb
View
@@ -8,6 +8,7 @@
require 'von/counters/total'
require 'von/counters/period'
require 'von/counters/best'
+require 'von/counters/current'
require 'von/version'
module Von
@@ -53,6 +54,11 @@ def self.increment_counts_for(field)
Counters::Best.new(counter.field, periods).increment
end
+ if config.currents_defined_for_counter?(counter)
+ periods = config.currents[counter.field]
+ Counters::Current.new(counter.field, periods).increment
+ end
+
total
end
View
@@ -82,6 +82,12 @@ def bests_defined_for_counter?(counter)
@bests.has_key?(counter.field)
end
+ # Returns a True if a current is defined for the
+ # given counter
+ def currents_defined_for_counter?(counter)
+ @currents.has_key?(counter.field)
+ end
+
private
def set_period(field, period, length)
View
@@ -37,8 +37,8 @@ def per(unit)
end
def best(unit)
- periods = Von.config.bests[@field]
- period_name = Period.unit_to_period(unit)
+ periods = Von.config.bests[@field]
+ period_name = Period.unit_to_period(unit)
if period_name.nil?
raise ArgumentError, "`#{unit}' is an unknown time unit"
@@ -49,5 +49,23 @@ def best(unit)
raise e if Von.config.raise_connection_errors
end
+ def this(unit)
+ periods = Von.config.currents[@field]
+
+ if !Period.time_unit_exists?(unit)
+ raise ArgumentError, "`#{unit}' is an unknown time unit"
+ else
+ Counters::Current.new(@field, periods).count(unit)
+ end
+ rescue Redis::BaseError => e
+ raise e if Von.config.raise_connection_errors
+ end
+
+ def today
+ periods = Von.config.currents[@field]
+
+ Counters::Current.new(@field, periods).count(:day)
+ end
+
end
end
@@ -0,0 +1,43 @@
+module Von
+ module Counters
+ class Current
+ include Von::Counters::Commands
+
+ # Initialize a new Counter
+ #
+ # field - counter field name
+ def initialize(field, periods = nil)
+ @field = field.to_sym
+ @periods = periods || []
+ end
+
+ # Returns the Redis hash key used for storing counts for this Counter
+ def hash_key
+ "#{Von.config.namespace}:counters:currents:#{@field}"
+ end
+
+ def current_timestamp(time_unit)
+ hget("#{hash_key}:#{time_unit}", 'timestamp')
+ end
+
+ def increment
+ return if @periods.empty?
+
+ @periods.each do |period|
+ if period.timestamp != current_timestamp(period.time_unit)
+ hset("#{hash_key}:#{period.time_unit}", 'total', 1)
+ hset("#{hash_key}:#{period.time_unit}", 'timestamp', period.timestamp)
+ else
+ hincrby("#{hash_key}:#{period.time_unit}", 'total', 1)
+ end
+ end
+ end
+
+ def count(time_unit)
+ count = hget("#{hash_key}:#{time_unit}", 'total')
+ count.nil? ? 0 : count.to_i
+ end
+
+ end
+ end
+end
View
@@ -71,5 +71,9 @@ def self.unit_to_period(time_unit)
def self.exists?(period)
AVAILABLE_PERIODS.include?(period)
end
+
+ def self.time_unit_exists?(time_unit)
+ AVAILABLE_TIME_UNITS.include?(time_unit)
+ end
end
end
View
@@ -52,5 +52,19 @@
Counter.new('foo').best(:week).must_equal({:timestamp => "2013-01-07", :count => 4})
end
+ it "returns current count for a given period" do
+ Von.configure do |config|
+ config.counter 'foo', :current => [:minute, :day]
+ end
+
+ 4.times { Von.increment('foo') }
+ Timecop.freeze(Time.local(2013, 01, 20, 06, 10))
+ 3.times { Von.increment('foo') }
+
+ Counter.new('foo').this(:minute).must_equal 3
+ Counter.new('foo').this(:day).must_equal 3
+ Counter.new('foo').today.must_equal 3
+ end
+
end
@@ -0,0 +1,55 @@
+require 'test_helper'
+
+describe Von::Counters::Current do
+ CurrentCounter = Von::Counters::Current
+
+ before :each do
+ Timecop.freeze(Time.local(2013, 01, 01, 06))
+ Von.config.init!
+ @redis = Redis.new
+ @redis.flushall
+ end
+
+ it "increments the current counter for a period" do
+ counter = CurrentCounter.new('foo', [ Von::Period.new(:day) ])
+
+ 4.times { counter.increment }
+ Timecop.freeze(Time.local(2013, 01, 02))
+ 3.times { counter.increment }
+
+ @redis.hget('von:counters:currents:foo:day', 'timestamp').must_equal '2013-01-02'
+ @redis.hget('von:counters:currents:foo:day', 'total').must_equal '3'
+ end
+
+ it "increments the current counter for multiple periods" do
+ counter = CurrentCounter.new('foo', [
+ Von::Period.new(:minute),
+ Von::Period.new(:week),
+ ])
+
+ 4.times { counter.increment }
+ Timecop.freeze(Time.local(2013, 01, 20, 06, 10))
+ 3.times { counter.increment }
+
+ @redis.hget('von:counters:currents:foo:minute', 'timestamp').must_equal '2013-01-20 06:10'
+ @redis.hget('von:counters:currents:foo:minute', 'total').must_equal '3'
+
+ @redis.hget('von:counters:currents:foo:week', 'timestamp').must_equal '2013-01-14'
+ @redis.hget('von:counters:currents:foo:week', 'total').must_equal '3'
+ end
+
+ it "counts acurrent counter for a period" do
+ counter = CurrentCounter.new('foo', [
+ Von::Period.new(:minute),
+ Von::Period.new(:day),
+ ])
+
+ 4.times { counter.increment }
+ Timecop.freeze(Time.local(2013, 01, 01, 06, 10))
+ 3.times { counter.increment }
+
+ counter.count(:minute).must_equal 3
+ counter.count(:day).must_equal 7
+ end
+
+end

0 comments on commit 9dbe228

Please sign in to comment.