redistat 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Jim Myhrberg.
1
+ Copyright (c) 2011 Jim Myhrberg.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -79,7 +79,7 @@ When retrieving statistics for a given date range, Redistat figures out how to d
79
79
 
80
80
  ## License and Copyright
81
81
 
82
- Copyright (c) 2010 Jim Myhrberg.
82
+ Copyright (c) 2011 Jim Myhrberg.
83
83
 
84
84
  Permission is hereby granted, free of charge, to any person obtaining
85
85
  a copy of this software and associated documentation files (the
@@ -2,23 +2,119 @@ module Redistat
2
2
  class Finder
3
3
  include Database
4
4
 
5
+ class << self
6
+ def find(*args)
7
+ new.find(*args)
8
+ end
9
+
10
+ def scope(scope)
11
+ new.scope(scope)
12
+ end
13
+
14
+ def label(label)
15
+ new.label(label)
16
+ end
17
+
18
+ def dates(from, till)
19
+ new.dates(from, till)
20
+ end
21
+ alias :date :dates
22
+
23
+ def from(date)
24
+ new.from(date)
25
+ end
26
+
27
+ def till(date)
28
+ new.till(date)
29
+ end
30
+ alias :untill :till
31
+
32
+ def depth(unit)
33
+ new.depth(unit)
34
+ end
35
+
36
+ def interval(unit)
37
+ new.interval(unit)
38
+ end
39
+ end
40
+
5
41
  attr_reader :options
6
42
 
7
43
  def initialize(options = {})
8
44
  @options = options
9
45
  end
10
46
 
11
- def db
12
- super(@options[:connection_ref])
47
+ def all(reload = false)
48
+ @result = nil if reload
49
+ @result ||= find
13
50
  end
14
51
 
15
- def valid_options?
16
- return true if !@options[:scope].blank? && !@options[:label].blank? && !@options[:from].blank? && !@options[:till].blank?
17
- false
52
+ def total
53
+ all.total
54
+ end
55
+
56
+ def each(&block)
57
+ all.each(&block)
58
+ end
59
+
60
+ def map(&block)
61
+ all.map(&block)
62
+ end
63
+
64
+ def each_with_index(&block)
65
+ all.each_with_index(&block)
66
+ end
67
+
68
+ def connection_ref(ref)
69
+ reset! if @options[:connection_ref] != ref
70
+ @options[:connection_ref] = ref
71
+ self
72
+ end
73
+
74
+ def scope(scope)
75
+ reset! if @options[:scope] != scope
76
+ @options[:scope] = scope
77
+ self
78
+ end
79
+
80
+ def label(label)
81
+ reset! if @options[:label] != label
82
+ @options[:label] = label
83
+ self
84
+ end
85
+
86
+ def dates(from, till)
87
+ from(from).till(till)
88
+ end
89
+ alias :date :dates
90
+
91
+ def from(date)
92
+ reset! if @options[:from] != date
93
+ @options[:from] = date
94
+ self
95
+ end
96
+
97
+ def till(date)
98
+ reset! if @options[:till] != date
99
+ @options[:till] = date
100
+ self
101
+ end
102
+ alias :until :till
103
+
104
+ def depth(unit)
105
+ reset! if @options[:depth] != unit
106
+ @options[:depth] = unit
107
+ self
108
+ end
109
+
110
+ def interval(unit)
111
+ reset! if @options[:interval] != unit
112
+ @options[:interval] = unit
113
+ self
18
114
  end
19
115
 
20
116
  def find(options = {})
21
- @options.merge!(options)
117
+ set_options(options)
22
118
  raise InvalidOptions.new if !valid_options?
23
119
  if @options[:interval].nil? || !@options[:interval]
24
120
  find_by_magic
@@ -27,8 +123,17 @@ module Redistat
27
123
  end
28
124
  end
29
125
 
126
+ private
127
+
128
+ def set_options(opts = {})
129
+ opts = opts.clone
130
+ opts.each do |key, value|
131
+ self.send(key, opts.delete(key)) if self.respond_to?(key)
132
+ end
133
+ @options.merge!(opts)
134
+ end
135
+
30
136
  def find_by_interval(options = {})
31
- @options.merge!(options)
32
137
  raise InvalidOptions.new if !valid_options?
33
138
  key = build_key
34
139
  col = Collection.new(@options)
@@ -48,7 +153,6 @@ module Redistat
48
153
  end
49
154
 
50
155
  def find_by_magic(options = {})
51
- @options.merge!(options)
52
156
  raise InvalidOptions.new if !valid_options?
53
157
  key = Key.new(@options[:scope], @options[:label])
54
158
  col = Collection.new(@options)
@@ -64,6 +168,15 @@ module Redistat
64
168
  end
65
169
  col
66
170
  end
171
+
172
+ def reset!
173
+ @result = nil
174
+ end
175
+
176
+ def valid_options?
177
+ return true if !@options[:scope].blank? && !@options[:label].blank? && !@options[:from].blank? && !@options[:till].blank?
178
+ false
179
+ end
67
180
 
68
181
  def build_date_sets
69
182
  Finder::DateSet.new(@options[:from], @options[:till], @options[:depth], @options[:interval])
@@ -91,78 +204,8 @@ module Redistat
91
204
  sum
92
205
  end
93
206
 
94
- class << self
95
-
96
- def find(*args)
97
- new.find(*args)
98
- end
99
-
100
- def scope(scope)
101
- new.scope(scope)
102
- end
103
-
104
- def label(label)
105
- new.label(label)
106
- end
107
-
108
- def dates(from, till)
109
- new.dates(from, till)
110
- end
111
- alias :date :dates
112
-
113
- def from(date)
114
- new.from(date)
115
- end
116
-
117
- def till(date)
118
- new.till(date)
119
- end
120
- alias :untill :till
121
-
122
- def depth(unit)
123
- new.depth(unit)
124
- end
125
-
126
- def interval(unit)
127
- new.interval(unit)
128
- end
129
-
130
- end
131
-
132
- def scope(scope)
133
- @options[:scope] = scope
134
- self
135
- end
136
-
137
- def label(label)
138
- @options[:label] = label
139
- self
140
- end
141
-
142
- def dates(from, till)
143
- from(from).till(till)
144
- end
145
- alias :date :dates
146
-
147
- def from(date)
148
- @options[:from] = date
149
- self
150
- end
151
-
152
- def till(date)
153
- @options[:till] = date
154
- self
155
- end
156
- alias :until :till
157
-
158
- def depth(unit)
159
- @options[:depth] = unit
160
- self
161
- end
162
-
163
- def interval(unit)
164
- @options[:interval] = unit
165
- self
207
+ def db
208
+ super(@options[:connection_ref])
166
209
  end
167
210
 
168
211
  end
@@ -6,31 +6,36 @@ module Redistat
6
6
  base.extend(self)
7
7
  end
8
8
 
9
+ #
10
+ # statistics store/fetch methods
11
+ #
12
+
9
13
  def store(label, stats = {}, date = nil, meta = {}, opts = {})
10
14
  Event.new(name, label, date, stats, options.merge(opts), meta).save
11
15
  end
12
16
  alias :event :store
17
+
18
+ def fetch(label, from, till, opts = {})
19
+ find(label, from, till, opts).all
20
+ end
21
+ alias :lookup :fetch
22
+
23
+ def find(label, from, till, opts = {})
24
+ Finder.new( { :scope => name,
25
+ :label => label,
26
+ :from => from,
27
+ :till => till }.merge(options.merge(opts)) )
28
+ end
29
+
30
+ #
31
+ # options methods
32
+ #
13
33
 
14
34
  def connect_to(opts = {})
15
35
  Connection.create(opts.merge(:ref => name))
16
36
  options[:connection_ref] = name
17
37
  end
18
38
 
19
- def connection
20
- db(options[:connection_ref])
21
- end
22
- alias :redis :connection
23
-
24
- def fetch(label, from, till, opts = {})
25
- Finder.find({
26
- :scope => name,
27
- :label => label,
28
- :from => from,
29
- :till => till
30
- }.merge(options.merge(opts)))
31
- end
32
- alias :lookup :fetch
33
-
34
39
  def hashed_label(boolean = nil)
35
40
  if !boolean.nil?
36
41
  options[:hashed_label] = boolean
@@ -64,15 +69,22 @@ module Redistat
64
69
  end
65
70
  end
66
71
 
72
+ #
73
+ # resource access methods
74
+ #
75
+
76
+ def connection
77
+ db(options[:connection_ref])
78
+ end
79
+ alias :redis :connection
80
+
67
81
  def options
68
82
  @options ||= {}
69
83
  end
70
84
 
71
- private
72
-
73
85
  def name
74
86
  options[:class_name] || (@name ||= self.to_s)
75
87
  end
76
-
88
+
77
89
  end
78
90
  end
@@ -1,3 +1,3 @@
1
1
  module Redistat
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -19,6 +19,10 @@ describe Redistat::Finder do
19
19
 
20
20
  finder = Redistat::Finder.new(options)
21
21
  finder.options.should == options
22
+
23
+ finder = Redistat::Finder.new
24
+ finder.send(:set_options, options)
25
+ finder.options.should == options
22
26
 
23
27
  finder = Redistat::Finder.dates(two_hours_ago, one_hour_ago).scope("PageViews").label("Label").depth(:hour).interval(:hour)
24
28
  finder.options.should == options
@@ -85,6 +89,65 @@ describe Redistat::Finder do
85
89
  lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions)
