counter 0.5.2 → 0.5.3
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/README.rdoc +6 -2
- data/VERSION +1 -1
- data/counter.gemspec +2 -2
- data/lib/counter/moving_count.rb +42 -3
- data/test/test_moving_count.rb +50 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -67,11 +67,15 @@ See Counter docs for detail.
|
|
67
67
|
c.increment('another-key')
|
68
68
|
end
|
69
69
|
|
70
|
-
#
|
70
|
+
# Both contribute to totals grouped by category.
|
71
71
|
PageView.totals
|
72
72
|
=> [['a-key',3],['another-key',1]]
|
73
73
|
|
74
|
-
|
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.
|
1
|
+
0.5.3
|
data/counter.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{counter}
|
8
|
-
s.version = "0.5.
|
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-
|
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 = [
|
data/lib/counter/moving_count.rb
CHANGED
@@ -88,10 +88,49 @@ class MovingCount < ActiveRecord::Base
|
|
88
88
|
true
|
89
89
|
end
|
90
90
|
|
91
|
-
# Returns
|
92
|
-
|
93
|
-
|
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
|
|
data/test/test_moving_count.rb
CHANGED
@@ -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.
|
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-
|
12
|
+
date: 2010-08-11 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|