Skip to content

Commit

Permalink
period tests, a bit of documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
trvsdnn committed Jan 24, 2013
1 parent 59b21fb commit 9ee305f
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 7 deletions.
32 changes: 28 additions & 4 deletions lib/von/counter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@ module Von
class Counter
CHILD_REGEX = /:[^:]+\z/
PARENT_REGEX = /:?[^:]+\z/


# Initialize a new Counter
#
# field - counter field name
def initialize(field)
@field = field.to_sym
end


# Returns options specified in config for this Counter
def options
@options ||= Von.config.counter_options(@field)
end


# Returns periods specified in config for this Counter
def periods
@periods ||= options.select { |k|
Period::AVAILABLE_PERIODS.include?(k)
}.inject({}) { |h, (p, l)| h[p] = Period.new(@field, p, l); h }
end

# Returns the Redis hash key used for storing counts for this Counter
def hash_key
@hash_key ||= "#{Von.config.namespace}:#{@field}"
end

# Increment the Redis count for this Counter.
# If the field is a Period, we increment the Period.
#
# field - the Redis field containing the count
def increment(field = 'total')
if field.is_a?(Period)
increment_period(field)
Expand All @@ -30,6 +40,9 @@ def increment(field = 'total')
end
end

# Increment the Redis count for a Period
#
# period - The Period to increment
def increment_period(period)
Von.connection.hincrby(period.hash_key, period.field, 1)
unless Von.connection.lrange(period.list_key, 0, -1).include?(period.field)
Expand All @@ -42,6 +55,9 @@ def increment_period(period)
end
end

# Increment the parent keys of this Counter.
# Example: increment('something:foo:bar') would increment
# 'something:foo:bar', 'something:foo', 'something'
def increment_parents
field = @field.to_s
return if field !~ CHILD_REGEX
Expand All @@ -54,7 +70,15 @@ def increment_parents
end
end

def count(period)
# Lookup the count for this Counter in Redis.
# If a Period argument is given we lookup the count for
# all of the possible units (not expired), zeroing ones that
# aren't set in Redis already.
#
# period - A Period to lookup
#
# Returns an Integer representing the count or an Array of counts.
def count(period = nil)
if period.nil?
Von.connection.hget(hash_key, 'total')
else
Expand Down
18 changes: 15 additions & 3 deletions lib/von/period.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ class Period

attr_reader :counter
attr_reader :length


# Initialize a Period object
#
# counter - the field name for the counter
# period - the time period one of AVAILABLE_PERIODS
# length - length of period
def initialize(counter, period, length)
@counter = counter
@period = period
@length = length
@now = Time.now
end

# Returns a Symbol representing the time unit
# for the current period.
def time_unit
@time_unit ||= case @period
when :hourly
Expand All @@ -27,22 +34,27 @@ def time_unit
end
end

# Returns True or False if the period is hourly
def hours?
@period == :hourly
end


# Returns the String DateTime format
def format
@format ||= Von.config.send(:"#{@period}_format")
end

# Returns the Redis hash key used for storing counts for this Period
def hash_key
@hash ||= "#{Von.config.namespace}:#{@counter}:#{@period}"
end

# Returns the Redis list key used for storing current "active" counters
def list_key
@list ||= "#{Von.config.namespace}:lists:#{@counter}:#{@period}"
end


# Returns the Redis field representation used for storing the count value
def field
@now.strftime(format)
end
Expand Down
64 changes: 64 additions & 0 deletions test/period_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
describe Von::Period do
Period = Von::Period

before :each do
@config = Von::Config
@config.reset!
end

it "intiializes given a counter, period, and length" do
period = Period.new('foo', :monthly, 6)
period.counter.must_equal 'foo'
period.length.must_equal 6
end

it "checks if the period is an hourly period" do
Period.new('foo', :hourly, 6).must_be :hours?
Period.new('foo', :daily, 6).wont_be :hours?
Period.new('foo', :weekly, 6).wont_be :hours?
Period.new('foo', :monthly, 6).wont_be :hours?
Period.new('foo', :yearly, 6).wont_be :hours?
end

it "knows what time unit it is" do
Period.new('foo', :hourly, 6).time_unit.must_equal :hour
Period.new('foo', :daily, 6).time_unit.must_equal :day
Period.new('foo', :weekly, 6).time_unit.must_equal :week
Period.new('foo', :monthly, 6).time_unit.must_equal :month
Period.new('foo', :yearly, 6).time_unit.must_equal :year
end

it "pulls a time format from config options" do
Period.new('foo', :hourly, 6).format.must_equal Von.config.hourly_format
Period.new('foo', :daily, 6).format.must_equal Von.config.daily_format
Period.new('foo', :weekly, 6).format.must_equal Von.config.weekly_format
Period.new('foo', :monthly, 6).format.must_equal Von.config.monthly_format
Period.new('foo', :yearly, 6).format.must_equal Von.config.yearly_format
end

it "builds a redis hash key string" do
field = 'foo'
period = :hourly
period_obj = Period.new(field, period, 6)

period_obj.hash_key.must_equal "#{@config.namespace}:#{field}:#{period}"
end

it "builds a redis list key string" do
field = 'foo'
period = :hourly
period_obj = Period.new(field, period, 6)

period_obj.list_key.must_equal "#{@config.namespace}:lists:#{field}:#{period}"
end

it "builds a redis field for the given period and current time" do
Timecop.freeze(Time.local(2013, 02, 01, 05))
Period.new('foo', :hourly, 6).field.must_equal '2013-02-01 05:00'
Period.new('foo', :daily, 6).field.must_equal '2013-02-01'
Period.new('foo', :weekly, 6).field.must_equal '2013-02-01'
Period.new('foo', :monthly, 6).field.must_equal '2013-02'
Period.new('foo', :yearly, 6).field.must_equal '2013'
end

end

0 comments on commit 9ee305f

Please sign in to comment.