86
90
  end
87
91
 
92
+ describe "Lazy-Loading" do
93
+
94
+ before(:each) do
95
+ @first_stat, @last_stat = create_example_stats
96
+
97
+ @finder = Redistat::Finder.new
98
+ @finder.from(@first_stat).till(@last_stat).scope(@scope).label(@label).depth(:hour)
99
+
100
+ @match = [{}, {"visitors"=>"4", "views"=>"6"},
101
+ {"visitors"=>"2", "views"=>"3"},
102
+ {"visitors"=>"2", "views"=>"3"}, {}]
103
+ end
104
+
105
+ it "should lazy-load" do
106
+
107
+ @finder.instance_variable_get("@result").should be_nil
108
+ stats = @finder.all
109
+ @finder.instance_variable_get("@result").should_not be_nil
110
+
111
+ stats.should == @finder.find # find method directly fetches results
112
+ stats.total.should == @finder.total
113
+ stats.total.should == { "views" => 12, "visitors" => 8 }
114
+ stats.total.from.should == @first_stat
115
+ stats.total.till.should == @last_stat
116
+ stats.first.should == stats.total
117
+
118
+ @finder.all.object_id.should == stats.object_id
119
+ @finder.from(@first_stat + 2.hours)
120
+ @finder.instance_variable_get("@result").should be_nil
121
+ @finder.all.object_id.should_not == stats.object_id
122
+ stats = @finder.all
123
+ stats.total.should == { "views" => 6, "visitors" => 4 }
124
+ end
125
+
126
+ it "should handle #map" do
127
+ @finder.interval(:hour)
128
+ @finder.map { |r| r }.should == @match
129
+ end
130
+
131
+ it "should handle #each" do
132
+ @finder.interval(:hour)
133
+
134
+ res = []
135
+ @finder.each { |r| res << r }
136
+ res.should == @match
137
+ end
138
+
139
+ it "should handle #each_with_index" do
140
+ @finder.interval(:hour)
141
+
142
+ res = {}
143
+ match = {}
144
+ @finder.each_with_index { |r, i| res[i] = r }
145
+ @match.each_with_index { |r, i| match[i] = r }
146
+ res.should == match
147
+ end
148
+
149
+ end
150
+
88
151
 
