counter 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -67,11 +67,15 @@ See Counter docs for detail.
67
67
  c.increment('another-key')
68
68
  end
69
69
 
70
- # Contribute to totals.
70
+ # Both contribute to totals grouped by category.
71
71
  PageView.totals
72
72
  => [['a-key',3],['another-key',1]]
73
73
 
74
- See MovingCount docs for detail.
74
+ # Get the grand total across all categories.
75
+ PageView.grand_total
76
+ => 4
77
+
78
+ See MovingCount docs for detail (filters available on totals to limit results).
75
79
 
76
80
  == Author
77
81
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.2
1
+ 0.5.3
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{counter}
8
- s.version = "0.5.2"
8
+ s.version = "0.5.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Koski"]
12
- s.date = %q{2010-07-29}
12
+ s.date = %q{2010-08-11}
13
13
  s.description = %q{count things, either as a one-off or aggregated over time}
14
14
  s.email = %q{bkoski@nytimes.com}
15
15
  s.extra_rdoc_files = [
@@ -88,10 +88,49 @@ class MovingCount < ActiveRecord::Base
88
88
  true
89
89
  end
90
90
 
91
- # Returns totals across entire history. Optional limit param restricts resultset.
92
- def self.totals limit=nil
93
- values = self.connection.select_rows("SELECT category, SUM(count) AS cnt FROM #{self.table_name} GROUP BY category ORDER BY cnt DESC #{"LIMIT #{limit}" if limit};")
91
+ # Returns single sum across all categories, limited by options. Use this to get, say, total across all categories matching "http://myhost..."
92
+ # Optional filters:
93
+ # * <tt>:window</tt> limits totaled to samples to those in the past <em>n</em> seconds (can of course specify as 1.hour with ActiveSupport)
94
+ # * <tt>:category_like</tt> run a LIKE match against categories before totaling, useful for limiting scope of totals. '%' wildcards are allowed.
95
+ def self.grand_total opts={}
96
+ latest_sample = self.maximum(:sample_time)
97
+ return 0 if latest_sample.nil? # don't try to run counts against empty db
98
+
99
+ q = "SELECT SUM(count) FROM #{self.table_name}"
100
+
101
+ where = []
102
+ where << self.sanitize_sql(['category LIKE ?', opts[:category_like]]) if opts[:category_like]
103
+ where << self.sanitize_sql(['sample_time > ?', latest_sample - opts[:window]]) if opts[:window]
104
+
105
+ q += " WHERE #{where.join(' AND ')}" unless where.empty?
106
+
107
+ self.connection.select_value(q).to_i
108
+ end
109
+
110
+ # Returns totals grouped by category across entire history.
111
+ # Optional filters can be used to filter totals:
112
+ # * <tt>:limit</tt> limits results to top <em>n</em>
113
+ # * <tt>:window</tt> limits totaled to samples to those in the past <em>n</em> seconds (can of course specify as 1.hour with ActiveSupport)
114
+ # * <tt>:category_like</tt> run a LIKE match against categories before totaling, useful for limiting scope of totals. '%' wildcards are allowed.
115
+ def self.totals opts={}
116
+ latest_sample = self.maximum(:sample_time)
117
+ return [] if latest_sample.nil? # don't try to run counts against empty db
118
+
119
+ q = "SELECT category, SUM(count) AS cnt FROM #{self.table_name}"
120
+
121
+ where = []
122
+ where << self.sanitize_sql(['category LIKE ?', opts[:category_like]]) if opts[:category_like]
123
+ where << self.sanitize_sql(['sample_time > ?', latest_sample - opts[:window]]) if opts[:window]
124
+
125
+ q += " WHERE #{where.join(' AND ')}" unless where.empty?
126
+
127
+ q += ' GROUP BY category'
128
+ q += ' ORDER BY cnt DESC'
129
+ q += " LIMIT #{opts[:limit]}" if opts[:limit]
130
+
131
+ values = self.connection.select_rows(q)
94
132
  values.map { |v| v[1] = v[1].to_i }
133
+
95
134
  return values
96
135
  end
97
136
 
@@ -111,12 +111,61 @@ class MovingCountTest < Test::Unit::TestCase
111
111
  assert_equal [['http://www.nytimes.com',3],['http://www.nytimes.com/article.html',1]], PageView.totals
112
112
  end
113
113
 
114
+ should "match against category_like if provided" do
115
+ setup_existing_counts(10.minutes)
116
+ setup_existing_counts(5.minutes)
117
+ PageView.record_counts { |c| c.saw('http://www.nytimes.com'); c.saw('http://www.nytimes.com/article.html') }
118
+
119
+ assert_equal [['http://www.nytimes.com/article.html',1]],
120
+ PageView.totals(:category_like => 'http://www.nytimes.com/article%')
121
+ end
122
+
123
+ should "filter to window if provided" do
124
+ setup_existing_counts(10.minutes)
125
+ setup_existing_counts(5.minutes)
126
+
127
+ assert_equal [['http://www.nytimes.com',1]], PageView.totals(:window => 5.minutes)
128
+ end
129
+
114
130
  should "respect limit if provided" do
115
131
  setup_existing_counts(10.minutes)
116
132
  setup_existing_counts(5.minutes)
117
133
  PageView.record_counts { |c| c.saw('http://www.nytimes.com'); c.saw('http://www.nytimes.com/article.html') }
118
134
 
119
- assert_equal [['http://www.nytimes.com',3]], PageView.totals(1)
135
+ assert_equal [['http://www.nytimes.com',3]], PageView.totals(:limit => 1)
136
+ end
137
+
138
+ should "return an empty array if no data has been recorded" do
139
+ assert_equal [], PageView.totals
140
+ end
141
+ end
142
+
143
+ context "grand total" do
144
+
145
+ should "return total sum across all samples" do
146
+ setup_existing_counts(10.minutes)
147
+ setup_existing_counts(5.minutes)
148
+
149
+ assert_equal 2, PageView.grand_total
150
+ end
151
+
152
+ should "match against category_like if providedd" do
153
+ setup_existing_counts(10.minutes)
154
+ setup_existing_counts(5.minutes)
155
+ PageView.record_counts { |c| c.saw('http://www.nytimes.com'); c.saw('http://www.nytimes.com/article.html') }
156
+
157
+ assert_equal 1, PageView.grand_total(:category_like => 'http://www.nytimes.com/article%')
158
+ end
159
+
160
+ should "filter to window if provided" do
161
+ setup_existing_counts(10.minutes)
162
+ setup_existing_counts(5.minutes)
163
+
164
+ assert_equal 1, PageView.grand_total(:window => 5.minutes)
165
+ end
166
+
167
+ should "return 0 if no data has been recorded" do
168
+ assert_equal 0, PageView.grand_total
120
169
  end
121
170
  end
122
171
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: counter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Koski
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-07-29 00:00:00 -04:00
12
+ date: 2010-08-11 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency