29 Commits

Author SHA1 Message Date
ecbd15ef1e Merge branch 'release/v0.2.4' 2011-03-14 11:14:01 +00:00
2b2461dd9f started release v0.2.4 2011-03-14 11:13:50 +00:00
3e177c9ae4 changed json dependency back to '>= 1.4.0' for backwards compatibility with certain older projects/gems, make sure you're using 1.5.0 or later of the json gem for JRuby support 2011-03-14 11:13:06 +00:00
d4cd5402bc create Label#join method for easily joining Labels 2011-03-14 11:10:24 +00:00
d560a7deff killed an old line of commented out code 2011-03-14 10:38:16 +00:00
3df6666704 additions to specs 2011-03-14 10:37:56 +00:00
80fd63059b updated time_ext dependency to ensure there's no loading issues within Rails applications 2011-03-13 23:47:02 +00:00
d0b7f097a8 updated json dependency to '>= 1.5.0' to ensure JRuby compatability 2011-03-13 23:46:00 +00:00
875d16b01c Merge branch 'release/v0.2.3' into dev 2011-03-13 20:30:21 +00:00
00791d36d8 Merge branch 'release/v0.2.3' 2011-03-13 20:30:17 +00:00
94b589c5e6 started release v0.2.3 2011-03-13 20:30:11 +00:00
cdf52869d6 added #find_event method to Model 2011-03-13 20:28:17 +00:00
8b711d4d9c fixed a bug with Event#find 2011-03-13 20:24:06 +00:00
e4aaedfe58 made Key#scope return Scope object instead of Scope#to_s 2011-03-13 20:23:41 +00:00
ea820d44f4 fixed typo in Finder spec 2011-03-13 19:52:30 +00:00
acedf071d1 improved options passed into Finder object, :depth option is not needed if :interval is set to a depth value instead of true 2011-03-13 19:51:04 +00:00
108b6ab02e Finder's options methods now set the option when an argument is supplied and returns self for method chaining. When no argument is supplied it returns the option value itself.
Example:

    finder = Redistat::Finder.new
    finder.scope("Foo") #=> Finder object
    finder.scope        #=> Scope object
    finder.scope.to_s   #=> "Foo"
2011-03-13 19:46:52 +00:00
9920c0dc2f Merge branch 'release/v0.2.2' into dev 2011-03-12 22:26:58 +00:00
a72ad31c51 Merge branch 'release/v0.2.2' 2011-03-12 22:26:52 +00:00
008228660e started release v0.2.2 2011-03-12 22:26:12 +00:00
b8ddcdf71a Merge remote-tracking branch 'origin/dev' into dev 2011-03-12 22:25:35 +00:00
94fcd5b4ae fixed a ruby 1.9.x issue 2011-03-12 22:24:06 +00:00
e2a551d01c syntax beautification 2011-03-12 22:23:06 +00:00
43fc8bc2dd updated Hash extensions and specs 2011-03-12 22:21:15 +00:00
dcca3556ea some cleanup 2011-03-12 22:00:21 +00:00
d5f79b82a9 somewhat better loading procedure 2011-03-12 21:59:52 +00:00
0938781cd1 extend ::Hash with #set_or_incr and #merge_and_incr methods 2011-03-12 21:47:54 +00:00
82119fcf69 wrong usage of interval method in Finder spec 2011-03-11 15:38:10 +00:00
746d0fea8f Merge branch 'release/v0.2.1' into dev 2011-03-10 16:31:42 +00:00
22 changed files with 176 additions and 62 deletions

View File

@@ -1,14 +1,20 @@
require 'rubygems'
require 'active_support'
require 'active_support/hash_with_indifferent_access' if !{}.respond_to?(:with_indifferent_access) # Active Support 2.x and 3.x
require 'redis'
require 'date'
require 'time'
require 'time_ext'
require 'json'
require 'digest/sha1'
# Active Support 2.x or 3.x
require 'active_support'
if !{}.respond_to?(:with_indifferent_access)
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/hash/reverse_merge'
end
require 'time_ext'
require 'redis'
require 'json'
require 'redistat/options'
require 'redistat/connection'
require 'redistat/database'
@@ -17,7 +23,6 @@ require 'redistat/date'
require 'redistat/date_helper'
require 'redistat/event'
require 'redistat/finder'
require 'redistat/finder/date_set'
require 'redistat/key'
require 'redistat/label'
require 'redistat/model'
@@ -26,10 +31,7 @@ require 'redistat/scope'
require 'redistat/summary'
require 'redistat/version'
require 'redistat/core_ext/date'
require 'redistat/core_ext/time'
require 'redistat/core_ext/fixnum'
require 'redistat/core_ext/bignum'
require 'redistat/core_ext'
module Redistat