89
152
  # helper methods
90
153
 
@@ -93,7 +156,7 @@ describe Redistat::Finder do
93
156
  Redistat::Summary.update(key, @stats, :hour)
94
157
  key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 13:53"))
95
158
  Redistat::Summary.update(key, @stats, :hour)
96
- key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 14:32"))
159
+ key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 14:52"))
97
160
  Redistat::Summary.update(key, @stats, :hour)
98
161
  key = Redistat::Key.new(@scope, @label, (last = Time.parse("2010-05-14 15:02")))
99
162
  Redistat::Summary.update(key, @stats, :hour)
@@ -5,6 +5,7 @@ describe Redistat::Model do
5
5
  include Redistat::Database
6
6
 
7
7
  before(:each) do
8
+ @time = Time.utc(2010, 8, 28, 12, 0, 0)
8
9
  ModelHelper1.redis.flushdb
9
10
  ModelHelper2.redis.flushdb
10
11
  ModelHelper3.redis.flushdb
@@ -16,6 +17,17 @@ describe Redistat::Model do
16
17
  ModelHelper2.send(:name).should == "ModelHelper2"
17
18
  end
18
19
 
20
+ it "should return a Finder" do
21
+ two_hours_ago = 2.hours.ago
22
+ one_hour_ago = 1.hour.ago
23
+ finder = ModelHelper1.find('label', two_hours_ago, one_hour_ago)
24
+ finder.should be_a(Redistat::Finder)
25
+ finder.options[:scope].should == 'ModelHelper1'
26
+ finder.options[:label].should == 'label'
27
+ finder.options[:from].should == two_hours_ago
28
+ finder.options[:till].should == one_hour_ago
29
+ end
30
+
19
31
  it "should listen to model-defined options" do
20
32
  ModelHelper2.depth.should == :day
21
33
  ModelHelper2.store_event.should == true
@@ -43,28 +55,28 @@ describe Redistat::Model do
43
55
  end
44
56
 
45
57
  it "should store and fetch stats" do
