17 Commits

14 changed files with 126 additions and 48 deletions

View File

@@ -1,14 +1,20 @@
require 'rubygems' 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 'date'
require 'time' require 'time'
require 'time_ext'
require 'json'
require 'digest/sha1' 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/options'
require 'redistat/connection' require 'redistat/connection'
require 'redistat/database' require 'redistat/database'
@@ -17,7 +23,6 @@ require 'redistat/date'
require 'redistat/date_helper' require 'redistat/date_helper'
require 'redistat/event' require 'redistat/event'
require 'redistat/finder' require 'redistat/finder'
require 'redistat/finder/date_set'
require 'redistat/key' require 'redistat/key'
require 'redistat/label' require 'redistat/label'
require 'redistat/model' require 'redistat/model'
@@ -26,16 +31,13 @@ require 'redistat/scope'
require 'redistat/summary' require 'redistat/summary'
require 'redistat/version' require 'redistat/version'
require 'redistat/core_ext/date' require 'redistat/core_ext'
require 'redistat/core_ext/time'
require 'redistat/core_ext/fixnum'
require 'redistat/core_ext/bignum'
module Redistat module Redistat
KEY_NEXT_ID = ".next_id" KEY_NEXT_ID = ".next_id"
KEY_EVENT = ".event:" KEY_EVENT = ".event:"
KEY_LEBELS = "Redistat.labels:" # used for reverse label hash lookup KEY_LABELS = "Redistat.labels:" # used for reverse label hash lookup
KEY_EVENT_IDS = ".event_ids" KEY_EVENT_IDS = ".event_ids"
LABEL_INDEX = ".label_index:" LABEL_INDEX = ".label_index:"
GROUP_SEPARATOR = "/" GROUP_SEPARATOR = "/"

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

@@ -1,3 +1,5 @@
require 'redistat/finder/date_set'
module Redistat module Redistat
class Finder class Finder
include Database include Database
@@ -69,6 +71,10 @@ module Redistat
all.each_with_index(&block) all.each_with_index(&block)
end end
def parent
@parent ||= self.class.new(options.merge(:label => options[:label].parent)) unless options[:label].nil?
end
def children def children
build_key.children.map { |key| build_key.children.map { |key|
self.class.new(options.merge(:label => key.label.to_s)) self.class.new(options.merge(:label => key.label.to_s))
@@ -88,8 +94,8 @@ module Redistat
end end
def label(label) def label(label)
reset! if !options[:label].nil? && options[:label].to_s != label reset! if options.has_key?(:label) && options[:label].to_s != label.to_s
options[:label] = Label.new(label) options[:label] = (!label.nil?) ? Label.new(label) : nil
self self
end end
@@ -181,6 +187,7 @@ module Redistat
def reset! def reset!
@result = nil @result = nil
@parent = nil
end end
def valid_options? def valid_options?

View File

@@ -66,7 +66,7 @@ module Redistat
end end
end end
def groups # TODO: Is this useless? def groups
@groups ||= @label.groups.map do |label| @groups ||= @label.groups.map do |label|
self.class.new(@scope, label, self.date, @options) self.class.new(@scope, label, self.date, @options)
end end

View File

@@ -29,7 +29,7 @@ module Redistat
end end
def save def save
@saved = db.hset(KEY_LEBELS, hash, self.to_s) if @options[:hashed_label] @saved = db.hset(KEY_LABELS, hash, self.to_s) if @options[:hashed_label]
self self
end end

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,3 @@
module Redistat module Redistat
VERSION = "0.2.0" VERSION = "0.2.2"
end end

View File

@@ -27,5 +27,4 @@ Gem::Specification.new do |s|
s.add_development_dependency 'rspec', '>= 2.1.0' s.add_development_dependency 'rspec', '>= 2.1.0'
s.add_development_dependency 'rcov', '>= 0.9.9' s.add_development_dependency 'rcov', '>= 0.9.9'
s.add_development_dependency 'yard', '>= 0.6.3' s.add_development_dependency 'yard', '>= 0.6.3'
s.add_development_dependency 'ruby-debug'
end 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

@@ -44,8 +44,11 @@ describe Redistat::Finder do
finder = Redistat::Finder.depth(:hour) finder = Redistat::Finder.depth(:hour)
finder.options[:depth].should == :hour finder.options[:depth].should == :hour
finder = Redistat::Finder.interval(:hour) finder = Redistat::Finder.interval(true)
finder.options[:interval].should == :hour finder.options[:interval].should be_true
finder = Redistat::Finder.interval(false)
finder.options[:interval].should be_false
end end
@@ -91,19 +94,36 @@ describe Redistat::Finder do
lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions) lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions)
end end
it "should find children" do describe "Grouping" do
Redistat::Key.new("PageViews", "message/public/die").update_index before(:each) do
Redistat::Key.new("PageViews", "message/public/live").update_index @options = {:scope => "PageViews", :label => "message/public", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
Redistat::Key.new("PageViews", "message/public/fester").update_index @finder = Redistat::Finder.new(@options)
members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}message/public") # checking 'message/public' end
options = {:scope => "PageViews", :label => "message/public", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
finder = Redistat::Finder.new(options) it "should return parent finder" do
finder.children.first.should be_a(Redistat::Finder) @finder.instance_variable_get("@parent").should be_nil
subs = finder.children.map { |f| f.options[:label].me } @finder.parent.should be_a(Redistat::Finder)
subs.should have(3).items @finder.instance_variable_get("@parent").should_not be_nil
subs.should include('die') @finder.parent.options[:label].to_s.should == 'message'
subs.should include('live') @finder.label('message')
subs.should include('fester') @finder.instance_variable_get("@parent").should be_nil
@finder.parent.should_not be_nil
@finder.parent.options[:label].should be_nil
@finder.parent.parent.should be_nil
end
it "should find children" do
Redistat::Key.new("PageViews", "message/public/die").update_index
Redistat::Key.new("PageViews", "message/public/live").update_index
Redistat::Key.new("PageViews", "message/public/fester").update_index
members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}message/public") # checking 'message/public'
@finder.children.first.should be_a(Redistat::Finder)
subs = @finder.children.map { |f| f.options[:label].me }
subs.should have(3).items
subs.should include('die')
subs.should include('live')
subs.should include('fester')
end
end end
describe "Lazy-Loading" do describe "Lazy-Loading" do

View File

@@ -17,12 +17,12 @@ describe Redistat::Label do
it "should store a label hash lookup key" do it "should store a label hash lookup key" do
label = Redistat::Label.new(@name, {:hashed_label => true}).save label = Redistat::Label.new(@name, {:hashed_label => true}).save
label.saved?.should be_true label.saved?.should be_true
db.hget(Redistat::KEY_LEBELS, label.hash).should == @name db.hget(Redistat::KEY_LABELS, label.hash).should == @name
name = "contact_us" name = "contact_us"
label = Redistat::Label.create(name, {:hashed_label => true}) label = Redistat::Label.create(name, {:hashed_label => true})
label.saved?.should be_true label.saved?.should be_true
db.hget(Redistat::KEY_LEBELS, label.hash).should == name db.hget(Redistat::KEY_LABELS, label.hash).should == name
end end
describe "Grouping" do describe "Grouping" do