5
lib/redistat/core_ext.rb Normal file
View File

@@ -0,0 +1,5 @@
require 'redistat/core_ext/bignum'
require 'redistat/core_ext/date'
require 'redistat/core_ext/fixnum'
require 'redistat/core_ext/hash'
require 'redistat/core_ext/time'

View File

@@ -0,0 +1,23 @@
class Hash
def merge_and_incr(hash)
self.clone.merge_and_incr!(hash)
end
def merge_and_incr!(hash)
raise ArgumentError unless hash.is_a?(Hash)
hash.each do |key, value|
self[key] = value unless self.set_or_incr(key, value)
end
self
end
def set_or_incr(key, value)
return false unless value.is_a?(Numeric)
self[key] = 0 unless self.has_key?(key)
return false unless self[key].is_a?(Numeric)
self[key] += value
true
end
end

View File

@@ -91,7 +91,7 @@ module Redistat
event = db.hgetall "#{scope}#{KEY_EVENT}#{id}"
return nil if event.size == 0
self.new( event["scope"], event["label"], event["date"], JSON.parse(event["stats"]),
JSON.parse(event["meta"]), JSON.parse(event["options"]), false )
JSON.parse(event["options"]), JSON.parse(event["meta"]), false )
end
end

View File

@@ -1,3 +1,5 @@
require 'redistat/finder/date_set'
module Redistat
class Finder
include Database
@@ -79,49 +81,56 @@ module Redistat
}
end
def connection_ref(ref)
def connection_ref(ref = nil)
return options[:connection_ref] if ref.nil?
reset! if options[:connection_ref] != ref
options[:connection_ref] = ref
self
end
def scope(scope)
reset! if !options[:scope].nil? && options[:scope].to_s != scope
options[:scope] = Scope.new(scope)
def scope(input = nil)
return options[:scope] if input.nil?
reset! if !options[:scope].nil? && options[:scope].to_s != input.to_s
options[:scope] = Scope.new(input)
self
end
def label(label)
reset! if options.has_key?(:label) && options[:label].to_s != label.to_s
options[:label] = (!label.nil?) ? Label.new(label) : nil
def label(input = nil)
return options[:label] if input.nil?
reset! if options.has_key?(:label) && options[:label].to_s != input.to_s
options[:label] = (!input.nil?) ? Label.new(input) : nil
self
end
def dates(from, till)
from(from).till(till)
def dates(start, finish)
from(start).till(finish)
end
alias :date :dates
def from(date)
def from(date = nil)
return options[:from] if date.nil?
reset! if options[:from] != date
options[:from] = date
self
end
def till(date)
def till(date = nil)
return options[:till] if date.nil?
reset! if options[:till] != date
options[:till] = date
self
end
alias :until :till
def depth(unit)
def depth(unit = nil)
return options[:depth] if unit.nil?
reset! if options[:depth] != unit
options[:depth] = unit
self
end
def interval(unit)
def interval(unit = nil)
return options[:interval] if unit.nil?
reset! if options[:interval] != unit
options[:interval] = unit
self

View File

@@ -9,6 +9,10 @@ module Redistat
end
def find_date_sets(start_date, end_date, depth = nil, interval = false)
if depth.nil? && interval.is_a?(Symbol)
depth = interval
interval = true
end
start_date = start_date.to_time if start_date.is_a?(::Date)
end_date = end_date.to_time if end_date.is_a?(::Date)
if !interval

View File

@@ -30,13 +30,14 @@ module Redistat
options[:depth]
end
def scope
@scope.to_s
end
# def scope
# @scope.to_s
# end
def scope=(input)
@scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)
end
attr_reader :scope
def label=(input)
@label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)
@@ -60,7 +61,6 @@ module Redistat
def update_index
@label.groups.each do |label|
# break if label.parent.nil?
parent = (label.parent || "")
db.sadd("#{scope}#{LABEL_INDEX}#{parent}", label.me)
end

View File

@@ -11,6 +11,11 @@ module Redistat
self.new(name, opts).save
end
def self.join(*args)
args = args.map {|i| i.to_s}
self.new(args.reject {|i| i.blank? }.join(GROUP_SEPARATOR))
end
def initialize(str, opts = {})
parse_options(opts)
@raw = str.to_s

View File

@@ -13,7 +13,7 @@ module Redistat
#
def store(label, stats = {}, date = nil, opts = {}, meta = {})
Event.new(name, label, date, stats, options.merge(opts), meta).save
Event.new(self.name, label, date, stats, options.merge(opts), meta).save
end
alias :event :store
@@ -29,6 +29,10 @@ module Redistat
:till => till }.merge(options.merge(opts)) )
end
def find_event(event_id)
Event.find(self.name, event_id)
end
#
# options methods

View File

@@ -5,8 +5,6 @@ module Redistat
base.extend(ClassMethods)
end
class InvalidDefaultOptions < ArgumentError; end
module ClassMethods
def option_accessor(*opts)
opts.each do |option|

View File

@@ -12,12 +12,5 @@ module Redistat
@till = options[:till] ||= nil
end
def set_or_incr(key, value)
self[key] = 0 if !self.has_key?(key)
self[key] += value
self
end
end
end
end

View File

@@ -18,10 +18,10 @@ module Redistat
if options[:enable_grouping]
stats = inject_group_summaries(stats)
key.groups.each { |k|
key.groups.each do |k|
update_key(k, stats, depth_limit, options[:connection_ref])
k.update_index if options[:label_indexing]
}
end
else
update_key(key, stats, depth_limit, options[:connection_ref])
end
@@ -43,6 +43,7 @@ module Redistat
end
def self.inject_group_summaries!(stats)
summaries = {}
stats.each do |key, value|
parts = key.to_s.split(GROUP_SEPARATOR)
parts.pop
@@ -51,11 +52,11 @@ module Redistat
parts.each do |part|
sum_parts << part
sum_key = sum_parts.join(GROUP_SEPARATOR)
(stats.has_key?(sum_key)) ? stats[sum_key] += value : stats[sum_key] = value
(summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value
end
end
end
stats
stats.merge_and_incr!(summaries)
end
def self.inject_group_summaries(stats)

View File

@@ -1,3 +1,3 @@
module Redistat
VERSION = "0.2.1"
VERSION = "0.2.4"
end

View File

@@ -22,10 +22,9 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'activesupport', '>= 2.3.6'
s.add_runtime_dependency 'json', '>= 1.4.0'
s.add_runtime_dependency 'redis', '>= 2.1.0'
s.add_runtime_dependency 'time_ext', '>= 0.2.8'
s.add_runtime_dependency 'time_ext', '>= 0.2.9'
s.add_development_dependency 'rspec', '>= 2.1.0'
s.add_development_dependency 'rcov', '>= 0.9.9'
s.add_development_dependency 'yard', '>= 0.6.3'
s.add_development_dependency 'ruby-debug'
end

View File

@@ -0,0 +1,30 @@
require "spec_helper"
describe Hash do
it "should #set_or_incr values" do
hash = {:count => 1}
hash.set_or_incr(:sum, 3).should be_true
hash.should == {:count => 1, :sum => 3}
hash.set_or_incr(:count, 4).should be_true
hash.should == {:count => 5, :sum => 3}
hash.set_or_incr(:count, 'test').should be_false
hash.set_or_incr(:view, 'test').should be_false
hash.should == {:count => 5, :sum => 3}
hash[:view] = 'test'
hash.set_or_incr(:view, 3).should be_false
end
it "should #merge_and_incr hashes" do
hash = { :count => 1, :city => 'hell', :sum => 3, :name => 'john' }
new_hash = { :count => 3, :city => 'slum', :views => 2 }
hash.clone.merge_and_incr(new_hash).should == { :count => 4, :city => 'slum', :views => 2,
:sum => 3, :name => 'john' }
new_hash = { :count => 'six', :city => 'slum', :views => 2, :time => 'late' }
hash.clone.merge_and_incr(new_hash).should == { :count => 'six', :city => 'slum', :views => 2,
:sum => 3, :name => 'john', :time => 'late' }
end
end

View File

@@ -8,8 +8,8 @@ describe Redistat::Event do
@scope = "PageViews"
@label = "about_us"
@label_hash = Digest::SHA1.hexdigest(@label)
@stats = {:views => 1}
@meta = {:user_id => 239}
@stats = {'views' => 1}
@meta = {'user_id' => 239}
@options = {:depth => :hour}
@date = Time.now
@event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta)
@@ -17,7 +17,7 @@ describe Redistat::Event do
it "should initialize properly" do
@event.id.should be_nil
@event.scope.should == @scope
@event.scope.to_s.should == @scope
@event.label.to_s.should == @label
@event.label_hash.should == @label_hash
@event.date.to_time.to_s.should == @date.to_s
@@ -63,9 +63,11 @@ describe Redistat::Event do
it "should find event by id" do
@event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save
fetched = Redistat::Event.find(@scope, @event.id)
@event.scope.should == fetched.scope
@event.scope.to_s.should == fetched.scope.to_s
@event.label.to_s.should == fetched.label.to_s
@event.date.to_s.should == fetched.date.to_s
@event.stats.should == fetched.stats
@event.meta.should == fetched.meta
end
it "should store summarized statistics" do

View File