46
- ModelHelper1.store("sheep.black", {:count => 6, :weight => 461}, 4.hours.ago)
47
- ModelHelper1.store("sheep.black", {:count => 2, :weight => 156})
58
+ ModelHelper1.store("sheep.black", {:count => 6, :weight => 461}, @time.hours_ago(4))
59
+ ModelHelper1.store("sheep.black", {:count => 2, :weight => 156}, @time)
48
60
 
49
- stats = ModelHelper1.fetch("sheep.black", 2.hours.ago, 1.hour.from_now)
61
+ stats = ModelHelper1.fetch("sheep.black", @time.hours_ago(2), @time.hours_since(1))
50
62
  stats.total["count"].should == 2
51
63
  stats.total["weight"].should == 156
52
64
  stats.first.should == stats.total
53
65
 
54
- stats = ModelHelper1.fetch("sheep.black", 5.hours.ago, 1.hour.from_now)
66
+ stats = ModelHelper1.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
55
67
  stats.total[:count].should == 8
56
68
  stats.total[:weight].should == 617
57
69
  stats.first.should == stats.total
58
70
 
59
- ModelHelper1.store("sheep.white", {:count => 5, :weight => 393}, 4.hours.ago)
60
- ModelHelper1.store("sheep.white", {:count => 4, :weight => 316})
71
+ ModelHelper1.store("sheep.white", {:count => 5, :weight => 393}, @time.hours_ago(4))
72
+ ModelHelper1.store("sheep.white", {:count => 4, :weight => 316}, @time)
61
73
 
62
- stats = ModelHelper1.fetch("sheep.white", 2.hours.ago, 1.hour.from_now)
74
+ stats = ModelHelper1.fetch("sheep.white", @time.hours_ago(2), @time.hours_since(1))
63
75
  stats.total[:count].should == 4
64
76
  stats.total[:weight].should == 316
65
77
  stats.first.should == stats.total
66
78
 
67
- stats = ModelHelper1.fetch("sheep.white", 5.hours.ago, 1.hour.from_now)
79
+ stats = ModelHelper1.fetch("sheep.white", @time.hours_ago(5), @time.hours_since(1))
68
80
  stats.total[:count].should == 9
69
81
  stats.total[:weight].should == 709
70
82
  stats.first.should == stats.total
@@ -73,31 +85,31 @@ describe Redistat::Model do
73
85
  it "should connect to different Redis servers on a per-model basis" do
74
86
  ModelHelper3.redis.client.db.should == 14
75
87
 
76
- ModelHelper3.store("sheep.black", {:count => 6, :weight => 461}, 4.hours.ago)
77
- ModelHelper3.store("sheep.black", {:count => 2, :weight => 156})
88
+ ModelHelper3.store("sheep.black", {:count => 6, :weight => 461}, @time.hours_ago(4))
89
+ ModelHelper3.store("sheep.black", {:count => 2, :weight => 156}, @time)
78
90
 
79
91
  db.keys("*").should be_empty
80
92
  ModelHelper1.redis.keys("*").should be_empty
81
93
  db("ModelHelper3").keys("*").should have(5).items
82
94
  ModelHelper3.redis.keys("*").should have(5).items
83
95
 
84
- stats = ModelHelper3.fetch("sheep.black", 2.hours.ago, 1.hour.from_now)
96
+ stats = ModelHelper3.fetch("sheep.black", @time.hours_ago(2), @time.hours_since(1))
85
97
  stats.total["count"].should == 2
86
98
  stats.total["weight"].should == 156
87
- stats = ModelHelper3.fetch("sheep.black", 5.hours.ago, 1.hour.from_now)
99
+ stats = ModelHelper3.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
88
100
  stats.total[:count].should == 8
89
101
  stats.total[:weight].should == 617
90
102
 
91
103
  ModelHelper3.connect_to(:port => 8379, :db => 13)
92
104
  ModelHelper3.redis.client.db.should == 13
93
105
 
94
- stats = ModelHelper3.fetch("sheep.black", 5.hours.ago, 1.hour.from_now)
106
+ stats = ModelHelper3.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
95
107
  stats.total.should == {}
96
108
 
97
109
  ModelHelper3.connect_to(:port => 8379, :db => 14)
98
110
  ModelHelper3.redis.client.db.should == 14
99
111
 
100
- stats = ModelHelper3.fetch("sheep.black", 5.hours.ago, 1.hour.from_now)
112
+ stats = ModelHelper3.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
101
113
  stats.total[:count].should == 8
102
114
  stats.total[:weight].should == 617
103
115
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redistat
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jim Myhrberg
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-04 00:00:00 +00:00
18
+ date: 2011-03-09 00:00:00 +00:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency