20 Commits

Author SHA1 Message Date
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
19 changed files with 146 additions and 60 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,10 +31,7 @@ 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

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}" event = db.hgetall "#{scope}#{KEY_EVENT}#{id}"
return nil if event.size == 0 return nil if event.size == 0
self.new( event["scope"], event["label"], event["date"], JSON.parse(event["stats"]), 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
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
@@ -79,49 +81,56 @@ module Redistat
} }
end end
def connection_ref(ref) def connection_ref(ref = nil)
return options[:connection_ref] if ref.nil?
reset! if options[:connection_ref] != ref reset! if options[:connection_ref] != ref
options[:connection_ref] = ref options[:connection_ref] = ref
self self
end end
def scope(scope) def scope(input = nil)
reset! if !options[:scope].nil? && options[:scope].to_s != scope return options[:scope] if input.nil?
options[:scope] = Scope.new(scope) reset! if !options[:scope].nil? && options[:scope].to_s != input.to_s
options[:scope] = Scope.new(input)
self self
end end
def label(label) def label(input = nil)
reset! if options.has_key?(:label) && options[:label].to_s != label.to_s return options[:label] if input.nil?
options[:label] = (!label.nil?) ? Label.new(label) : nil reset! if options.has_key?(:label) && options[:label].to_s != input.to_s
options[:label] = (!input.nil?) ? Label.new(input) : nil
self self
end end
def dates(from, till) def dates(start, finish)
from(from).till(till) from(start).till(finish)
end end
alias :date :dates alias :date :dates
def from(date) def from(date = nil)
return options[:from] if date.nil?
reset! if options[:from] != date reset! if options[:from] != date
options[:from] = date options[:from] = date
self self
end end
def till(date) def till(date = nil)
return options[:till] if date.nil?
reset! if options[:till] != date reset! if options[:till] != date
options[:till] = date options[:till] = date
self self
end end
alias :until :till alias :until :till
def depth(unit) def depth(unit = nil)
return options[:depth] if unit.nil?
reset! if options[:depth] != unit reset! if options[:depth] != unit
options[:depth] = unit options[:depth] = unit
self self
end end
def interval(unit) def interval(unit = nil)
return options[:interval] if unit.nil?
reset! if options[:interval] != unit reset! if options[:interval] != unit
options[:interval] = unit options[:interval] = unit
self self

View File

@@ -9,6 +9,10 @@ module Redistat
end end
def find_date_sets(start_date, end_date, depth = nil, interval = false) 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) start_date = start_date.to_time if start_date.is_a?(::Date)
end_date = end_date.to_time if end_date.is_a?(::Date) end_date = end_date.to_time if end_date.is_a?(::Date)
if !interval if !interval

View File

@@ -30,13 +30,14 @@ module Redistat
options[:depth] options[:depth]
end end
def scope # def scope
@scope.to_s # @scope.to_s
end # end
def scope=(input) def scope=(input)
@scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input) @scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)
end end
attr_reader :scope
def label=(input) def label=(input)
@label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options) @label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)

View File

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

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.1" VERSION = "0.2.3"
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

@@ -8,8 +8,8 @@ describe Redistat::Event do
@scope = "PageViews" @scope = "PageViews"
@label = "about_us" @label = "about_us"
@label_hash = Digest::SHA1.hexdigest(@label) @label_hash = Digest::SHA1.hexdigest(@label)
@stats = {:views => 1} @stats = {'views' => 1}
@meta = {:user_id => 239} @meta = {'user_id' => 239}
@options = {:depth => :hour} @options = {:depth => :hour}
@date = Time.now @date = Time.now
@event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta) @event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta)
@@ -17,7 +17,7 @@ describe Redistat::Event do
it "should initialize properly" do it "should initialize properly" do
@event.id.should be_nil @event.id.should be_nil
@event.scope.should == @scope @event.scope.to_s.should == @scope
@event.label.to_s.should == @label @event.label.to_s.should == @label
@event.label_hash.should == @label_hash @event.label_hash.should == @label_hash
@event.date.to_time.to_s.should == @date.to_s @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 it "should find event by id" do
@event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save @event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save
fetched = Redistat::Event.find(@scope, @event.id) 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.label.to_s.should == fetched.label.to_s
@event.date.to_s.should == fetched.date.to_s @event.date.to_s.should == fetched.date.to_s
@event.stats.should == fetched.stats
@event.meta.should == fetched.meta
end end
it "should store summarized statistics" do 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 = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :hour, true)
result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"] result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"]
result[0][:rem].should == [] result[0][:rem].should == []
result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :hour)
t_end = t_start + 4.days t_end = t_start + 4.days
result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :day, true) 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][:add].should == ["20100828", "20100829", "20100830", "20100831", "20100901"]
result[0][:rem].should == [] result[0][:rem].should == []
result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :day)
end end
it "should find start keys properly" do 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[:label].to_s.should == options[:label]
finder.options.should == options.merge(:scope => finder.options[:scope], :label => finder.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 = Redistat::Finder.dates(@two_hours_ago, @one_hour_ago)
finder.options[:from].should == @two_hours_ago finder.options[:from].should == @two_hours_ago
finder.options[:till].should == @one_hour_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 = Redistat::Finder.from(@two_hours_ago)
finder.options[:from].should == @two_hours_ago finder.options[:from].should == @two_hours_ago
finder.from.should == @two_hours_ago
finder = Redistat::Finder.till(@one_hour_ago) finder = Redistat::Finder.till(@one_hour_ago)
finder.options[:till].should == @one_hour_ago finder.options[:till].should == @one_hour_ago
finder.till.should == @one_hour_ago
finder = Redistat::Finder.depth(:hour) finder = Redistat::Finder.depth(:hour)
finder.options[:depth].should == :hour finder.options[:depth].should == :hour
finder.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.interval.should be_true
finder = Redistat::Finder.interval(false)
finder.options[:interval].should be_false
finder.interval.should be_false
end end
it "should fetch stats properly" do it "should fetch stats properly" do

View File

@@ -13,7 +13,7 @@ describe Redistat::Key do
end end
it "should initialize properly" do it "should initialize properly" do
@key.scope.should == @scope @key.scope.to_s.should == @scope
@key.label.to_s.should == @label @key.label.to_s.should == @label
@key.label_hash.should == @label_hash @key.label_hash.should == @label_hash
@key.groups.map { |k| k.instance_variable_get("@label") }.should == @key.instance_variable_get("@label").groups @key.groups.map { |k| k.instance_variable_get("@label") }.should == @key.instance_variable_get("@label").groups
@@ -44,10 +44,10 @@ describe Redistat::Key do
it "should allow changing attributes" do it "should allow changing attributes" do
# scope # scope
@key.scope.should == @scope @key.scope.to_s.should == @scope
@scope = "VisitorCount" @scope = "VisitorCount"
@key.scope = @scope @key.scope = @scope
@key.scope.should == @scope @key.scope.to_s.should == @scope
# date # date
@key.date.to_time.to_s.should == @date.to_s @key.date.to_time.to_s.should == @date.to_s
@date = Time.now @date = Time.now

View File

@@ -28,6 +28,11 @@ describe Redistat::Model do
finder.options[:till].should == one_hour_ago finder.options[:till].should == one_hour_ago
end 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 it "should listen to model-defined options" do
ModelHelper2.depth.should == :day ModelHelper2.depth.should == :day
ModelHelper2.store_event.should == true ModelHelper2.store_event.should == true