@@ -28,11 +28,13 @@ describe Redistat::Finder::DateSet do
result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :hour, true)
result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"]
result[0][:rem].should == []
result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :hour)
t_end = t_start + 4.days
result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :day, true)
result[0][:add].should == ["20100828", "20100829", "20100830", "20100831", "20100901"]
result[0][:rem].should == []
result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :day)
end
it "should find start keys properly" do

View File

@@ -25,28 +25,36 @@ describe Redistat::Finder do
finder.options[:label].to_s.should == options[:label]
finder.options.should == options.merge(:scope => finder.options[:scope], :label => finder.options[:label])
finder = Redistat::Finder.scope("hello")
finder.options[:scope].to_s.should == "hello"
finder.scope.to_s.should == "hello"
finder = Redistat::Finder.label("hello")
finder.options[:label].to_s.should == "hello"
finder.label.to_s.should == "hello"
finder = Redistat::Finder.dates(@two_hours_ago, @one_hour_ago)
finder.options[:from].should == @two_hours_ago
finder.options[:till].should == @one_hour_ago
finder = Redistat::Finder.scope("hello")
finder.options[:scope].to_s.should == "hello"
finder = Redistat::Finder.label("hello")
finder.options[:label].to_s.should == "hello"
finder = Redistat::Finder.from(@two_hours_ago)
finder.options[:from].should == @two_hours_ago
finder.from.should == @two_hours_ago
finder = Redistat::Finder.till(@one_hour_ago)
finder.options[:till].should == @one_hour_ago
finder.till.should == @one_hour_ago
finder = Redistat::Finder.depth(:hour)
finder.options[:depth].should == :hour
finder.depth.should == :hour
finder = Redistat::Finder.interval(:hour)
finder.options[:interval].should == :hour
finder = Redistat::Finder.interval(true)
finder.options[:interval].should be_true
finder.interval.should be_true
finder = Redistat::Finder.interval(false)
finder.options[:interval].should be_false
finder.interval.should be_false
end
it "should fetch stats properly" do

View File

@@ -13,7 +13,7 @@ describe Redistat::Key do
end
it "should initialize properly" do
@key.scope.should == @scope
@key.scope.to_s.should == @scope
@key.label.to_s.should == @label
@key.label_hash.should == @label_hash
@key.groups.map { |k| k.instance_variable_get("@label") }.should == @key.instance_variable_get("@label").groups
@@ -28,6 +28,8 @@ describe Redistat::Key do
@key.to_s(props.last).should == "#{@scope}/#{@label}:#{@key.date.to_s(props.last)}"
props.pop
end
key = Redistat::Key.new(@scope, nil, @date, {:depth => :hour})
key.to_s.should == "#{@scope}:#{key.date.to_s(:hour)}"
end
it "should abide to hashed_label option" do
@@ -44,10 +46,10 @@ describe Redistat::Key do
it "should allow changing attributes" do
# scope
@key.scope.should == @scope
@key.scope.to_s.should == @scope
@scope = "VisitorCount"
@key.scope = @scope
@key.scope.should == @scope
@key.scope.to_s.should == @scope
# date
@key.date.to_time.to_s.should == @date.to_s
@date = Time.now

View File

@@ -25,6 +25,19 @@ describe Redistat::Label do
db.hget(Redistat::KEY_LABELS, label.hash).should == name
end
it "should join labels" do
include Redistat
label = Label.join('email', 'message', 'public')
label.should be_a(Label)
label.to_s.should == 'email/message/public'
label = Label.join(Label.new('email'), Label.new('message'), Label.new('public'))
label.should be_a(Label)
label.to_s.should == 'email/message/public'
label = Label.join('email', '', 'message', nil, 'public')
label.should be_a(Label)
label.to_s.should == 'email/message/public'
end
describe "Grouping" do
before(:each) do
@name = "message/public/offensive"

View File

@@ -28,6 +28,11 @@ describe Redistat::Model do
finder.options[:till].should == one_hour_ago
end
it "should #find_event" do
Redistat::Event.should_receive(:find).with('ModelHelper1', 1)
ModelHelper1.find_event(1)
end
it "should listen to model-defined options" do
ModelHelper2.depth.should == :day
ModelHelper2.store_event.should == true

View File

@@ -46,6 +46,15 @@ describe Redistat::Summary do
end
end
it "should update summaries even if no label is set" do
key = Redistat::Key.new(@scope, nil, @date, {:depth => :day})
Redistat::Summary.update(key, @stats, :hour)
summary = db.hgetall(key.to_s(:hour))
summary.should have(2).items
summary["views"].should == "3"
summary["visitors"].should == "2"
end
it "should inject stats key grouping summaries" do
hash = { "count/hello" => 3, "count/world" => 7,
"death/bomb" => 4, "death/unicorn" => 3,