redisrank 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +27 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +297 -0
  8. data/Rakefile +69 -0
  9. data/lib/redisrank.rb +106 -0
  10. data/lib/redisrank/buffer.rb +110 -0
  11. data/lib/redisrank/collection.rb +20 -0
  12. data/lib/redisrank/connection.rb +89 -0
  13. data/lib/redisrank/core_ext.rb +5 -0
  14. data/lib/redisrank/core_ext/bignum.rb +8 -0
  15. data/lib/redisrank/core_ext/date.rb +8 -0
  16. data/lib/redisrank/core_ext/fixnum.rb +8 -0
  17. data/lib/redisrank/core_ext/hash.rb +20 -0
  18. data/lib/redisrank/core_ext/time.rb +3 -0
  19. data/lib/redisrank/date.rb +88 -0
  20. data/lib/redisrank/event.rb +98 -0
  21. data/lib/redisrank/finder.rb +245 -0
  22. data/lib/redisrank/finder/date_set.rb +99 -0
  23. data/lib/redisrank/key.rb +84 -0
  24. data/lib/redisrank/label.rb +69 -0
  25. data/lib/redisrank/mixins/database.rb +11 -0
  26. data/lib/redisrank/mixins/date_helper.rb +8 -0
  27. data/lib/redisrank/mixins/options.rb +41 -0
  28. data/lib/redisrank/mixins/synchronize.rb +52 -0
  29. data/lib/redisrank/model.rb +77 -0
  30. data/lib/redisrank/result.rb +18 -0
  31. data/lib/redisrank/scope.rb +18 -0
  32. data/lib/redisrank/summary.rb +90 -0
  33. data/lib/redisrank/version.rb +3 -0
  34. data/redisrank.gemspec +31 -0
  35. data/spec/Find Results +3349 -0
  36. data/spec/buffer_spec.rb +104 -0
  37. data/spec/collection_spec.rb +20 -0
  38. data/spec/connection_spec.rb +67 -0
  39. data/spec/core_ext/hash_spec.rb +26 -0
  40. data/spec/database_spec.rb +10 -0
  41. data/spec/date_spec.rb +95 -0
  42. data/spec/event_spec.rb +86 -0
  43. data/spec/finder/date_set_spec.rb +527 -0
  44. data/spec/finder_spec.rb +205 -0
  45. data/spec/key_spec.rb +129 -0
  46. data/spec/label_spec.rb +86 -0
  47. data/spec/model_helper.rb +31 -0
  48. data/spec/model_spec.rb +191 -0
  49. data/spec/options_spec.rb +36 -0
  50. data/spec/redis-test.conf +9 -0
  51. data/spec/result_spec.rb +23 -0
  52. data/spec/scope_spec.rb +27 -0
  53. data/spec/spec_helper.rb +18 -0
  54. data/spec/summary_spec.rb +177 -0
  55. data/spec/synchronize_spec.rb +125 -0
  56. data/spec/thread_safety_spec.rb +39 -0
  57. metadata +235 -0
@@ -0,0 +1,11 @@
1
+ module Redisrank
2
+ module Database
3
+ def self.included(base)
4
+ base.extend(Database)
5
+ end
6
+ def db(ref = nil)
7
+ ref ||= @options[:connection_ref] if !@options.nil?
8
+ Redisrank.connection(ref)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Redisrank
2
+ module DateHelper
3
+ def to_redisrank(depth = nil)
4
+ Redisrank::Date.new(self, depth)
5
+ end
6
+ alias :to_rs :to_redisrank
7
+ end
8
+ end
@@ -0,0 +1,41 @@
1
+ module Redisrank
2
+ module Options
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def option_accessor(*opts)
10
+ opts.each do |option|
11
+ define_method(option) do |*args|
12
+ if !args.first.nil?
13
+ options[option.to_sym] = args.first
14
+ else
15
+ options[option.to_sym] || nil
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def parse_options(opts)
23
+ opts ||= {}
24
+ @raw_options = opts
25
+ @options = default_options.merge(opts.reject { |k,v| v.nil? })
26
+ end
27
+
28
+ def default_options
29
+ {}
30
+ end
31
+
32
+ def options
33
+ @options ||= {}
34
+ end
35
+
36
+ def raw_options
37
+ @raw_options ||= {}
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,52 @@
1
+ require 'monitor'
2
+
3
+ module Redisrank
4
+ module Synchronize
5
+
6
+ class << self
7
+ def included(base)
8
+ base.send(:include, InstanceMethods)
9
+ end
10
+
11
+ def monitor
12
+ @monitor ||= Monitor.new
13
+ end
14
+
15
+ def thread_safe
16
+ monitor.synchronize do
17
+ return @thread_safe unless @thread_safe.nil?
18
+ @thread_safe = false
19
+ end
20
+ end
21
+
22
+ def thread_safe=(value)
23
+ monitor.synchronize do
24
+ @thread_safe = value
25
+ end
26
+ end
27
+ end # << self
28
+
29
+ module InstanceMethods
30
+ def thread_safe
31
+ Synchronize.thread_safe
32
+ end
33
+
34
+ def thread_safe=(value)
35
+ Synchronize.thread_safe = value
36
+ end
37
+
38
+ def monitor
39
+ Synchronize.monitor
40
+ end
41
+
42
+ def synchronize(&block)
43
+ if thread_safe
44
+ monitor.synchronize(&block)
45
+ else
46
+ block.call
47
+ end
48
+ end
49
+ end # InstanceMethods
50
+
51
+ end
52
+ end
@@ -0,0 +1,77 @@
1
+ module Redisrank
2
+ module Model
3
+ include Database
4
+ include Options
5
+
6
+ def self.included(base)
7
+ base.extend(self)
8
+ end
9
+
10
+
11
+ #
12
+ # statistics store/fetch methods
13
+ #
14
+
15
+ def store(label, stats = {}, date = nil, opts = {}, meta = {})
16
+ Event.new(self.name, label, date, stats, options.merge(opts), meta).save
17
+ end
18
+ alias :event :store
19
+
20
+ def fetch(label, from, till, opts = {})
21
+ find(label, from, till, opts).all
22
+ end
23
+ alias :lookup :fetch
24
+
25
+ def find(label, from, till, opts = {})
26
+ Finder.new( { :scope => self.name,
27
+ :label => label,
28
+ :from => from,
29
+ :till => till }.merge(options.merge(opts)) )
30
+ end
31
+
32
+ def find_event(event_id)
33
+ Event.find(self.name, event_id)
34
+ end
35
+
36
+
37
+ #
38
+ # options methods
39
+ #
40
+
41
+ option_accessor :depth
42
+ option_accessor :scope
43
+ option_accessor :store_event
44
+ option_accessor :hashed_label
45
+ option_accessor :label_indexing
46
+
47
+ alias :class_name :scope
48
+
49
+ def expire(exp = nil)
50
+ if !exp.nil?
51
+ options[:expire] = exp.is_a?(Hash) ? exp : Hash.new(exp)
52
+ else
53
+ options[:expire]
54
+ end
55
+ end
56
+
57
+ def connect_to(opts = {})
58
+ Connection.create(opts.merge(:ref => name))
59
+ options[:connection_ref] = name
60
+ end
61
+
62
+
63
+ #
64
+ # resource access methods
65
+ #
66
+
67
+ def connection
68
+ db(options[:connection_ref])
69
+ end
70
+ alias :redis :connection
71
+
72
+ def name
73
+ options[:scope] || (@name ||= self.to_s)
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,18 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+
3
+ module Redisrank
4
+ class Result < HashWithIndifferentAccess
5
+
6
+ attr_accessor :from
7
+ attr_accessor :till
8
+
9
+ alias :date :from
10
+ alias :date= :from=
11
+
12
+ def initialize(options = {})
13
+ @from = options[:from] ||= nil
14
+ @till = options[:till] ||= nil
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Redisrank
2
+ class Scope
3
+ include Database
4
+
5
+ def initialize(name)
6
+ @name = name.to_s
7
+ end
8
+
9
+ def to_s
10
+ @name
11
+ end
12
+
13
+ def next_id
14
+ db.incr("#{@name}#{KEY_NEXT_ID}")
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,90 @@
1
+ module Redisrank
2
+ class Summary
3
+ include Database
4
+
5
+ class << self
6
+
7
+ def default_options
8
+ {
9
+ :enable_grouping => true,
10
+ :label_indexing => true,
11
+ :connection_ref => nil,
12
+ :expire => {}
13
+ }
14
+ end
15
+
16
+ def buffer
17
+ Redisrank.buffer
18
+ end
19
+
20
+ def update_all(key, stats = {}, depth_limit = nil, opts = {})
21
+ stats ||= {}
22
+ return if stats.empty?
23
+
24
+ options = default_options.merge((opts || {}).reject { |k,v| v.nil? })
25
+
26
+ depth_limit ||= key.depth
27
+
28
+ update_through_buffer(key, stats, depth_limit, options)
29
+ end
30
+
31
+ def update_through_buffer(*args)
32
+ update(*args) unless buffer.store(*args)
33
+ end
34
+
35
+ def update(key, stats, depth_limit, opts = {})
36
+ if opts[:enable_grouping]
37
+ stats = inject_group_summaries(stats)
38
+ key.groups.each do |k|
39
+ update_key(k, stats, depth_limit, opts)
40
+ k.update_index if opts[:label_indexing]
41
+ end
42
+ else
43
+ update_key(key, stats, depth_limit, opts)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def update_key(key, stats, depth_limit, opts = {})
50
+ Date::DEPTHS.each do |depth|
51
+ update_fields(key, stats, depth, opts)
52
+ break if depth == depth_limit
53
+ end
54
+ end
55
+
56
+ def update_fields(key, stats, depth, opts = {})
57
+ stats.each do |member, score|
58
+ exists = db(opts[:connection_ref]).zscore(key.to_s(depth), member)
59
+ db(opts[:connection_ref]).zadd key.to_s(depth), score, member if (exists || 0) < score
60
+ end
61
+
62
+ if opts[:expire] && !opts[:expire][depth].nil?
63
+ db(opts[:connection_ref]).expire key.to_s(depth), opts[:expire][depth]
64
+ end
65
+ end
66
+
67
+ def inject_group_summaries!(stats)
68
+ summaries = {}
69
+ stats.each do |key, value|
70
+ parts = key.to_s.split(Redisrank.group_separator)
71
+ parts.pop
72
+ if parts.size > 0
73
+ sum_parts = []
74
+ parts.each do |part|
75
+ sum_parts << part
76
+ sum_key = sum_parts.join(Redisrank.group_separator)
77
+ (summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value
78
+ end
79
+ end
80
+ end
81
+ stats.merge_to_max!(summaries)
82
+ end
83
+
84
+ def inject_group_summaries(stats)
85
+ inject_group_summaries!(stats.clone)
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,3 @@
1
+ module Redisrank
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "redisrank/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redisrank"
7
+ s.version = Redisrank::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Felipe Lopes"]
10
+ s.email = ["felipelopes10@gmail.com"]
11
+ s.homepage = "http://github.com/felipeclopes/redisrank"
12
+ s.summary = %q{A Redis-backed ranking storage and querying library written in Ruby.}
13
+ s.description = %q{A Redis-backed ranking storage and querying library written in Ruby.}
14
+
15
+ s.rubyforge_project = "redisrank"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency 'activesupport', '>= 2.3.6'
23
+ s.add_runtime_dependency 'json', '>= 1.4.0'
24
+ s.add_runtime_dependency 'redis', '>= 2.1.0'
25
+ s.add_runtime_dependency 'time_ext', '>= 0.2.9'
26
+
27
+ s.add_development_dependency 'rake', '>= 0.8.7'
28
+ s.add_development_dependency 'rspec', '>= 2.1.0'
29
+ s.add_development_dependency 'yard', '>= 0.6.3'
30
+ s.add_development_dependency 'simplecov', '>= 0.6.1'
31
+ end
@@ -0,0 +1,3349 @@
1
+ Searching 85 files for "redisrank"
2
+
3
+ /Users/felipeclopes/projects/redisrank/coverage/.resultset.json:
4
+ 2 "RSpec": {
5
+ 3 "coverage": {
6
+ 4: "/Users/felipeclopes/projects/redisrank/lib/redisrank.rb": [
7
+ 5 null,
8
+ 6 1,
9
+ .
10
+ 110 null
11
+ 111 ],
12
+ 112: "/Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/options.rb": [
13
+ 113 1,
14
+ 114 1,
15
+ ...
16
+ 153 null
17
+ 154 ],
18
+ 155: "/Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/synchronize.rb": [
19
+ 156 1,
20
+ 157 null,
21
+ ...
22
+ 207 null
23
+ 208 ],
24
+ 209: "/Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/database.rb": [
25
+ 210 1,
26
+ 211 1,
27
+ ...
28
+ 220 null
29
+ 221 ],
30
+ 222: "/Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/date_helper.rb": [
31
+ 223 1,
32
+ 224 1,
33
+ ...
34
+ 230 null
35
+ 231 ],
36
+ 232: "/Users/felipeclopes/projects/redisrank/lib/redisrank/connection.rb": [
37
+ 233 1,
38
+ 234 null,
39
+ ...
40
+ 321 null
41
+ 322 ],
42
+ 323: "/Users/felipeclopes/projects/redisrank/lib/redisrank/buffer.rb": [
43
+ 324 1,
44
+ 325 null,
45
+ ...
46
+ 433 null
47
+ 434 ],
48
+ 435: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/hash.rb": [
49
+ 436 1,
50
+ 437 null,
51
+ ...
52
+ 455 null
53
+ 456 ],
54
+ 457: "/Users/felipeclopes/projects/redisrank/lib/redisrank/collection.rb": [
55
+ 458 1,
56
+ 459 1,
57
+ ...
58
+ 477 null
59
+ 478 ],
60
+ 479: "/Users/felipeclopes/projects/redisrank/lib/redisrank/date.rb": [
61
+ 480 1,
62
+ 481 1,
63
+ ...
64
+ 567 null
65
+ 568 ],
66
+ 569: "/Users/felipeclopes/projects/redisrank/lib/redisrank/event.rb": [
67
+ 570 1,
68
+ 571 1,
69
+ ...
70
+ 667 null
71
+ 668 ],
72
+ 669: "/Users/felipeclopes/projects/redisrank/lib/redisrank/finder.rb": [
73
+ 670 1,
74
+ 671 null,
75
+ ...
76
+ 914 null
77
+ 915 ],
78
+ 916: "/Users/felipeclopes/projects/redisrank/lib/redisrank/finder/date_set.rb": [
79
+ 917 1,
80
+ 918 1,
81
+ ...
82
+ 1015 null
83
+ 1016 ],
84
+ 1017: "/Users/felipeclopes/projects/redisrank/lib/redisrank/key.rb": [
85
+ 1018 1,
86
+ 1019 1,
87
+ ....
88
+ 1101 null
89
+ 1102 ],
90
+ 1103: "/Users/felipeclopes/projects/redisrank/lib/redisrank/label.rb": [
91
+ 1104 1,
92
+ 1105 1,
93
+ ....
94
+ 1172 null
95
+ 1173 ],
96
+ 1174: "/Users/felipeclopes/projects/redisrank/lib/redisrank/model.rb": [
97
+ 1175 1,
98
+ 1176 1,
99
+ ....
100
+ 1251 null
101
+ 1252 ],
102
+ 1253: "/Users/felipeclopes/projects/redisrank/lib/redisrank/result.rb": [
103
+ 1254 1,
104
+ 1255 null,
105
+ ....
106
+ 1271 null
107
+ 1272 ],
108
+ 1273: "/Users/felipeclopes/projects/redisrank/lib/redisrank/scope.rb": [
109
+ 1274 1,
110
+ 1275 1,
111
+ ....
112
+ 1291 null
113
+ 1292 ],
114
+ 1293: "/Users/felipeclopes/projects/redisrank/lib/redisrank/summary.rb": [
115
+ 1294 1,
116
+ 1295 1,
117
+ ....
118
+ 1383 null
119
+ 1384 ],
120
+ 1385: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext.rb": [
121
+ 1386 1,
122
+ 1387 1,
123
+ ....
124
+ 1390 1
125
+ 1391 ],
126
+ 1392: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/bignum.rb": [
127
+ 1393 1,
128
+ 1394 1,
129
+ ....
130
+ 1400 null
131
+ 1401 ],
132
+ 1402: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/date.rb": [
133
+ 1403 1,
134
+ 1404 1,
135
+ ....
136
+ 1410 null
137
+ 1411 ],
138
+ 1412: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/fixnum.rb": [
139
+ 1413 1,
140
+ 1414 1,
141
+ ....
142
+ 1420 null
143
+ 1421 ],
144
+ 1422: "/Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/time.rb": [
145
+ 1423 1,
146
+ 1424 1,
147
+
148
+ /Users/felipeclopes/projects/redisrank/coverage/index.html:
149
+ 52
150
+ 53 <tr>
151
+ 54: <td class="strong"><a href="#5f3d02dddf749f33b220f1d8a1b532440c0dc27e" class="src_link" title="lib/redisrank.rb">lib/redisrank.rb</a></td>
152
+ 55 <td class="green strong">90.91 %</td>
153
+ 56 <td>106</td>
154
+ ..
155
+ 62
156
+ 63 <tr>
157
+ 64: <td class="strong"><a href="#8c1481ec29601d06aa57b3e587a67a7834a4f6e4" class="src_link" title="lib/redisrank/buffer.rb">lib/redisrank/buffer.rb</a></td>
158
+ 65 <td class="green strong">100.0 %</td>
159
+ 66 <td>110</td>
160
+ ..
161
+ 72
162
+ 73 <tr>
163
+ 74: <td class="strong"><a href="#d3e9fd19771bd479d9a665ed2cff793490e15462" class="src_link" title="lib/redisrank/collection.rb">lib/redisrank/collection.rb</a></td>
164
+ 75 <td class="green strong">100.0 %</td>
165
+ 76 <td>20</td>
166
+ ..
167
+ 82
168
+ 83 <tr>
169
+ 84: <td class="strong"><a href="#ca4cc2e3bbfbe3ee94db3576ffb8aa464737cd80" class="src_link" title="lib/redisrank/connection.rb">lib/redisrank/connection.rb</a></td>
170
+ 85 <td class="yellow strong">86.67 %</td>
171
+ 86 <td>89</td>
172
+ ..
173
+ 92
174
+ 93 <tr>
175
+ 94: <td class="strong"><a href="#56543f0ff162392b04cff944aa846343fdb8c953" class="src_link" title="lib/redisrank/core_ext.rb">lib/redisrank/core_ext.rb</a></td>
176
+ 95 <td class="green strong">100.0 %</td>
177
+ 96 <td>5</td>
178
+ ..
179
+ 102
180
+ 103 <tr>
181
+ 104: <td class="strong"><a href="#0199b10aa595ac3dc02798926112446fa7b48aff" class="src_link" title="lib/redisrank/core_ext/bignum.rb">lib/redisrank/core_ext/bignum.rb</a></td>
182
+ 105 <td class="red strong">75.0 %</td>
183
+ 106 <td>8</td>
184
+ ...
185
+ 112
186
+ 113 <tr>
187
+ 114: <td class="strong"><a href="#fd5639c9afa530f6aad29ca2209fe1a8e36ce611" class="src_link" title="lib/redisrank/core_ext/date.rb">lib/redisrank/core_ext/date.rb</a></td>
188
+ 115 <td class="green strong">100.0 %</td>
189
+ 116 <td>8</td>
190
+ ...
191
+ 122
192
+ 123 <tr>
193
+ 124: <td class="strong"><a href="#228cb580a293e5d779c815fe93d6b58d00f168b1" class="src_link" title="lib/redisrank/core_ext/fixnum.rb">lib/redisrank/core_ext/fixnum.rb</a></td>
194
+ 125 <td class="green strong">100.0 %</td>
195
+ 126 <td>8</td>
196
+ ...
197
+ 132
198
+ 133 <tr>
199
+ 134: <td class="strong"><a href="#ff4375643e395caeeb60ca12edb2ec6c97c9fdb1" class="src_link" title="lib/redisrank/core_ext/hash.rb">lib/redisrank/core_ext/hash.rb</a></td>
200
+ 135 <td class="green strong">100.0 %</td>
201
+ 136 <td>20</td>
202
+ ...
203
+ 142
204
+ 143 <tr>
205
+ 144: <td class="strong"><a href="#b29d797d5842d9292883d53729f272f232c03286" class="src_link" title="lib/redisrank/core_ext/time.rb">lib/redisrank/core_ext/time.rb</a></td>
206
+ 145 <td class="green strong">100.0 %</td>
207
+ 146 <td>3</td>
208
+ ...
209
+ 152
210
+ 153 <tr>
211
+ 154: <td class="strong"><a href="#c3e929b1fdac4c8b5d6f7444bc37de594ded7c75" class="src_link" title="lib/redisrank/date.rb">lib/redisrank/date.rb</a></td>
212
+ 155 <td class="green strong">96.49 %</td>
213
+ 156 <td>88</td>
214
+ ...
215
+ 162
216
+ 163 <tr>
217
+ 164: <td class="strong"><a href="#109532c307fabc080fa13f73d588b098fc936aa1" class="src_link" title="lib/redisrank/event.rb">lib/redisrank/event.rb</a></td>
218
+ 165 <td class="green strong">96.08 %</td>
219
+ 166 <td>98</td>
220
+ ...
221
+ 172
222
+ 173 <tr>
223
+ 174: <td class="strong"><a href="#9364489efe6fdf47db14281f184659528d91e920" class="src_link" title="lib/redisrank/finder.rb">lib/redisrank/finder.rb</a></td>
224
+ 175 <td class="green strong">98.68 %</td>
225
+ 176 <td>245</td>
226
+ ...
227
+ 182
228
+ 183 <tr>
229
+ 184: <td class="strong"><a href="#f08239cbf009f185ee396584e1c11d4fca61da14" class="src_link" title="lib/redisrank/finder/date_set.rb">lib/redisrank/finder/date_set.rb</a></td>
230
+ 185 <td class="green strong">100.0 %</td>
231
+ 186 <td>99</td>
232
+ ...
233
+ 192
234
+ 193 <tr>
235
+ 194: <td class="strong"><a href="#091e0442202c28d13d16aaf647f801bdacaaf43f" class="src_link" title="lib/redisrank/key.rb">lib/redisrank/key.rb</a></td>
236
+ 195 <td class="green strong">100.0 %</td>
237
+ 196 <td>84</td>
238
+ ...
239
+ 202
240
+ 203 <tr>
241
+ 204: <td class="strong"><a href="#f084e7730511c8254398e9d8898036f80110b94b" class="src_link" title="lib/redisrank/label.rb">lib/redisrank/label.rb</a></td>
242
+ 205 <td class="green strong">100.0 %</td>
243
+ 206 <td>69</td>
244
+ ...
245
+ 212
246
+ 213 <tr>
247
+ 214: <td class="strong"><a href="#14bf81df729f5b64ae04d4cc23dcaf066ff47460" class="src_link" title="lib/redisrank/mixins/database.rb">lib/redisrank/mixins/database.rb</a></td>
248
+ 215 <td class="green strong">100.0 %</td>
249
+ 216 <td>11</td>
250
+ ...
251
+ 222
252
+ 223 <tr>
253
+ 224: <td class="strong"><a href="#26682b6e33149c5227ac95e96a64009cc562842c" class="src_link" title="lib/redisrank/mixins/date_helper.rb">lib/redisrank/mixins/date_helper.rb</a></td>
254
+ 225 <td class="green strong">100.0 %</td>
255
+ 226 <td>8</td>
256
+ ...
257
+ 232
258
+ 233 <tr>
259
+ 234: <td class="strong"><a href="#e3ee422da87b12823b5844f03ab6331ad5dca1b6" class="src_link" title="lib/redisrank/mixins/options.rb">lib/redisrank/mixins/options.rb</a></td>
260
+ 235 <td class="green strong">95.24 %</td>
261
+ 236 <td>41</td>
262
+ ...
263
+ 242
264
+ 243 <tr>
265
+ 244: <td class="strong"><a href="#fa2133f6ba899094454baa3bb930b76407532812" class="src_link" title="lib/redisrank/mixins/synchronize.rb">lib/redisrank/mixins/synchronize.rb</a></td>
266
+ 245 <td class="green strong">100.0 %</td>
267
+ 246 <td>52</td>
268
+ ...
269
+ 252
270
+ 253 <tr>
271
+ 254: <td class="strong"><a href="#1fdcf8497be392cb64905957375de3cc3e0d7ccb" class="src_link" title="lib/redisrank/model.rb">lib/redisrank/model.rb</a></td>
272
+ 255 <td class="green strong">100.0 %</td>
273
+ 256 <td>77</td>
274
+ ...
275
+ 262
276
+ 263 <tr>
277
+ 264: <td class="strong"><a href="#4b19da367c091d280cf1621d5e4bfdd2c90e04e9" class="src_link" title="lib/redisrank/result.rb">lib/redisrank/result.rb</a></td>
278
+ 265 <td class="green strong">100.0 %</td>
279
+ 266 <td>18</td>
280
+ ...
281
+ 272
282
+ 273 <tr>
283
+ 274: <td class="strong"><a href="#51418f37251ac0c95c6a3b8eecc5c7f4a4fa91a7" class="src_link" title="lib/redisrank/scope.rb">lib/redisrank/scope.rb</a></td>
284
+ 275 <td class="green strong">100.0 %</td>
285
+ 276 <td>18</td>
286
+ ...
287
+ 282
288
+ 283 <tr>
289
+ 284: <td class="strong"><a href="#a2ff63e1a8c4e9c28925432188451353d3cbf689" class="src_link" title="lib/redisrank/summary.rb">lib/redisrank/summary.rb</a></td>
290
+ 285 <td class="green strong">100.0 %</td>
291
+ 286 <td>90</td>
292
+ ...
293
+ 309 <div class="source_table" id="5f3d02dddf749f33b220f1d8a1b532440c0dc27e">
294
+ 310 <div class="header">
295
+ 311: <h3>lib/redisrank.rb</h3>
296
+ 312 <h4><span class="green">90.91 %</span> covered</h4>
297
+ 313 <div>
298
+ ...
299
+ 432 <span class="hits">1</span>
300
+ 433
301
+ 434: <code class="ruby">require &#39;redisrank/mixins/options&#39;</code>
302
+ 435 </li>
303
+ 436
304
+ ...
305
+ 438 <span class="hits">1</span>
306
+ 439
307
+ 440: <code class="ruby">require &#39;redisrank/mixins/synchronize&#39;</code>
308
+ 441 </li>
309
+ 442
310
+ ...
311
+ 444 <span class="hits">1</span>
312
+ 445
313
+ 446: <code class="ruby">require &#39;redisrank/mixins/database&#39;</code>
314
+ 447 </li>
315
+ 448
316
+ ...
317
+ 450 <span class="hits">1</span>
318
+ 451
319
+ 452: <code class="ruby">require &#39;redisrank/mixins/date_helper&#39;</code>
320
+ 453 </li>
321
+ 454
322
+ ...
323
+ 462 <span class="hits">1</span>
324
+ 463
325
+ 464: <code class="ruby">require &#39;redisrank/connection&#39;</code>
326
+ 465 </li>
327
+ 466
328
+ ...
329
+ 468 <span class="hits">1</span>
330
+ 469
331
+ 470: <code class="ruby">require &#39;redisrank/buffer&#39;</code>
332
+ 471 </li>
333
+ 472
334
+ ...
335
+ 474 <span class="hits">1</span>
336
+ 475
337
+ 476: <code class="ruby">require &#39;redisrank/collection&#39;</code>
338
+ 477 </li>
339
+ 478
340
+ ...
341
+ 480 <span class="hits">1</span>
342
+ 481
343
+ 482: <code class="ruby">require &#39;redisrank/date&#39;</code>
344
+ 483 </li>
345
+ 484
346
+ ...
347
+ 486 <span class="hits">1</span>
348
+ 487
349
+ 488: <code class="ruby">require &#39;redisrank/event&#39;</code>
350
+ 489 </li>
351
+ 490
352
+ ...
353
+ 492 <span class="hits">1</span>
354
+ 493
355
+ 494: <code class="ruby">require &#39;redisrank/finder&#39;</code>
356
+ 495 </li>
357
+ 496
358
+ ...
359
+ 498 <span class="hits">1</span>
360
+ 499
361
+ 500: <code class="ruby">require &#39;redisrank/key&#39;</code>
362
+ 501 </li>
363
+ 502
364
+ ...
365
+ 504 <span class="hits">1</span>
366
+ 505
367
+ 506: <code class="ruby">require &#39;redisrank/label&#39;</code>
368
+ 507 </li>
369
+ 508
370
+ ...
371
+ 510 <span class="hits">1</span>
372
+ 511
373
+ 512: <code class="ruby">require &#39;redisrank/model&#39;</code>
374
+ 513 </li>
375
+ 514
376
+ ...
377
+ 516 <span class="hits">1</span>
378
+ 517
379
+ 518: <code class="ruby">require &#39;redisrank/result&#39;</code>
380
+ 519 </li>
381
+ 520
382
+ ...
383
+ 522 <span class="hits">1</span>
384
+ 523
385
+ 524: <code class="ruby">require &#39;redisrank/scope&#39;</code>
386
+ 525 </li>
387
+ 526
388
+ ...
389
+ 528 <span class="hits">1</span>
390
+ 529
391
+ 530: <code class="ruby">require &#39;redisrank/summary&#39;</code>
392
+ 531 </li>
393
+ 532
394
+ ...
395
+ 534 <span class="hits">1</span>
396
+ 535
397
+ 536: <code class="ruby">require &#39;redisrank/version&#39;</code>
398
+ 537 </li>
399
+ 538
400
+ ...
401
+ 546 <span class="hits">1</span>
402
+ 547
403
+ 548: <code class="ruby">require &#39;redisrank/core_ext&#39;</code>
404
+ 549 </li>
405
+ 550
406
+ ...
407
+ 564 <span class="hits">1</span>
408
+ 565
409
+ 566: <code class="ruby">module Redistat</code>
410
+ 567 </li>
411
+ 568
412
+ ...
413
+ 588 <span class="hits">1</span>
414
+ 589
415
+ 590: <code class="ruby"> KEY_LABELS = &quot;Redistat.labels:&quot; # used for reverse label hash lookup</code>
416
+ 591 </li>
417
+ 592
418
+ ...
419
+ 858
420
+ 859
421
+ 860: <code class="ruby"> puts &quot;WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead.&quot;</code>
422
+ 861 </li>
423
+ 862
424
+ ...
425
+ 948 <span class="hits">1</span>
426
+ 949
427
+ 950: <code class="ruby"> Redistat.buffer.flush(true)</code>
428
+ 951 </li>
429
+ 952
430
+ ...
431
+ 963 <div class="source_table" id="8c1481ec29601d06aa57b3e587a67a7834a4f6e4">
432
+ 964 <div class="header">
433
+ 965: <h3>lib/redisrank/buffer.rb</h3>
434
+ 966 <h4><span class="green">100.0 %</span> covered</h4>
435
+ 967 <div>
436
+ ...
437
+ 978 <span class="hits">1</span>
438
+ 979
439
+ 980: <code class="ruby">require &#39;redisrank/core_ext/hash&#39;</code>
440
+ 981 </li>
441
+ 982
442
+ ...
443
+ 990 <span class="hits">1</span>
444
+ 991
445
+ 992: <code class="ruby">module Redistat</code>
446
+ 993 </li>
447
+ 994
448
+ ...
449
+ 1641 <div class="source_table" id="d3e9fd19771bd479d9a665ed2cff793490e15462">
450
+ 1642 <div class="header">
451
+ 1643: <h3>lib/redisrank/collection.rb</h3>
452
+ 1644 <h4><span class="green">100.0 %</span> covered</h4>
453
+ 1645 <div>
454
+ ....
455
+ 1656 <span class="hits">1</span>
456
+ 1657
457
+ 1658: <code class="ruby">module Redistat</code>
458
+ 1659 </li>
459
+ 1660
460
+ ....
461
+ 1779 <div class="source_table" id="ca4cc2e3bbfbe3ee94db3576ffb8aa464737cd80">
462
+ 1780 <div class="header">
463
+ 1781: <h3>lib/redisrank/connection.rb</h3>
464
+ 1782 <h4><span class="yellow">86.67 %</span> covered</h4>
465
+ 1783 <div>
466
+ ....
467
+ 1806 <span class="hits">1</span>
468
+ 1807
469
+ 1808: <code class="ruby">module Redistat</code>
470
+ 1809 </li>
471
+ 1810
472
+ ....
473
+ 2331 <div class="source_table" id="56543f0ff162392b04cff944aa846343fdb8c953">
474
+ 2332 <div class="header">
475
+ 2333: <h3>lib/redisrank/core_ext.rb</h3>
476
+ 2334 <h4><span class="green">100.0 %</span> covered</h4>
477
+ 2335 <div>
478
+ ....
479
+ 2346 <span class="hits">1</span>
480
+ 2347
481
+ 2348: <code class="ruby">require &#39;redisrank/core_ext/bignum&#39;</code>
482
+ 2349 </li>
483
+ 2350
484
+ ....
485
+ 2352 <span class="hits">1</span>
486
+ 2353
487
+ 2354: <code class="ruby">require &#39;redisrank/core_ext/date&#39;</code>
488
+ 2355 </li>
489
+ 2356
490
+ ....
491
+ 2358 <span class="hits">1</span>
492
+ 2359
493
+ 2360: <code class="ruby">require &#39;redisrank/core_ext/fixnum&#39;</code>
494
+ 2361 </li>
495
+ 2362
496
+ ....
497
+ 2364 <span class="hits">1</span>
498
+ 2365
499
+ 2366: <code class="ruby">require &#39;redisrank/core_ext/hash&#39;</code>
500
+ 2367 </li>
501
+ 2368
502
+ ....
503
+ 2370 <span class="hits">1</span>
504
+ 2371
505
+ 2372: <code class="ruby">require &#39;redisrank/core_ext/time&#39;</code>
506
+ 2373 </li>
507
+ 2374
508
+ ....
509
+ 2379 <div class="source_table" id="0199b10aa595ac3dc02798926112446fa7b48aff">
510
+ 2380 <div class="header">
511
+ 2381: <h3>lib/redisrank/core_ext/bignum.rb</h3>
512
+ 2382 <h4><span class="red">75.0 %</span> covered</h4>
513
+ 2383 <div>
514
+ ....
515
+ 2400 <span class="hits">1</span>
516
+ 2401
517
+ 2402: <code class="ruby"> include Redistat::DateHelper</code>
518
+ 2403 </li>
519
+ 2404
520
+ ....
521
+ 2445 <div class="source_table" id="fd5639c9afa530f6aad29ca2209fe1a8e36ce611">
522
+ 2446 <div class="header">
523
+ 2447: <h3>lib/redisrank/core_ext/date.rb</h3>
524
+ 2448 <h4><span class="green">100.0 %</span> covered</h4>
525
+ 2449 <div>
526
+ ....
527
+ 2466 <span class="hits">1</span>
528
+ 2467
529
+ 2468: <code class="ruby"> include Redistat::DateHelper</code>
530
+ 2469 </li>
531
+ 2470
532
+ ....
533
+ 2511 <div class="source_table" id="228cb580a293e5d779c815fe93d6b58d00f168b1">
534
+ 2512 <div class="header">
535
+ 2513: <h3>lib/redisrank/core_ext/fixnum.rb</h3>
536
+ 2514 <h4><span class="green">100.0 %</span> covered</h4>
537
+ 2515 <div>
538
+ ....
539
+ 2532 <span class="hits">1</span>
540
+ 2533
541
+ 2534: <code class="ruby"> include Redistat::DateHelper</code>
542
+ 2535 </li>
543
+ 2536
544
+ ....
545
+ 2577 <div class="source_table" id="ff4375643e395caeeb60ca12edb2ec6c97c9fdb1">
546
+ 2578 <div class="header">
547
+ 2579: <h3>lib/redisrank/core_ext/hash.rb</h3>
548
+ 2580 <h4><span class="green">100.0 %</span> covered</h4>
549
+ 2581 <div>
550
+ ....
551
+ 2715 <div class="source_table" id="b29d797d5842d9292883d53729f272f232c03286">
552
+ 2716 <div class="header">
553
+ 2717: <h3>lib/redisrank/core_ext/time.rb</h3>
554
+ 2718 <h4><span class="green">100.0 %</span> covered</h4>
555
+ 2719 <div>
556
+ ....
557
+ 2736 <span class="hits">1</span>
558
+ 2737
559
+ 2738: <code class="ruby"> include Redistat::DateHelper</code>
560
+ 2739 </li>
561
+ 2740
562
+ ....
563
+ 2751 <div class="source_table" id="c3e929b1fdac4c8b5d6f7444bc37de594ded7c75">
564
+ 2752 <div class="header">
565
+ 2753: <h3>lib/redisrank/date.rb</h3>
566
+ 2754 <h4><span class="green">96.49 %</span> covered</h4>
567
+ 2755 <div>
568
+ ....
569
+ 2766 <span class="hits">1</span>
570
+ 2767
571
+ 2768: <code class="ruby">module Redistat</code>
572
+ 2769 </li>
573
+ 2770
574
+ ....
575
+ 3297 <div class="source_table" id="109532c307fabc080fa13f73d588b098fc936aa1">
576
+ 3298 <div class="header">
577
+ 3299: <h3>lib/redisrank/event.rb</h3>
578
+ 3300 <h4><span class="green">96.08 %</span> covered</h4>
579
+ 3301 <div>
580
+ ....
581
+ 3312 <span class="hits">1</span>
582
+ 3313
583
+ 3314: <code class="ruby">module Redistat</code>
584
+ 3315 </li>
585
+ 3316
586
+ ....
587
+ 3903 <div class="source_table" id="9364489efe6fdf47db14281f184659528d91e920">
588
+ 3904 <div class="header">
589
+ 3905: <h3>lib/redisrank/finder.rb</h3>
590
+ 3906 <h4><span class="green">98.68 %</span> covered</h4>
591
+ 3907 <div>
592
+ ....
593
+ 3918 <span class="hits">1</span>
594
+ 3919
595
+ 3920: <code class="ruby">require &#39;redisrank/finder/date_set&#39;</code>
596
+ 3921 </li>
597
+ 3922
598
+ ....
599
+ 3930 <span class="hits">1</span>
600
+ 3931
601
+ 3932: <code class="ruby">module Redistat</code>
602
+ 3933 </li>
603
+ 3934
604
+ ....
605
+ 5391 <div class="source_table" id="f08239cbf009f185ee396584e1c11d4fca61da14">
606
+ 5392 <div class="header">
607
+ 5393: <h3>lib/redisrank/finder/date_set.rb</h3>
608
+ 5394 <h4><span class="green">100.0 %</span> covered</h4>
609
+ 5395 <div>
610
+ ....
611
+ 5406 <span class="hits">1</span>
612
+ 5407
613
+ 5408: <code class="ruby">module Redistat</code>
614
+ 5409 </li>
615
+ 5410
616
+ ....
617
+ 6003 <div class="source_table" id="091e0442202c28d13d16aaf647f801bdacaaf43f">
618
+ 6004 <div class="header">
619
+ 6005: <h3>lib/redisrank/key.rb</h3>
620
+ 6006 <h4><span class="green">100.0 %</span> covered</h4>
621
+ 6007 <div>
622
+ ....
623
+ 6018 <span class="hits">1</span>
624
+ 6019
625
+ 6020: <code class="ruby">module Redistat</code>
626
+ 6021 </li>
627
+ 6022
628
+ ....
629
+ 6162 <span class="hits">313</span>
630
+ 6163
631
+ 6164: <code class="ruby"> @date = (input.instance_of?(Redistat::Date)) ? input : Date.new(input) # Redistat::Date, not ::Date</code>
632
+ 6165 </li>
633
+ 6166
634
+ ....
635
+ 6240 <span class="hits">312</span>
636
+ 6241
637
+ 6242: <code class="ruby"> @scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)</code>
638
+ 6243 </li>
639
+ 6244
640
+ ....
641
+ 6270 <span class="hits">310</span>
642
+ 6271
643
+ 6272: <code class="ruby"> @label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)</code>
644
+ 6273 </li>
645
+ 6274
646
+ ....
647
+ 6366 <span class="hits">19</span>
648
+ 6367
649
+ 6368: <code class="ruby"> self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options)</code>
650
+ 6369 </li>
651
+ 6370
652
+ ....
653
+ 6525 <div class="source_table" id="f084e7730511c8254398e9d8898036f80110b94b">
654
+ 6526 <div class="header">
655
+ 6527: <h3>lib/redisrank/label.rb</h3>
656
+ 6528 <h4><span class="green">100.0 %</span> covered</h4>
657
+ 6529 <div>
658
+ ....
659
+ 6540 <span class="hits">1</span>
660
+ 6541
661
+ 6542: <code class="ruby">module Redistat</code>
662
+ 6543 </li>
663
+ 6544
664
+ ....
665
+ 6630 <span class="hits">28</span>
666
+ 6631
667
+ 6632: <code class="ruby"> self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator))</code>
668
+ 6633 </li>
669
+ 6634
670
+ ....
671
+ 6840 <span class="hits">109</span>
672
+ 6841
673
+ 6842: <code class="ruby"> self.to_s.split(Redistat.group_separator).last</code>
674
+ 6843 </li>
675
+ 6844
676
+ ....
677
+ 6882 <span class="hits">266</span>
678
+ 6883
679
+ 6884: <code class="ruby"> self.to_s.split(Redistat.group_separator).each do |part|</code>
680
+ 6885 </li>
681
+ 6886
682
+ ....
683
+ 6894 <span class="hits">324</span>
684
+ 6895
685
+ 6896: <code class="ruby"> group = ((parent.blank?) ? &quot;&quot; : &quot;#{parent}#{Redistat.group_separator}&quot;) + part</code>
686
+ 6897 </li>
687
+ 6898
688
+ ....
689
+ 6957 <div class="source_table" id="14bf81df729f5b64ae04d4cc23dcaf066ff47460">
690
+ 6958 <div class="header">
691
+ 6959: <h3>lib/redisrank/mixins/database.rb</h3>
692
+ 6960 <h4><span class="green">100.0 %</span> covered</h4>
693
+ 6961 <div>
694
+ ....
695
+ 6972 <span class="hits">1</span>
696
+ 6973
697
+ 6974: <code class="ruby">module Redistat</code>
698
+ 6975 </li>
699
+ 6976
700
+ ....
701
+ 7014 <span class="hits">1667</span>
702
+ 7015
703
+ 7016: <code class="ruby"> Redistat.connection(ref)</code>
704
+ 7017 </li>
705
+ 7018
706
+ ....
707
+ 7041 <div class="source_table" id="26682b6e33149c5227ac95e96a64009cc562842c">
708
+ 7042 <div class="header">
709
+ 7043: <h3>lib/redisrank/mixins/date_helper.rb</h3>
710
+ 7044 <h4><span class="green">100.0 %</span> covered</h4>
711
+ 7045 <div>
712
+ ....
713
+ 7056 <span class="hits">1</span>
714
+ 7057
715
+ 7058: <code class="ruby">module Redistat</code>
716
+ 7059 </li>
717
+ 7060
718
+ ....
719
+ 7068 <span class="hits">1</span>
720
+ 7069
721
+ 7070: <code class="ruby"> def to_redisrank(depth = nil)</code>
722
+ 7071 </li>
723
+ 7072
724
+ ....
725
+ 7074 <span class="hits">544</span>
726
+ 7075
727
+ 7076: <code class="ruby"> Redistat::Date.new(self, depth)</code>
728
+ 7077 </li>
729
+ 7078
730
+ ....
731
+ 7086 <span class="hits">1</span>
732
+ 7087
733
+ 7088: <code class="ruby"> alias :to_rs :to_redisrank</code>
734
+ 7089 </li>
735
+ 7090
736
+ ....
737
+ 7107 <div class="source_table" id="e3ee422da87b12823b5844f03ab6331ad5dca1b6">
738
+ 7108 <div class="header">
739
+ 7109: <h3>lib/redisrank/mixins/options.rb</h3>
740
+ 7110 <h4><span class="green">95.24 %</span> covered</h4>
741
+ 7111 <div>
742
+ ....
743
+ 7122 <span class="hits">1</span>
744
+ 7123
745
+ 7124: <code class="ruby">module Redistat</code>
746
+ 7125 </li>
747
+ 7126
748
+ ....
749
+ 7371 <div class="source_table" id="fa2133f6ba899094454baa3bb930b76407532812">
750
+ 7372 <div class="header">
751
+ 7373: <h3>lib/redisrank/mixins/synchronize.rb</h3>
752
+ 7374 <h4><span class="green">100.0 %</span> covered</h4>
753
+ 7375 <div>
754
+ ....
755
+ 7398 <span class="hits">1</span>
756
+ 7399
757
+ 7400: <code class="ruby">module Redistat</code>
758
+ 7401 </li>
759
+ 7402
760
+ ....
761
+ 7701 <div class="source_table" id="1fdcf8497be392cb64905957375de3cc3e0d7ccb">
762
+ 7702 <div class="header">
763
+ 7703: <h3>lib/redisrank/model.rb</h3>
764
+ 7704 <h4><span class="green">100.0 %</span> covered</h4>
765
+ 7705 <div>
766
+ ....
767
+ 7716 <span class="hits">1</span>
768
+ 7717
769
+ 7718: <code class="ruby">module Redistat</code>
770
+ 7719 </li>
771
+ 7720
772
+ ....
773
+ 8181 <div class="source_table" id="4b19da367c091d280cf1621d5e4bfdd2c90e04e9">
774
+ 8182 <div class="header">
775
+ 8183: <h3>lib/redisrank/result.rb</h3>
776
+ 8184 <h4><span class="green">100.0 %</span> covered</h4>
777
+ 8185 <div>
778
+ ....
779
+ 8208 <span class="hits">1</span>
780
+ 8209
781
+ 8210: <code class="ruby">module Redistat</code>
782
+ 8211 </li>
783
+ 8212
784
+ ....
785
+ 8307 <div class="source_table" id="51418f37251ac0c95c6a3b8eecc5c7f4a4fa91a7">
786
+ 8308 <div class="header">
787
+ 8309: <h3>lib/redisrank/scope.rb</h3>
788
+ 8310 <h4><span class="green">100.0 %</span> covered</h4>
789
+ 8311 <div>
790
+ ....
791
+ 8322 <span class="hits">1</span>
792
+ 8323
793
+ 8324: <code class="ruby">module Redistat</code>
794
+ 8325 </li>
795
+ 8326
796
+ ....
797
+ 8433 <div class="source_table" id="a2ff63e1a8c4e9c28925432188451353d3cbf689">
798
+ 8434 <div class="header">
799
+ 8435: <h3>lib/redisrank/summary.rb</h3>
800
+ 8436 <h4><span class="green">100.0 %</span> covered</h4>
801
+ 8437 <div>
802
+ ....
803
+ 8448 <span class="hits">1</span>
804
+ 8449
805
+ 8450: <code class="ruby">module Redistat</code>
806
+ 8451 </li>
807
+ 8452
808
+ ....
809
+ 8544 <span class="hits">105</span>
810
+ 8545
811
+ 8546: <code class="ruby"> Redistat.buffer</code>
812
+ 8547 </li>
813
+ 8548
814
+ ....
815
+ 8862 <span class="hits">151</span>
816
+ 8863
817
+ 8864: <code class="ruby"> parts = key.to_s.split(Redistat.group_separator)</code>
818
+ 8865 </li>
819
+ 8866
820
+ ....
821
+ 8898 <span class="hits">12</span>
822
+ 8899
823
+ 8900: <code class="ruby"> sum_key = sum_parts.join(Redistat.group_separator)</code>
824
+ 8901 </li>
825
+ 8902
826
+
827
+ /Users/felipeclopes/projects/redisrank/Gemfile:
828
+ 1 source 'http://rubygems.org/'
829
+ 2
830
+ 3: # Specify your gem's dependencies in redisrank.gemspec
831
+ 4 gemspec
832
+ 5
833
+
834
+ /Users/felipeclopes/projects/redisrank/Gemfile.lock:
835
+ 2 remote: .
836
+ 3 specs:
837
+ 4: redisrank (0.5.0)
838
+ 5 activesupport (>= 2.3.6)
839
+ 6 json (>= 1.4.0)
840
+ .
841
+ 55 DEPENDENCIES
842
+ 56 rake (>= 0.8.7)
843
+ 57: redisrank!
844
+ 58 rspec (>= 2.1.0)
845
+ 59 simplecov (>= 0.6.1)
846
+
847
+ /Users/felipeclopes/projects/redisrank/lib/redisrank.rb:
848
+ 17 require 'json'
849
+ 18
850
+ 19: require 'redisrank/mixins/options'
851
+ 20: require 'redisrank/mixins/synchronize'
852
+ 21: require 'redisrank/mixins/database'
853
+ 22: require 'redisrank/mixins/date_helper'
854
+ 23
855
+ 24: require 'redisrank/connection'
856
+ 25: require 'redisrank/buffer'
857
+ 26: require 'redisrank/collection'
858
+ 27: require 'redisrank/date'
859
+ 28: require 'redisrank/event'
860
+ 29: require 'redisrank/finder'
861
+ 30: require 'redisrank/key'
862
+ 31: require 'redisrank/label'
863
+ 32: require 'redisrank/model'
864
+ 33: require 'redisrank/result'
865
+ 34: require 'redisrank/scope'
866
+ 35: require 'redisrank/summary'
867
+ 36: require 'redisrank/version'
868
+ 37
869
+ 38: require 'redisrank/core_ext'
870
+ 39
871
+ 40
872
+ 41: module Redistat
873
+ 42
874
+ 43 KEY_NEXT_ID = ".next_id"
875
+ 44 KEY_EVENT = ".event:"
876
+ 45: KEY_LABELS = "Redistat.labels:" # used for reverse label hash lookup
877
+ 46 KEY_EVENT_IDS = ".event_ids"
878
+ 47 LABEL_INDEX = ".label_index:"
879
+ ..
880
+ 88
881
+ 89 def flush
882
+ 90: puts "WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead."
883
+ 91 connection.flushdb
884
+ 92 end
885
+ ..
886
+ 103 # ensure buffer is flushed on program exit
887
+ 104 Kernel.at_exit do
888
+ 105: Redistat.buffer.flush(true)
889
+ 106 end
890
+ 107
891
+
892
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/buffer.rb:
893
+ 1: require 'redisrank/core_ext/hash'
894
+ 2
895
+ 3: module Redistat
896
+ 4 class Buffer
897
+ 5 include Synchronize
898
+
899
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/collection.rb:
900
+ 1: module Redistat
901
+ 2 class Collection < ::Array
902
+ 3
903
+
904
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/connection.rb:
905
+ 1 require 'monitor'
906
+ 2
907
+ 3: module Redistat
908
+ 4 module Connection
909
+ 5
910
+
911
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext.rb:
912
+ 1: require 'redisrank/core_ext/bignum'
913
+ 2: require 'redisrank/core_ext/date'
914
+ 3: require 'redisrank/core_ext/fixnum'
915
+ 4: require 'redisrank/core_ext/hash'
916
+ 5: require 'redisrank/core_ext/time'
917
+ 6
918
+
919
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/bignum.rb:
920
+ 1 class Bignum
921
+ 2: include Redistat::DateHelper
922
+ 3
923
+ 4 def to_time
924
+
925
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/date.rb:
926
+ 1 class Date
927
+ 2: include Redistat::DateHelper
928
+ 3
929
+ 4 def to_time
930
+
931
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/fixnum.rb:
932
+ 1 class Fixnum
933
+ 2: include Redistat::DateHelper
934
+ 3
935
+ 4 def to_time
936
+
937
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/time.rb:
938
+ 1 class Time
939
+ 2: include Redistat::DateHelper
940
+ 3 end
941
+ 4
942
+
943
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/date.rb:
944
+ 1: module Redistat
945
+ 2 class Date
946
+ 3
947
+
948
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/event.rb:
949
+ 1: module Redistat
950
+ 2 class Event
951
+ 3 include Database
952
+
953
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/finder.rb:
954
+ 1: require 'redisrank/finder/date_set'
955
+ 2
956
+ 3: module Redistat
957
+ 4 class Finder
958
+ 5 include Database
959
+
960
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/finder/date_set.rb:
961
+ 1: module Redistat
962
+ 2 class Finder
963
+ 3 class DateSet < Array
964
+
965
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/key.rb:
966
+ 1: module Redistat
967
+ 2 class Key
968
+ 3 include Database
969
+ .
970
+ 23
971
+ 24 def date=(input)
972
+ 25: @date = (input.instance_of?(Redistat::Date)) ? input : Date.new(input) # Redistat::Date, not ::Date
973
+ 26 end
974
+ 27 attr_reader :date
975
+ ..
976
+ 36
977
+ 37 def scope=(input)
978
+ 38: @scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)
979
+ 39 end
980
+ 40 attr_reader :scope
981
+ 41
982
+ 42 def label=(input)
983
+ 43: @label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)
984
+ 44 end
985
+ 45 attr_reader :label
986
+ ..
987
+ 57 members.map { |member|
988
+ 58 child_label = [@label, member].reject { |i| i.nil? }
989
+ 59: self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options)
990
+ 60 }
991
+ 61 end
992
+
993
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/label.rb:
994
+ 1: module Redistat
995
+ 2 class Label
996
+ 3 include Database
997
+ .
998
+ 14 def self.join(*args)
999
+ 15 args = args.map {|i| i.to_s}
1000
+ 16: self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator))
1001
+ 17 end
1002
+ 18
1003
+ ..
1004
+ 49
1005
+ 50 def me
1006
+ 51: self.to_s.split(Redistat.group_separator).last
1007
+ 52 end
1008
+ 53
1009
+ ..
1010
+ 56 @groups = []
1011
+ 57 parent = ""
1012
+ 58: self.to_s.split(Redistat.group_separator).each do |part|
1013
+ 59 if !part.blank?
1014
+ 60: group = ((parent.blank?) ? "" : "#{parent}#{Redistat.group_separator}") + part
1015
+ 61 @groups << Label.new(group)
1016
+ 62 parent = group
1017
+
1018
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/database.rb:
1019
+ 1: module Redistat
1020
+ 2 module Database
1021
+ 3 def self.included(base)
1022
+ .
1023
+ 6 def db(ref = nil)
1024
+ 7 ref ||= @options[:connection_ref] if !@options.nil?
1025
+ 8: Redistat.connection(ref)
1026
+ 9 end
1027
+ 10 end
1028
+
1029
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/date_helper.rb:
1030
+ 1: module Redistat
1031
+ 2 module DateHelper
1032
+ 3: def to_redisrank(depth = nil)
1033
+ 4: Redistat::Date.new(self, depth)
1034
+ 5 end
1035
+ 6: alias :to_rs :to_redisrank
1036
+ 7 end
1037
+ 8 end
1038
+
1039
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/options.rb:
1040
+ 1: module Redistat
1041
+ 2 module Options
1042
+ 3
1043
+
1044
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/synchronize.rb:
1045
+ 1 require 'monitor'
1046
+ 2
1047
+ 3: module Redistat
1048
+ 4 module Synchronize
1049
+ 5
1050
+
1051
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/model.rb:
1052
+ 1: module Redistat
1053
+ 2 module Model
1054
+ 3 include Database
1055
+
1056
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/result.rb:
1057
+ 1 require 'active_support/core_ext/hash/indifferent_access'
1058
+ 2
1059
+ 3: module Redistat
1060
+ 4 class Result < HashWithIndifferentAccess
1061
+ 5
1062
+
1063
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/scope.rb:
1064
+ 1: module Redistat
1065
+ 2 class Scope
1066
+ 3 include Database
1067
+
1068
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/summary.rb:
1069
+ 1: module Redistat
1070
+ 2 class Summary
1071
+ 3 include Database
1072
+ .
1073
+ 15
1074
+ 16 def buffer
1075
+ 17: Redistat.buffer
1076
+ 18 end
1077
+ 19
1078
+ ..
1079
+ 68 summaries = {}
1080
+ 69 stats.each do |key, value|
1081
+ 70: parts = key.to_s.split(Redistat.group_separator)
1082
+ 71 parts.pop
1083
+ 72 if parts.size > 0
1084
+ ..
1085
+ 74 parts.each do |part|
1086
+ 75 sum_parts << part
1087
+ 76: sum_key = sum_parts.join(Redistat.group_separator)
1088
+ 77 (summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value
1089
+ 78 end
1090
+
1091
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/version.rb:
1092
+ 1: module Redistat
1093
+ 2 VERSION = "0.5.0"
1094
+ 3 end
1095
+
1096
+ /Users/felipeclopes/projects/redisrank/Rakefile:
1097
+ 63 #
1098
+ 64
1099
+ 65: desc "Start an irb console with Redistat pre-loaded."
1100
+ 66 task :console do
1101
+ 67 exec "irb -r spec/spec_helper"
1102
+
1103
+ /Users/felipeclopes/projects/redisrank/README.md:
1104
+ 1: # Redistat [![Build Status](https://secure.travis-ci.org/jimeh/redisrank.png)](http://travis-ci.org/jimeh/redisrank)
1105
+ 2
1106
+ 3 A Redis-backed statistics storage and querying library written in Ruby.
1107
+ 4
1108
+ 5: Redistat was originally created to replace a small hacked together statistics
1109
+ 6 collection solution which was MySQL-based. When I started I had a short list
1110
+ 7 of requirements:
1111
+ .
1112
+ 18 ## Installation
1113
+ 19
1114
+ 20: gem install redisrank
1115
+ 21
1116
+ 22 If you are using Ruby 1.8.x, it's recommended you also install the
1117
+ ..
1118
+ 28
1119
+ 29 ```ruby
1120
+ 30: require 'redisrank'
1121
+ 31
1122
+ 32 class ViewStats
1123
+ 33: include Redistat::Model
1124
+ 34 end
1125
+ 35
1126
+ 36: # if using Redistat in multiple threads set this
1127
+ 37 # somewhere in the beginning of the execution stack
1128
+ 38: Redistat.thread_safe = true
1129
+ 39 ```
1130
+ 40
1131
+ ..
1132
+ 118 ```
1133
+ 119
1134
+ 120: Fetch list of products known to Redistat:
1135
+ 121
1136
+ 122 ```ruby
1137
+ ...
1138
+ 136 ### Scope
1139
+ 137
1140
+ 138: A type of global-namespace for storing data. When using the `Redistat::Model`
1141
+ 139 wrapper, the scope is automatically set to the class name. In the examples
1142
+ 140 above, the scope is `ViewStats`. Can be overridden by calling the `#scope`
1143
+ ...
1144
+ 151 label called `views/product/44`, the data is stored for the label you specify,
1145
+ 152 and also for `views/product` and `views`. You may also configure a different
1146
+ 153: group separator using the `Redistat.group_separator=` method. For example:
1147
+ 154
1148
+ 155 ```ruby
1149
+ 156: Redistat.group_separator = '|'
1150
+ 157 ```
1151
+ 158
1152
+ ...
1153
+ 164 ### Input Statistics Data
1154
+ 165
1155
+ 166: You provide Redistat with the data you want to store using a Ruby Hash. This
1156
+ 167 data is then stored in a corresponding Redis hash with identical key/field
1157
+ 168 names.
1158
+ ...
1159
+ 175
1160
+ 176 Define how accurately data should be stored, and how accurately it's looked up
1161
+ 177: when fetching it again. By default Redistat uses a depth value of `:hour`,
1162
+ 178 which means it's impossible to separate two events which were stored at 10:18
1163
+ 179 and 10:23. In Redis they are both stored within a date key of `2011031610`.
1164
+ ...
1165
+ 186 When you fetch data, you need to specify a start and an end time. The
1166
+ 187 selection behavior can seem a bit weird at first when, but makes sense when
1167
+ 188: you understand how Redistat works internally.
1168
+ 189
1169
+ 190 For example, if we are using a Depth value of `:hour`, and we trigger a fetch
1170
+ ...
1171
+ 197 ### The Finder Object
1172
+ 198
1173
+ 199: Calling the `#find` method on a Redistat model class returns a
1174
+ 200: `Redistat::Finder` object. The finder is a lazy-loaded gateway to your
1175
+ 201 data. Meaning you can create a new finder, and modify instantiated finder's
1176
+ 202 label, scope, dates, and more. It does not call Redis and fetch the data until
1177
+ ...
1178
+ 222 ```ruby
1179
+ 223 class ViewStats
1180
+ 224: include Redistat::Model
1181
+ 225
1182
+ 226 depth :sec
1183
+ ...
1184
+ 243 ### Storing / Writing
1185
+ 244
1186
+ 245: Redistat stores all data into a Redis hash keys. The Redis key name the used
1187
+ 246 consists of three parts. The scope, label, and datetime:
1188
+ 247
1189
+ ...
1190
+ 296 ### Fetching / Reading
1191
+ 297
1192
+ 298: By default when fetching statistics, Redistat will figure out how to do the
1193
+ 299 least number of reads from Redis. First it checks how long range you're
1194
+ 300 fetching. If whole days, months or years for example fit within the start and
1195
+ ...
1196
+ 310
1197
+ 311 The buffer is a new, still semi-beta, feature aimed to reduce the number of
1198
+ 312: Redis `hincrby` that Redistat sends. This should only really be useful when
1199
+ 313 you're hitting north of 30,000 Redis requests per second, if your Redis server
1200
+ 314 has limited resources, or against my recommendation you've opted to use 10,
1201
+ ...
1202
+ 318 possible by merging the statistics hashes from all calls and groups them based
1203
+ 319 on scope, label, date depth, and more. You configure the the buffer by setting
1204
+ 320: `Redistat.buffer_size` to an integer higher than 1. This basically tells
1205
+ 321: Redistat how many `store` calls to buffer in memory before writing all data to
1206
+ 322 Redis.
1207
+ 323
1208
+ ...
1209
+ 333
1210
+ 334 [Global Personals](http://globalpersonals.co.uk/) deserves a thank
1211
+ 335: you. Currently the primary user of Redistat, they've allowed me to spend some
1212
+ 336 company time to further develop the project.
1213
+ 337
1214
+
1215
+ /Users/felipeclopes/projects/redisrank/redisrank.gemspec:
1216
+ 1 # -*- encoding: utf-8 -*-
1217
+ 2 $:.push File.expand_path("../lib", __FILE__)
1218
+ 3: require "redisrank/version"
1219
+ 4
1220
+ 5 Gem::Specification.new do |s|
1221
+ 6: s.name = "redisrank"
1222
+ 7: s.version = Redistat::VERSION
1223
+ 8 s.platform = Gem::Platform::RUBY
1224
+ 9 s.authors = ["Jim Myhrberg"]
1225
+ 10 s.email = ["contact@jimeh.me"]
1226
+ 11: s.homepage = "http://github.com/jimeh/redisrank"
1227
+ 12 s.summary = %q{A Redis-backed statistics storage and querying library written in Ruby.}
1228
+ 13 s.description = %q{A Redis-backed statistics storage and querying library written in Ruby.}
1229
+ 14
1230
+ 15: s.rubyforge_project = "redisrank"
1231
+ 16
1232
+ 17 s.files = `git ls-files`.split("\n")
1233
+
1234
+ /Users/felipeclopes/projects/redisrank/spec/buffer_spec.rb:
1235
+ 1 require "spec_helper"
1236
+ 2
1237
+ 3: describe Redistat::Buffer do
1238
+ 4
1239
+ 5 before(:each) do
1240
+ 6: @class = Redistat::Buffer
1241
+ 7: @buffer = Redistat::Buffer.instance
1242
+ 8 @key = double("Key", :to_s => "Scope/label:2011")
1243
+ 9 @stats = {:count => 1, :views => 3}
1244
+ ..
1245
+ 73 }}
1246
+ 74 item = data.first[1]
1247
+ 75: Redistat::Summary.should_receive(:update).with(@key, @stats, @depth_limit, @opts)
1248
+ 76 @buffer.send(:flush_data, data)
1249
+ 77 end
1250
+
1251
+ /Users/felipeclopes/projects/redisrank/spec/collection_spec.rb:
1252
+ 1 require "spec_helper"
1253
+ 2
1254
+ 3: describe Redistat::Collection do
1255
+ 4
1256
+ 5 it "should initialize properly" do
1257
+ 6 options = {:from => "from", :till => "till", :depth => "depth"}
1258
+ 7: result = Redistat::Collection.new(options)
1259
+ 8 result.from.should == options[:from]
1260
+ 9 result.till.should == options[:till]
1261
+ ..
1262
+ 12
1263
+ 13 it "should have a rank property" do
1264
+ 14: col = Redistat::Collection.new()
1265
+ 15 col.rank.should == {}
1266
+ 16 col.rank = {:foo => "bar"}
1267
+
1268
+ /Users/felipeclopes/projects/redisrank/spec/connection_spec.rb:
1269
+ 1 require "spec_helper"
1270
+ 2: include Redistat
1271
+ 3
1272
+ 4: describe Redistat::Connection do
1273
+ 5
1274
+ 6 before(:each) do
1275
+ 7: @redis = Redistat.redis
1276
+ 8 end
1277
+ 9
1278
+ 10 it "should have a valid Redis client instance" do
1279
+ 11: Redistat.redis.should_not be_nil
1280
+ 12 end
1281
+ 13
1282
+ ..
1283
+ 34 end
1284
+ 35
1285
+ 36: it "should be accessible from Redistat module" do
1286
+ 37: Redistat.redis.should == Connection.get
1287
+ 38: Redistat.redis.should == Redistat.connection
1288
+ 39 end
1289
+ 40
1290
+ 41 it "should handle multiple connections with refs" do
1291
+ 42: Redistat.redis.client.db.should == 15
1292
+ 43: Redistat.connect(:port => 8379, :db => 14, :ref => "Custom")
1293
+ 44: Redistat.redis.client.db.should == 15
1294
+ 45: Redistat.redis("Custom").client.db.should == 14
1295
+ 46 end
1296
+ 47
1297
+ 48 it "should be able to overwrite default and custom refs" do
1298
+ 49: Redistat.redis.client.db.should == 15
1299
+ 50: Redistat.connect(:port => 8379, :db => 14)
1300
+ 51: Redistat.redis.client.db.should == 14
1301
+ 52
1302
+ 53: Redistat.redis("Custom").client.db.should == 14
1303
+ 54: Redistat.connect(:port => 8379, :db => 15, :ref => "Custom")
1304
+ 55: Redistat.redis("Custom").client.db.should == 15
1305
+ 56
1306
+ 57 # Reset the default connection to the testing server or all hell
1307
+ 58 # might brake loose from the rest of the specs
1308
+ 59: Redistat.connect(:port => 8379, :db => 15)
1309
+ 60 end
1310
+ 61
1311
+
1312
+ /Users/felipeclopes/projects/redisrank/spec/database_spec.rb:
1313
+ 1 require "spec_helper"
1314
+ 2
1315
+ 3: describe Redistat::Database do
1316
+ 4: include Redistat::Database
1317
+ 5
1318
+ 6 it "should make #db method available when included" do
1319
+ 7: db.should == Redistat.redis
1320
+ 8 end
1321
+ 9
1322
+
1323
+ /Users/felipeclopes/projects/redisrank/spec/date_spec.rb:
1324
+ 1 require "spec_helper"
1325
+ 2
1326
+ 3: describe Redistat::Date do
1327
+ 4
1328
+ 5 it "should initialize from Time object" do
1329
+ 6 now = Time.now
1330
+ 7: [Redistat::Date.new(now), now.to_rs].each do |rdate|
1331
+ 8: Redistat::Date::DEPTHS.each { |k| rdate.send(k).should == now.send(k) }
1332
+ 9 end
1333
+ 10 end
1334
+ ..
1335
+ 12 it "should initialize from Date object" do
1336
+ 13 today = Date.today
1337
+ 14: [Redistat::Date.new(today), today.to_rs].each do |rdate|
1338
+ 15 [:year, :month, :day].each { |k| rdate.send(k).should == today.send(k) }
1339
+ 16 [:hour, :min, :sec, :usec].each { |k| rdate.send(k).should == 0 }
1340
+ ..
1341
+ 21 now = Time.now.to_i
1342
+ 22 time = Time.at(now)
1343
+ 23: [Redistat::Date.new(now), now.to_rs].each do |rdate|
1344
+ 24 [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == time.send(k) }
1345
+ 25 end
1346
+ ..
1347
+ 28 it "should initialize from String object" do
1348
+ 29 now = Time.now
1349
+ 30: rdate = Redistat::Date.new(now.to_s)
1350
+ 31 [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == now.send(k) }
1351
+ 32 end
1352
+ 33
1353
+ 34: it "should initialize from Redistat date String" do
1354
+ 35 now = Time.now
1355
+ 36: rdate = Redistat::Date.new(now.to_s)
1356
+ 37 [:year, :month, :day, :hour, :min, :sec].each { |k|
1357
+ 38: rdate.to_s(k).should == Redistat::Date.new(rdate.to_s(k)).to_s(k)
1358
+ 39 }
1359
+ 40 end
1360
+ ..
1361
+ 42 it "should convert to Time object" do
1362
+ 43 now = Time.now
1363
+ 44: rdate = Redistat::Date.new(now)
1364
+ 45 rdate.to_time.to_s.should == now.to_s
1365
+ 46 end
1366
+ ..
1367
+ 48 it "should convert to Date object" do
1368
+ 49 today = Date.today
1369
+ 50: rdate = Redistat::Date.new(today)
1370
+ 51 rdate.to_date.to_s.should == today.to_s
1371
+ 52 end
1372
+ ..
1373
+ 54 it "should convert to Fixnum object (UNIX Timestamp)" do
1374
+ 55 now = Time.now
1375
+ 56: rdate = Redistat::Date.new(now)
1376
+ 57 rdate.to_i.should == now.to_i
1377
+ 58 end
1378
+ ..
1379
+ 61 today = Date.today
1380
+ 62 now = Time.now
1381
+ 63: [[now, Redistat::Date.new(now)], [today, Redistat::Date.new(today)]].each do |current, rdate|
1382
+ 64 props = [:year, :month, :day, :hour, :min, :sec, nil]
1383
+ 65 if rdate.usec > 0
1384
+ ..
1385
+ 82 now = Time.now
1386
+ 83
1387
+ 84: date = Redistat::Date.new(now)
1388
+ 85 date.depth.should be_nil
1389
+ 86 date.to_s.should == now.to_rs(:sec).to_s
1390
+ 87 date.to_s.should == now.to_rs.to_s(:sec)
1391
+ 88
1392
+ 89: date = Redistat::Date.new(now, :hour)
1393
+ 90 date.depth.should == :hour
1394
+ 91 date.to_s.should == now.to_rs(:hour).to_s
1395
+
1396
+ /Users/felipeclopes/projects/redisrank/spec/event_spec.rb:
1397
+ 1 require "spec_helper"
1398
+ 2
1399
+ 3: describe Redistat::Event do
1400
+ 4: include Redistat::Database
1401
+ 5
1402
+ 6 before(:each) do
1403
+ .
1404
+ 13 @options = {:depth => :hour}
1405
+ 14 @date = Time.now
1406
+ 15: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta)
1407
+ 16 end
1408
+ 17
1409
+ ..
1410
+ 44
1411
+ 45 it "should increment next_id" do
1412
+ 46: event = Redistat::Event.new("VisitorCount", @label, @date, @stats, @options, @meta)
1413
+ 47 @event.next_id.should == 1
1414
+ 48 event.next_id.should == 1
1415
+ ..
1416
+ 52
1417
+ 53 it "should store event properly" do
1418
+ 54: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta)
1419
+ 55 expect(@event.new?).to be true
1420
+ 56 @event.save
1421
+ 57 expect(@event.new?).to be false
1422
+ 58 keys = db.keys "*"
1423
+ 59: keys.should include("#{@event.scope}#{Redistat::KEY_EVENT}#{@event.id}")
1424
+ 60: keys.should include("#{@event.scope}#{Redistat::KEY_EVENT_IDS}")
1425
+ 61 end
1426
+ 62
1427
+ 63 it "should find event by id" do
1428
+ 64: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save
1429
+ 65: fetched = Redistat::Event.find(@scope, @event.id)
1430
+ 66 @event.scope.to_s.should == fetched.scope.to_s
1431
+ 67 @event.label.to_s.should == fetched.label.to_s
1432
+ ..
1433
+ 73 it "should store summarized statistics" do
1434
+ 74 2.times do |i|
1435
+ 75: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta).save
1436
+ 76: Redistat::Date::DEPTHS.each do |depth|
1437
+ 77 summary = db.zrevrange @event.key.to_s(depth), 0, -1, :with_scores => true
1438
+ 78 expect(summary.count).to be > 0
1439
+
1440
+ /Users/felipeclopes/projects/redisrank/spec/finder/date_set_spec.rb:
1441
+ 1 require "spec_helper"
1442
+ 2
1443
+ 3: describe Redistat::Finder::DateSet do
1444
+ 4
1445
+ 5 before(:all) do
1446
+ 6: @finder = Redistat::Finder::DateSet.new
1447
+ 7 end
1448
+ 8
1449
+ .
1450
+ 10 t_start = Time.utc(2010, 8, 28, 22, 54, 57)
1451
+ 11 t_end = Time.utc(2013, 12, 4, 22, 52, 3)
1452
+ 12: result = Redistat::Finder::DateSet.new(t_start, t_end)
1453
+ 13 result.should == [
1454
+ 14 { :add => ["2010082822", "2010082823"], :rem => [] },
1455
+ ..
1456
+ 26
1457
+ 27 t_end = t_start + 4.hours
1458
+ 28: result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :hour, true)
1459
+ 29 result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"]
1460
+ 30 result[0][:rem].should == []
1461
+ 31: result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :hour)
1462
+ 32
1463
+ 33 t_end = t_start + 4.days
1464
+ 34: result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :day, true)
1465
+ 35 result[0][:add].should == ["20100828", "20100829", "20100830", "20100831", "20100901"]
1466
+ 36 result[0][:rem].should == []
1467
+ 37: result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :day)
1468
+ 38 end
1469
+ 39
1470
+
1471
+ /Users/felipeclopes/projects/redisrank/spec/finder_spec.rb:
1472
+ 1 require "spec_helper"
1473
+ 2
1474
+ 3: describe Redistat::Finder do
1475
+ 4: include Redistat::Database
1476
+ 5
1477
+ 6 before(:each) do
1478
+ .
1479
+ 9 @label = "about_us"
1480
+ 10 @date = Time.now
1481
+ 11: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
1482
+ 12 @stats = {"user_3" => 3, "user_2" => 2}
1483
+ 13 @stats2 = {"user_3" => 6, "user_2" => 2}
1484
+ ..
1485
+ 19 options = {:scope => "PageViews", :label => "Label", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
1486
+ 20
1487
+ 21: finder = Redistat::Finder.new
1488
+ 22 finder.send(:set_options, options)
1489
+ 23: finder.options[:scope].should be_a(Redistat::Scope)
1490
+ 24 finder.options[:scope].to_s.should == options[:scope]
1491
+ 25: finder.options[:label].should be_a(Redistat::Label)
1492
+ 26 finder.options[:label].to_s.should == options[:label]
1493
+ 27 finder.options.should == options.merge(:scope => finder.options[:scope], :label => finder.options[:label])
1494
+ 28
1495
+ 29: finder = Redistat::Finder.scope("hello")
1496
+ 30 finder.options[:scope].to_s.should == "hello"
1497
+ 31 finder.scope.to_s.should == "hello"
1498
+ 32
1499
+ 33: finder = Redistat::Finder.label("hello")
1500
+ 34 finder.options[:label].to_s.should == "hello"
1501
+ 35 finder.label.to_s.should == "hello"
1502
+ 36
1503
+ 37: finder = Redistat::Finder.dates(@two_hours_ago, @one_hour_ago)
1504
+ 38 finder.options[:from].should == @two_hours_ago
1505
+ 39 finder.options[:till].should == @one_hour_ago
1506
+ 40
1507
+ 41: finder = Redistat::Finder.from(@two_hours_ago)
1508
+ 42 finder.options[:from].should == @two_hours_ago
1509
+ 43 finder.from.should == @two_hours_ago
1510
+ 44
1511
+ 45: finder = Redistat::Finder.till(@one_hour_ago)
1512
+ 46 finder.options[:till].should == @one_hour_ago
1513
+ 47 finder.till.should == @one_hour_ago
1514
+ 48
1515
+ 49: finder = Redistat::Finder.depth(:hour)
1516
+ 50 finder.options[:depth].should == :hour
1517
+ 51 finder.depth.should == :hour
1518
+ 52
1519
+ 53: finder = Redistat::Finder.interval(true)
1520
+ 54 expect(finder.options[:interval]).to be true
1521
+ 55 expect(finder.interval).to be true
1522
+ 56: finder = Redistat::Finder.interval(false)
1523
+ 57 expect(finder.options[:interval]).to be false
1524
+ 58 expect(finder.interval).to be false
1525
+ ..
1526
+ 62 first_stat, last_stat = create_example_stats
1527
+ 63
1528
+ 64: stats = Redistat::Finder.find({:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour})
1529
+ 65 stats.from.should == first_stat
1530
+ 66 stats.till.should == last_stat
1531
+ ..
1532
+ 73 first_stat, last_stat = create_example_stats
1533
+ 74
1534
+ 75: stats = Redistat::Finder.find(:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour, :interval => :hour)
1535
+ 76 stats.from.should == first_stat
1536
+ 77 stats.till.should == last_stat
1537
+ ..
1538
+ 90
1539
+ 91 it "should return empty hash when attempting to fetch non-existent results" do
1540
+ 92: stats = Redistat::Finder.find({:from => 3.hours.ago, :till => 2.hours.from_now, :scope => @scope, :label => @label, :depth => :hour})
1541
+ 93 stats.rank.should == {}
1542
+ 94 end
1543
+ 95
1544
+ 96 it "should throw error on invalid options" do
1545
+ 97: lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions)
1546
+ 98 end
1547
+ 99
1548
+ ...
1549
+ 101 before(:each) do
1550
+ 102 @options = {:scope => "PageViews", :label => "message/public", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
1551
+ 103: @finder = Redistat::Finder.new(@options)
1552
+ 104 end
1553
+ 105
1554
+ 106 it "should return parent finder" do
1555
+ 107 @finder.instance_variable_get("@parent").should be_nil
1556
+ 108: @finder.parent.should be_a(Redistat::Finder)
1557
+ 109 @finder.instance_variable_get("@parent").should_not be_nil
1558
+ 110 @finder.parent.options[:label].to_s.should == 'message'
1559
+ ...
1560
+ 117
1561
+ 118 it "should find children" do
1562
+ 119: Redistat::Key.new("PageViews", "message/public/die").update_index
1563
+ 120: Redistat::Key.new("PageViews", "message/public/live").update_index
1564
+ 121: Redistat::Key.new("PageViews", "message/public/fester").update_index
1565
+ 122: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}message/public") # checking 'message/public'
1566
+ 123: @finder.children.first.should be_a(Redistat::Finder)
1567
+ 124 subs = @finder.children.map { |f| f.options[:label].me }
1568
+ 125 expect(subs.count).to eq(3)
1569
+ ...
1570
+ 135 @first_stat, @last_stat = create_example_stats
1571
+ 136
1572
+ 137: @finder = Redistat::Finder.new
1573
+ 138 @finder.from(@first_stat).till(@last_stat).scope(@scope).label(@label).depth(:hour)
1574
+ 139
1575
+ ...
1576
+ 192
1577
+ 193 def create_example_stats
1578
+ 194: key = Redistat::Key.new(@scope, @label, (first = Time.parse("2010-05-14 13:43")))
1579
+ 195: Redistat::Summary.send(:update_fields, key, @stats, :hour)
1580
+ 196: key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 13:53"))
1581
+ 197: Redistat::Summary.send(:update_fields, key, @stats, :hour)
1582
+ 198: key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 14:52"))
1583
+ 199: Redistat::Summary.send(:update_fields, key, @stats, :hour)
1584
+ 200: key = Redistat::Key.new(@scope, @label, (last = Time.parse("2010-05-14 15:02")))
1585
+ 201: Redistat::Summary.send(:update_fields, key, @stats2, :hour)
1586
+ 202 [first - 1.hour, last + 1.hour]
1587
+ 203 end
1588
+
1589
+ /Users/felipeclopes/projects/redisrank/spec/key_spec.rb:
1590
+ 1 require "spec_helper"
1591
+ 2
1592
+ 3: describe Redistat::Key do
1593
+ 4: include Redistat::Database
1594
+ 5
1595
+ 6 before(:each) do
1596
+ .
1597
+ 10 @label_hash = Digest::SHA1.hexdigest(@label)
1598
+ 11 @date = Time.now
1599
+ 12: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour})
1600
+ 13 end
1601
+ 14
1602
+ ..
1603
+ 18 @key.label_hash.should == @label_hash
1604
+ 19 @key.groups.map { |k| k.instance_variable_get("@label") }.should == @key.instance_variable_get("@label").groups
1605
+ 20: @key.date.should be_instance_of(Redistat::Date)
1606
+ 21 @key.date.to_time.to_s.should == @date.to_s
1607
+ 22 end
1608
+ ..
1609
+ 29 props.pop
1610
+ 30 end
1611
+ 31: key = Redistat::Key.new(@scope, nil, @date, {:depth => :hour})
1612
+ 32 key.to_s.should == "#{@scope}:#{key.date.to_s(:hour)}"
1613
+ 33 end
1614
+ 34
1615
+ 35 it "should abide to hashed_label option" do
1616
+ 36: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :hashed_label => true})
1617
+ 37 @key.to_s.should == "#{@scope}/#{@label_hash}:#{@key.date.to_s(:hour)}"
1618
+ 38: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :hashed_label => false})
1619
+ 39 @key.to_s.should == "#{@scope}/#{@label}:#{@key.date.to_s(:hour)}"
1620
+ 40 end
1621
+ 41
1622
+ 42 it "should have default depth option" do
1623
+ 43: @key = Redistat::Key.new(@scope, @label, @date)
1624
+ 44 @key.depth.should == :hour
1625
+ 45 end
1626
+ ..
1627
+ 69 before(:each) do
1628
+ 70 @label = "message/public/offensive"
1629
+ 71: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour})
1630
+ 72 end
1631
+ 73
1632
+ ..
1633
+ 78 "message" ]
1634
+ 79
1635
+ 80: key = Redistat::Key.new(@scope, label, @date, {:depth => :hour})
1636
+ 81
1637
+ 82 key.groups.map { |k| k.label.to_s }.should == result
1638
+ ..
1639
+ 84
1640
+ 85 it "should know it's parent" do
1641
+ 86: @key.parent.should be_a(Redistat::Key)
1642
+ 87 @key.parent.label.to_s.should == 'message/public'
1643
+ 88: Redistat::Key.new(@scope, 'hello', @date).parent.should be_nil
1644
+ 89 end
1645
+ 90
1646
+ 91 it "should update label index and return children" do
1647
+ 92: db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{@key.label.parent}").should == []
1648
+ 93 @key.children.count.should be(0)
1649
+ 94
1650
+ 95 @key.update_index # indexing 'message/publish/offensive'
1651
+ 96: Redistat::Key.new("PageViews", "message/public/die").update_index # indexing 'message/publish/die'
1652
+ 97: Redistat::Key.new("PageViews", "message/public/live").update_index # indexing 'message/publish/live'
1653
+ 98
1654
+ 99: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{@key.label.parent}") # checking 'message/public'
1655
+ 100 members.count.should be(3)
1656
+ 101 members.should include('offensive')
1657
+ ...
1658
+ 104
1659
+ 105 key = @key.parent
1660
+ 106: key.children.first.should be_a(Redistat::Key)
1661
+ 107 key.children.count.should be(3)
1662
+ 108 key.children.map { |k| k.label.me }.should == members
1663
+ 109
1664
+ 110: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{key.label.parent}") # checking 'message'
1665
+ 111 members.count.should be(1)
1666
+ 112 members.should include('public')
1667
+ ...
1668
+ 116 key.children.map { |k| k.label.me }.should == members
1669
+ 117
1670
+ 118: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}") # checking ''
1671
+ 119 members.count.should be(1)
1672
+ 120 members.should include('message')
1673
+ 121
1674
+ 122 key.parent.should be_nil
1675
+ 123: key = Redistat::Key.new("PageViews")
1676
+ 124 key.children.count.should be(1)
1677
+ 125 key.children.map { |k| k.label.me }.should include('message')
1678
+
1679
+ /Users/felipeclopes/projects/redisrank/spec/label_spec.rb:
1680
+ 1 require "spec_helper"
1681
+ 2
1682
+ 3: describe Redistat::Label do
1683
+ 4: include Redistat::Database
1684
+ 5
1685
+ 6 before(:each) do
1686
+ 7 db.flushdb
1687
+ 8 @name = "about_us"
1688
+ 9: @label = Redistat::Label.new(@name)
1689
+ 10 end
1690
+ 11
1691
+ ..
1692
+ 16
1693
+ 17 it "should store a label hash lookup key" do
1694
+ 18: label = Redistat::Label.new(@name, {:hashed_label => true}).save
1695
+ 19 label.saved?.should be(true)
1696
+ 20: db.hget(Redistat::KEY_LABELS, label.hash).should == @name
1697
+ 21
1698
+ 22 name = "contact_us"
1699
+ 23: label = Redistat::Label.create(name, {:hashed_label => true})
1700
+ 24 label.saved?.should be(true)
1701
+ 25: db.hget(Redistat::KEY_LABELS, label.hash).should == name
1702
+ 26 end
1703
+ 27
1704
+ 28 it "should join labels" do
1705
+ 29: include Redistat
1706
+ 30: label = Redistat::Label.join('email', 'message', 'public')
1707
+ 31: label.should be_a(Redistat::Label)
1708
+ 32 label.to_s.should == 'email/message/public'
1709
+ 33: label = Redistat::Label.join(Redistat::Label.new('email'), Redistat::Label.new('message'), Redistat::Label.new('public'))
1710
+ 34: label.should be_a(Redistat::Label)
1711
+ 35 label.to_s.should == 'email/message/public'
1712
+ 36: label = Redistat::Label.join('email', '', 'message', nil, 'public')
1713
+ 37: label.should be_a(Redistat::Label)
1714
+ 38 label.to_s.should == 'email/message/public'
1715
+ 39 end
1716
+ 40
1717
+ 41 it "should allow you to use a different group separator" do
1718
+ 42: include Redistat
1719
+ 43: Redistat.group_separator = '|'
1720
+ 44: label = Redistat::Label.join('email', 'message', 'public')
1721
+ 45: label.should be_a(Redistat::Label)
1722
+ 46 label.to_s.should == 'email|message|public'
1723
+ 47: label = Redistat::Label.join(Redistat::Label.new('email'), Redistat::Label.new('message'), Redistat::Label.new('public'))
1724
+ 48: label.should be_a(Redistat::Label)
1725
+ 49 label.to_s.should == 'email|message|public'
1726
+ 50: label = Redistat::Label.join('email', '', 'message', nil, 'public')
1727
+ 51: label.should be_a(Redistat::Label)
1728
+ 52 label.to_s.should == 'email|message|public'
1729
+ 53: Redistat.group_separator = Redistat::GROUP_SEPARATOR
1730
+ 54 end
1731
+ 55
1732
+ ..
1733
+ 57 before(:each) do
1734
+ 58 @name = "message/public/offensive"
1735
+ 59: @label = Redistat::Label.new(@name)
1736
+ 60 end
1737
+ 61
1738
+ 62 it "should know it's parent label group" do
1739
+ 63 @label.parent.to_s.should == 'message/public'
1740
+ 64: Redistat::Label.new('hello').parent.should be_nil
1741
+ 65 end
1742
+ 66
1743
+ ..
1744
+ 72
1745
+ 73 @name = "/message/public/"
1746
+ 74: @label = Redistat::Label.new(@name)
1747
+ 75 @label.name.should == @name
1748
+ 76 @label.groups.map { |l| l.to_s }.should == [ "message/public",
1749
+ ..
1750
+ 78
1751
+ 79 @name = "message"
1752
+ 80: @label = Redistat::Label.new(@name)
1753
+ 81 @label.name.should == @name
1754
+ 82 @label.groups.map { |l| l.to_s }.should == [ "message" ]
1755
+
1756
+ /Users/felipeclopes/projects/redisrank/spec/model_helper.rb:
1757
+ 1: require "redisrank"
1758
+ 2
1759
+ 3 class ModelHelper1
1760
+ 4: include Redistat::Model
1761
+ 5
1762
+ 6
1763
+ .
1764
+ 8
1765
+ 9 class ModelHelper2
1766
+ 10: include Redistat::Model
1767
+ 11
1768
+ 12 depth :day
1769
+ ..
1770
+ 17
1771
+ 18 class ModelHelper3
1772
+ 19: include Redistat::Model
1773
+ 20
1774
+ 21 connect_to :port => 8379, :db => 14
1775
+ ..
1776
+ 24
1777
+ 25 class ModelHelper4
1778
+ 26: include Redistat::Model
1779
+ 27
1780
+ 28 scope "FancyHelper"
1781
+
1782
+ /Users/felipeclopes/projects/redisrank/spec/model_spec.rb:
1783
+ 2 require "model_helper"
1784
+ 3
1785
+ 4: describe Redistat::Model do
1786
+ 5: include Redistat::Database
1787
+ 6
1788
+ 7 before(:each) do
1789
+ .
1790
+ 22 one_hour_ago = 1.hour.ago
1791
+ 23 finder = ModelHelper1.find('label', two_hours_ago, one_hour_ago)
1792
+ 24: finder.should be_a(Redistat::Finder)
1793
+ 25 finder.options[:scope].to_s.should == 'ModelHelper1'
1794
+ 26 finder.options[:label].to_s.should == 'label'
1795
+ ..
1796
+ 30
1797
+ 31 it "should #find_event" do
1798
+ 32: Redistat::Event.should_receive(:find).with('ModelHelper1', 1)
1799
+ 33 ModelHelper1.find_event(1)
1800
+ 34 end
1801
+ ..
1802
+ 151 describe "Write Buffer" do
1803
+ 152 before(:each) do
1804
+ 153: Redistat.buffer_size = 20
1805
+ 154 end
1806
+ 155
1807
+ 156 after(:each) do
1808
+ 157: Redistat.buffer_size = 0
1809
+ 158 end
1810
+ 159
1811
+ ...
1812
+ 181 end
1813
+ 182 ModelHelper1.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1)).rank.should == {}
1814
+ 183: Redistat.buffer.flush(true)
1815
+ 184
1816
+ 185 stats = ModelHelper1.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
1817
+
1818
+ /Users/felipeclopes/projects/redisrank/spec/options_spec.rb:
1819
+ 1 require "spec_helper"
1820
+ 2
1821
+ 3: describe Redistat::Options do
1822
+ 4
1823
+ 5 before(:each) do
1824
+ .
1825
+ 24
1826
+ 25 class OptionsHelper
1827
+ 26: include Redistat::Options
1828
+ 27
1829
+ 28 option_accessor :hello
1830
+
1831
+ /Users/felipeclopes/projects/redisrank/spec/result_spec.rb:
1832
+ 1 require "spec_helper"
1833
+ 2
1834
+ 3: describe Redistat::Result do
1835
+ 4
1836
+ 5 it "should should initialize properly" do
1837
+ 6 options = {:from => "from", :till => "till"}
1838
+ 7: result = Redistat::Result.new(options)
1839
+ 8 result.from.should == "from"
1840
+ 9 result.till.should == "till"
1841
+ ..
1842
+ 11
1843
+ 12 it "should have merge_to_max method" do
1844
+ 13: result = Redistat::Result.new
1845
+ 14 result[:world].should be_nil
1846
+ 15 result.merge_to_max(:world, 3)
1847
+
1848
+ /Users/felipeclopes/projects/redisrank/spec/scope_spec.rb:
1849
+ 1 require "spec_helper"
1850
+ 2
1851
+ 3: describe Redistat::Scope do
1852
+ 4: include Redistat::Database
1853
+ 5
1854
+ 6 before(:all) do
1855
+ .
1856
+ 10 before(:each) do
1857
+ 11 @name = "PageViews"
1858
+ 12: @scope = Redistat::Scope.new(@name)
1859
+ 13 end
1860
+ 14
1861
+ ..
1862
+ 18
1863
+ 19 it "should increment next_id" do
1864
+ 20: scope = Redistat::Scope.new("Visitors")
1865
+ 21 @scope.next_id.should == 1
1866
+ 22 scope.next_id.should == 1
1867
+
1868
+ /Users/felipeclopes/projects/redisrank/spec/spec_helper.rb:
1869
+ 10
1870
+ 11 # require stuff
1871
+ 12: require 'redisrank'
1872
+ 13 require 'rspec'
1873
+ 14 require 'rspec/autorun'
1874
+ 15
1875
+ 16: # use the test Redistat instance
1876
+ 17: Redistat.connect(:port => 8379, :db => 15, :thread_safe => true)
1877
+ 18: Redistat.redis.flushdb
1878
+ 19
1879
+
1880
+ /Users/felipeclopes/projects/redisrank/spec/summary_spec.rb:
1881
+ 1 require "spec_helper"
1882
+ 2
1883
+ 3: describe Redistat::Summary do
1884
+ 4: include Redistat::Database
1885
+ 5
1886
+ 6 before(:each) do
1887
+ .
1888
+ 9 @label = "about_us"
1889
+ 10 @date = Time.now
1890
+ 11: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
1891
+ 12 @stats = {"views" => 3, "visitors" => 2}
1892
+ 13 @expire = {:hour => 24*3600}
1893
+ ..
1894
+ 15
1895
+ 16 it "should update a single summary properly" do
1896
+ 17: Redistat::Summary.send(:update_fields, @key, @stats, :hour)
1897
+ 18 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
1898
+ 19 expect(summary.count).to be 2
1899
+ ..
1900
+ 25 expect(visitors.last).to be 2.0
1901
+ 26
1902
+ 27: Redistat::Summary.send(:update_fields, @key, @stats, :hour)
1903
+ 28 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
1904
+ 29 expect(summary.count).to be 2
1905
+ ..
1906
+ 37
1907
+ 38 it "should set key expiry properly" do
1908
+ 39: Redistat::Summary.update_all(@key, @stats, :hour,{:expire => @expire})
1909
+ 40 ((24*3600)-1..(24*3600)+1).should include(db.ttl(@key.to_s(:hour)))
1910
+ 41 [:day, :month, :year].each do |depth|
1911
+ ..
1912
+ 44
1913
+ 45 db.flushdb
1914
+ 46: Redistat::Summary.update_all(@key, @stats, :hour, {:expire => {}})
1915
+ 47 [:hour, :day, :month, :year].each do |depth|
1916
+ 48 db.ttl(@key.to_s(depth)).should == -1
1917
+ ..
1918
+ 51
1919
+ 52 it "should update all summaries properly" do
1920
+ 53: Redistat::Summary.update_all(@key, @stats, :sec)
1921
+ 54 [:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
1922
+ 55 summary = db.zrevrange(@key.to_s(depth), 0, -1, :with_scores => true)
1923
+ ..
1924
+ 69
1925
+ 70 it "should update summaries even if no label is set" do
1926
+ 71: key = Redistat::Key.new(@scope, nil, @date, {:depth => :day})
1927
+ 72: Redistat::Summary.send(:update_fields, key, @stats, :hour)
1928
+ 73 summary = db.zrevrange(key.to_s(:hour), 0, -1, :with_scores => true)
1929
+ 74 views = summary.first
1930
+ ..
1931
+ 84 "death/bomb" => 4, "death/unicorn" => 3,
1932
+ 85 :"od/sugar" => 7, :"od/meth" => 8 }
1933
+ 86: res = Redistat::Summary.send(:inject_group_summaries, hash)
1934
+ 87 res.should == { "count" => 10, "count/hello" => 3, "count/world" => 7,
1935
+ 88 "death" => 7, "death/bomb" => 4, "death/unicorn" => 3,
1936
+ ..
1937
+ 92 it "should properly store key group summaries" do
1938
+ 93 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
1939
+ 94: Redistat::Summary.update_all(@key, stats, :hour)
1940
+ 95 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
1941
+ 96 summary.count.should eq(4)
1942
+ ..
1943
+ 109 it "should not store key group summaries when option is disabled" do
1944
+ 110 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
1945
+ 111: Redistat::Summary.update_all(@key, stats, :hour, {:enable_grouping => false})
1946
+ 112 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
1947
+ 113 summary.count.should eq(3)
1948
+ ...
1949
+ 125 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
1950
+ 126 label = "views/about_us"
1951
+ 127: key = Redistat::Key.new(@scope, label, @date)
1952
+ 128: Redistat::Summary.update_all(key, stats, :hour)
1953
+ 129
1954
+ 130 key.groups[0].label.to_s.should == "views/about_us"
1955
+ ...
1956
+ 134
1957
+ 135 label = "views/contact"
1958
+ 136: key = Redistat::Key.new(@scope, label, @date)
1959
+ 137: Redistat::Summary.update_all(key, stats, :hour)
1960
+ 138
1961
+ 139 key.groups[0].label.to_s.should == "views/contact"
1962
+
1963
+ /Users/felipeclopes/projects/redisrank/spec/synchronize_spec.rb:
1964
+ 1 require "spec_helper"
1965
+ 2
1966
+ 3: module Redistat
1967
+ 4 describe Synchronize do
1968
+ 5
1969
+ .
1970
+ 62
1971
+ 63 describe '.monitor' do
1972
+ 64: it 'defers to Redistat::Synchronize' do
1973
+ 65 klass.should_receive(:monitor).once
1974
+ 66 subject.monitor
1975
+ ..
1976
+ 69
1977
+ 70 describe '.thread_safe' do
1978
+ 71: it ' defers to Redistat::Synchronize' do
1979
+ 72 klass.should_receive(:thread_safe).once
1980
+ 73 subject.thread_safe
1981
+ ..
1982
+ 76
1983
+ 77 describe '.thread_safe=' do
1984
+ 78: it 'defers to Redistat::Synchronize' do
1985
+ 79 klass.should_receive(:thread_safe=).once.with(true)
1986
+ 80 subject.thread_safe = true
1987
+ ..
1988
+ 119
1989
+ 120 end # Synchronize
1990
+ 121: end # Redistat
1991
+ 122
1992
+ 123 class SynchronizeSpecHelper
1993
+ 124: include Redistat::Synchronize
1994
+ 125 end
1995
+ 126
1996
+
1997
+ /Users/felipeclopes/projects/redisrank/spec/thread_safety_spec.rb:
1998
+ 2
1999
+ 3 describe "Thread-Safety" do
2000
+ 4: include Redistat::Database
2001
+ 5
2002
+ 6 before(:each) do
2003
+ .
2004
+ 23 it "should store event in multiple threads" do
2005
+ 24 class ThreadSafetySpec
2006
+ 25: include Redistat::Model
2007
+ 26 end
2008
+ 27 threads = []
2009
+
2010
+ 467 matches across 50 files
2011
+
2012
+
2013
+ Searching 85 files for "Redistat" (case sensitive)
2014
+
2015
+ /Users/felipeclopes/projects/redisrank/coverage/index.html:
2016
+ 564 <span class="hits">1</span>
2017
+ 565
2018
+ 566: <code class="ruby">module Redistat</code>
2019
+ 567 </li>
2020
+ 568
2021
+ ...
2022
+ 588 <span class="hits">1</span>
2023
+ 589
2024
+ 590: <code class="ruby"> KEY_LABELS = &quot;Redistat.labels:&quot; # used for reverse label hash lookup</code>
2025
+ 591 </li>
2026
+ 592
2027
+ ...
2028
+ 858
2029
+ 859
2030
+ 860: <code class="ruby"> puts &quot;WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead.&quot;</code>
2031
+ 861 </li>
2032
+ 862
2033
+ ...
2034
+ 948 <span class="hits">1</span>
2035
+ 949
2036
+ 950: <code class="ruby"> Redistat.buffer.flush(true)</code>
2037
+ 951 </li>
2038
+ 952
2039
+ ...
2040
+ 990 <span class="hits">1</span>
2041
+ 991
2042
+ 992: <code class="ruby">module Redistat</code>
2043
+ 993 </li>
2044
+ 994
2045
+ ...
2046
+ 1656 <span class="hits">1</span>
2047
+ 1657
2048
+ 1658: <code class="ruby">module Redistat</code>
2049
+ 1659 </li>
2050
+ 1660
2051
+ ....
2052
+ 1806 <span class="hits">1</span>
2053
+ 1807
2054
+ 1808: <code class="ruby">module Redistat</code>
2055
+ 1809 </li>
2056
+ 1810
2057
+ ....
2058
+ 2400 <span class="hits">1</span>
2059
+ 2401
2060
+ 2402: <code class="ruby"> include Redistat::DateHelper</code>
2061
+ 2403 </li>
2062
+ 2404
2063
+ ....
2064
+ 2466 <span class="hits">1</span>
2065
+ 2467
2066
+ 2468: <code class="ruby"> include Redistat::DateHelper</code>
2067
+ 2469 </li>
2068
+ 2470
2069
+ ....
2070
+ 2532 <span class="hits">1</span>
2071
+ 2533
2072
+ 2534: <code class="ruby"> include Redistat::DateHelper</code>
2073
+ 2535 </li>
2074
+ 2536
2075
+ ....
2076
+ 2736 <span class="hits">1</span>
2077
+ 2737
2078
+ 2738: <code class="ruby"> include Redistat::DateHelper</code>
2079
+ 2739 </li>
2080
+ 2740
2081
+ ....
2082
+ 2766 <span class="hits">1</span>
2083
+ 2767
2084
+ 2768: <code class="ruby">module Redistat</code>
2085
+ 2769 </li>
2086
+ 2770
2087
+ ....
2088
+ 3312 <span class="hits">1</span>
2089
+ 3313
2090
+ 3314: <code class="ruby">module Redistat</code>
2091
+ 3315 </li>
2092
+ 3316
2093
+ ....
2094
+ 3930 <span class="hits">1</span>
2095
+ 3931
2096
+ 3932: <code class="ruby">module Redistat</code>
2097
+ 3933 </li>
2098
+ 3934
2099
+ ....
2100
+ 5406 <span class="hits">1</span>
2101
+ 5407
2102
+ 5408: <code class="ruby">module Redistat</code>
2103
+ 5409 </li>
2104
+ 5410
2105
+ ....
2106
+ 6018 <span class="hits">1</span>
2107
+ 6019
2108
+ 6020: <code class="ruby">module Redistat</code>
2109
+ 6021 </li>
2110
+ 6022
2111
+ ....
2112
+ 6162 <span class="hits">313</span>
2113
+ 6163
2114
+ 6164: <code class="ruby"> @date = (input.instance_of?(Redistat::Date)) ? input : Date.new(input) # Redistat::Date, not ::Date</code>
2115
+ 6165 </li>
2116
+ 6166
2117
+ ....
2118
+ 6240 <span class="hits">312</span>
2119
+ 6241
2120
+ 6242: <code class="ruby"> @scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)</code>
2121
+ 6243 </li>
2122
+ 6244
2123
+ ....
2124
+ 6270 <span class="hits">310</span>
2125
+ 6271
2126
+ 6272: <code class="ruby"> @label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)</code>
2127
+ 6273 </li>
2128
+ 6274
2129
+ ....
2130
+ 6366 <span class="hits">19</span>
2131
+ 6367
2132
+ 6368: <code class="ruby"> self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options)</code>
2133
+ 6369 </li>
2134
+ 6370
2135
+ ....
2136
+ 6540 <span class="hits">1</span>
2137
+ 6541
2138
+ 6542: <code class="ruby">module Redistat</code>
2139
+ 6543 </li>
2140
+ 6544
2141
+ ....
2142
+ 6630 <span class="hits">28</span>
2143
+ 6631
2144
+ 6632: <code class="ruby"> self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator))</code>
2145
+ 6633 </li>
2146
+ 6634
2147
+ ....
2148
+ 6840 <span class="hits">109</span>
2149
+ 6841
2150
+ 6842: <code class="ruby"> self.to_s.split(Redistat.group_separator).last</code>
2151
+ 6843 </li>
2152
+ 6844
2153
+ ....
2154
+ 6882 <span class="hits">266</span>
2155
+ 6883
2156
+ 6884: <code class="ruby"> self.to_s.split(Redistat.group_separator).each do |part|</code>
2157
+ 6885 </li>
2158
+ 6886
2159
+ ....
2160
+ 6894 <span class="hits">324</span>
2161
+ 6895
2162
+ 6896: <code class="ruby"> group = ((parent.blank?) ? &quot;&quot; : &quot;#{parent}#{Redistat.group_separator}&quot;) + part</code>
2163
+ 6897 </li>
2164
+ 6898
2165
+ ....
2166
+ 6972 <span class="hits">1</span>
2167
+ 6973
2168
+ 6974: <code class="ruby">module Redistat</code>
2169
+ 6975 </li>
2170
+ 6976
2171
+ ....
2172
+ 7014 <span class="hits">1667</span>
2173
+ 7015
2174
+ 7016: <code class="ruby"> Redistat.connection(ref)</code>
2175
+ 7017 </li>
2176
+ 7018
2177
+ ....
2178
+ 7056 <span class="hits">1</span>
2179
+ 7057
2180
+ 7058: <code class="ruby">module Redistat</code>
2181
+ 7059 </li>
2182
+ 7060
2183
+ ....
2184
+ 7074 <span class="hits">544</span>
2185
+ 7075
2186
+ 7076: <code class="ruby"> Redistat::Date.new(self, depth)</code>
2187
+ 7077 </li>
2188
+ 7078
2189
+ ....
2190
+ 7122 <span class="hits">1</span>
2191
+ 7123
2192
+ 7124: <code class="ruby">module Redistat</code>
2193
+ 7125 </li>
2194
+ 7126
2195
+ ....
2196
+ 7398 <span class="hits">1</span>
2197
+ 7399
2198
+ 7400: <code class="ruby">module Redistat</code>
2199
+ 7401 </li>
2200
+ 7402
2201
+ ....
2202
+ 7716 <span class="hits">1</span>
2203
+ 7717
2204
+ 7718: <code class="ruby">module Redistat</code>
2205
+ 7719 </li>
2206
+ 7720
2207
+ ....
2208
+ 8208 <span class="hits">1</span>
2209
+ 8209
2210
+ 8210: <code class="ruby">module Redistat</code>
2211
+ 8211 </li>
2212
+ 8212
2213
+ ....
2214
+ 8322 <span class="hits">1</span>
2215
+ 8323
2216
+ 8324: <code class="ruby">module Redistat</code>
2217
+ 8325 </li>
2218
+ 8326
2219
+ ....
2220
+ 8448 <span class="hits">1</span>
2221
+ 8449
2222
+ 8450: <code class="ruby">module Redistat</code>
2223
+ 8451 </li>
2224
+ 8452
2225
+ ....
2226
+ 8544 <span class="hits">105</span>
2227
+ 8545
2228
+ 8546: <code class="ruby"> Redistat.buffer</code>
2229
+ 8547 </li>
2230
+ 8548
2231
+ ....
2232
+ 8862 <span class="hits">151</span>
2233
+ 8863
2234
+ 8864: <code class="ruby"> parts = key.to_s.split(Redistat.group_separator)</code>
2235
+ 8865 </li>
2236
+ 8866
2237
+ ....
2238
+ 8898 <span class="hits">12</span>
2239
+ 8899
2240
+ 8900: <code class="ruby"> sum_key = sum_parts.join(Redistat.group_separator)</code>
2241
+ 8901 </li>
2242
+ 8902
2243
+
2244
+ /Users/felipeclopes/projects/redisrank/lib/redisrank.rb:
2245
+ 39
2246
+ 40
2247
+ 41: module Redistat
2248
+ 42
2249
+ 43 KEY_NEXT_ID = ".next_id"
2250
+ 44 KEY_EVENT = ".event:"
2251
+ 45: KEY_LABELS = "Redistat.labels:" # used for reverse label hash lookup
2252
+ 46 KEY_EVENT_IDS = ".event_ids"
2253
+ 47 LABEL_INDEX = ".label_index:"
2254
+ ..
2255
+ 88
2256
+ 89 def flush
2257
+ 90: puts "WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead."
2258
+ 91 connection.flushdb
2259
+ 92 end
2260
+ ..
2261
+ 103 # ensure buffer is flushed on program exit
2262
+ 104 Kernel.at_exit do
2263
+ 105: Redistat.buffer.flush(true)
2264
+ 106 end
2265
+ 107
2266
+
2267
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/buffer.rb:
2268
+ 1 require 'redisrank/core_ext/hash'
2269
+ 2
2270
+ 3: module Redistat
2271
+ 4 class Buffer
2272
+ 5 include Synchronize
2273
+
2274
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/collection.rb:
2275
+ 1: module Redistat
2276
+ 2 class Collection < ::Array
2277
+ 3
2278
+
2279
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/connection.rb:
2280
+ 1 require 'monitor'
2281
+ 2
2282
+ 3: module Redistat
2283
+ 4 module Connection
2284
+ 5
2285
+
2286
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/bignum.rb:
2287
+ 1 class Bignum
2288
+ 2: include Redistat::DateHelper
2289
+ 3
2290
+ 4 def to_time
2291
+
2292
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/date.rb:
2293
+ 1 class Date
2294
+ 2: include Redistat::DateHelper
2295
+ 3
2296
+ 4 def to_time
2297
+
2298
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/fixnum.rb:
2299
+ 1 class Fixnum
2300
+ 2: include Redistat::DateHelper
2301
+ 3
2302
+ 4 def to_time
2303
+
2304
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/core_ext/time.rb:
2305
+ 1 class Time
2306
+ 2: include Redistat::DateHelper
2307
+ 3 end
2308
+ 4
2309
+
2310
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/date.rb:
2311
+ 1: module Redistat
2312
+ 2 class Date
2313
+ 3
2314
+
2315
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/event.rb:
2316
+ 1: module Redistat
2317
+ 2 class Event
2318
+ 3 include Database
2319
+
2320
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/finder.rb:
2321
+ 1 require 'redisrank/finder/date_set'
2322
+ 2
2323
+ 3: module Redistat
2324
+ 4 class Finder
2325
+ 5 include Database
2326
+
2327
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/finder/date_set.rb:
2328
+ 1: module Redistat
2329
+ 2 class Finder
2330
+ 3 class DateSet < Array
2331
+
2332
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/key.rb:
2333
+ 1: module Redistat
2334
+ 2 class Key
2335
+ 3 include Database
2336
+ .
2337
+ 23
2338
+ 24 def date=(input)
2339
+ 25: @date = (input.instance_of?(Redistat::Date)) ? input : Date.new(input) # Redistat::Date, not ::Date
2340
+ 26 end
2341
+ 27 attr_reader :date
2342
+ ..
2343
+ 36
2344
+ 37 def scope=(input)
2345
+ 38: @scope = (input.instance_of?(Redistat::Scope)) ? input : Scope.new(input)
2346
+ 39 end
2347
+ 40 attr_reader :scope
2348
+ 41
2349
+ 42 def label=(input)
2350
+ 43: @label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)
2351
+ 44 end
2352
+ 45 attr_reader :label
2353
+ ..
2354
+ 57 members.map { |member|
2355
+ 58 child_label = [@label, member].reject { |i| i.nil? }
2356
+ 59: self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options)
2357
+ 60 }
2358
+ 61 end
2359
+
2360
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/label.rb:
2361
+ 1: module Redistat
2362
+ 2 class Label
2363
+ 3 include Database
2364
+ .
2365
+ 14 def self.join(*args)
2366
+ 15 args = args.map {|i| i.to_s}
2367
+ 16: self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator))
2368
+ 17 end
2369
+ 18
2370
+ ..
2371
+ 49
2372
+ 50 def me
2373
+ 51: self.to_s.split(Redistat.group_separator).last
2374
+ 52 end
2375
+ 53
2376
+ ..
2377
+ 56 @groups = []
2378
+ 57 parent = ""
2379
+ 58: self.to_s.split(Redistat.group_separator).each do |part|
2380
+ 59 if !part.blank?
2381
+ 60: group = ((parent.blank?) ? "" : "#{parent}#{Redistat.group_separator}") + part
2382
+ 61 @groups << Label.new(group)
2383
+ 62 parent = group
2384
+
2385
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/database.rb:
2386
+ 1: module Redistat
2387
+ 2 module Database
2388
+ 3 def self.included(base)
2389
+ .
2390
+ 6 def db(ref = nil)
2391
+ 7 ref ||= @options[:connection_ref] if !@options.nil?
2392
+ 8: Redistat.connection(ref)
2393
+ 9 end
2394
+ 10 end
2395
+
2396
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/date_helper.rb:
2397
+ 1: module Redistat
2398
+ 2 module DateHelper
2399
+ 3 def to_redisrank(depth = nil)
2400
+ 4: Redistat::Date.new(self, depth)
2401
+ 5 end
2402
+ 6 alias :to_rs :to_redisrank
2403
+
2404
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/options.rb:
2405
+ 1: module Redistat
2406
+ 2 module Options
2407
+ 3
2408
+
2409
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/mixins/synchronize.rb:
2410
+ 1 require 'monitor'
2411
+ 2
2412
+ 3: module Redistat
2413
+ 4 module Synchronize
2414
+ 5
2415
+
2416
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/model.rb:
2417
+ 1: module Redistat
2418
+ 2 module Model
2419
+ 3 include Database
2420
+
2421
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/result.rb:
2422
+ 1 require 'active_support/core_ext/hash/indifferent_access'
2423
+ 2
2424
+ 3: module Redistat
2425
+ 4 class Result < HashWithIndifferentAccess
2426
+ 5
2427
+
2428
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/scope.rb:
2429
+ 1: module Redistat
2430
+ 2 class Scope
2431
+ 3 include Database
2432
+
2433
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/summary.rb:
2434
+ 1: module Redistat
2435
+ 2 class Summary
2436
+ 3 include Database
2437
+ .
2438
+ 15
2439
+ 16 def buffer
2440
+ 17: Redistat.buffer
2441
+ 18 end
2442
+ 19
2443
+ ..
2444
+ 68 summaries = {}
2445
+ 69 stats.each do |key, value|
2446
+ 70: parts = key.to_s.split(Redistat.group_separator)
2447
+ 71 parts.pop
2448
+ 72 if parts.size > 0
2449
+ ..
2450
+ 74 parts.each do |part|
2451
+ 75 sum_parts << part
2452
+ 76: sum_key = sum_parts.join(Redistat.group_separator)
2453
+ 77 (summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value
2454
+ 78 end
2455
+
2456
+ /Users/felipeclopes/projects/redisrank/lib/redisrank/version.rb:
2457
+ 1: module Redistat
2458
+ 2 VERSION = "0.5.0"
2459
+ 3 end
2460
+
2461
+ /Users/felipeclopes/projects/redisrank/Rakefile:
2462
+ 63 #
2463
+ 64
2464
+ 65: desc "Start an irb console with Redistat pre-loaded."
2465
+ 66 task :console do
2466
+ 67 exec "irb -r spec/spec_helper"
2467
+
2468
+ /Users/felipeclopes/projects/redisrank/README.md:
2469
+ 1: # Redistat [![Build Status](https://secure.travis-ci.org/jimeh/redisrank.png)](http://travis-ci.org/jimeh/redisrank)
2470
+ 2
2471
+ 3 A Redis-backed statistics storage and querying library written in Ruby.
2472
+ 4
2473
+ 5: Redistat was originally created to replace a small hacked together statistics
2474
+ 6 collection solution which was MySQL-based. When I started I had a short list
2475
+ 7 of requirements:
2476
+ .
2477
+ 31
2478
+ 32 class ViewStats
2479
+ 33: include Redistat::Model
2480
+ 34 end
2481
+ 35
2482
+ 36: # if using Redistat in multiple threads set this
2483
+ 37 # somewhere in the beginning of the execution stack
2484
+ 38: Redistat.thread_safe = true
2485
+ 39 ```
2486
+ 40
2487
+ ..
2488
+ 118 ```
2489
+ 119
2490
+ 120: Fetch list of products known to Redistat:
2491
+ 121
2492
+ 122 ```ruby
2493
+ ...
2494
+ 136 ### Scope
2495
+ 137
2496
+ 138: A type of global-namespace for storing data. When using the `Redistat::Model`
2497
+ 139 wrapper, the scope is automatically set to the class name. In the examples
2498
+ 140 above, the scope is `ViewStats`. Can be overridden by calling the `#scope`
2499
+ ...
2500
+ 151 label called `views/product/44`, the data is stored for the label you specify,
2501
+ 152 and also for `views/product` and `views`. You may also configure a different
2502
+ 153: group separator using the `Redistat.group_separator=` method. For example:
2503
+ 154
2504
+ 155 ```ruby
2505
+ 156: Redistat.group_separator = '|'
2506
+ 157 ```
2507
+ 158
2508
+ ...
2509
+ 164 ### Input Statistics Data
2510
+ 165
2511
+ 166: You provide Redistat with the data you want to store using a Ruby Hash. This
2512
+ 167 data is then stored in a corresponding Redis hash with identical key/field
2513
+ 168 names.
2514
+ ...
2515
+ 175
2516
+ 176 Define how accurately data should be stored, and how accurately it's looked up
2517
+ 177: when fetching it again. By default Redistat uses a depth value of `:hour`,
2518
+ 178 which means it's impossible to separate two events which were stored at 10:18
2519
+ 179 and 10:23. In Redis they are both stored within a date key of `2011031610`.
2520
+ ...
2521
+ 186 When you fetch data, you need to specify a start and an end time. The
2522
+ 187 selection behavior can seem a bit weird at first when, but makes sense when
2523
+ 188: you understand how Redistat works internally.
2524
+ 189
2525
+ 190 For example, if we are using a Depth value of `:hour`, and we trigger a fetch
2526
+ ...
2527
+ 197 ### The Finder Object
2528
+ 198
2529
+ 199: Calling the `#find` method on a Redistat model class returns a
2530
+ 200: `Redistat::Finder` object. The finder is a lazy-loaded gateway to your
2531
+ 201 data. Meaning you can create a new finder, and modify instantiated finder's
2532
+ 202 label, scope, dates, and more. It does not call Redis and fetch the data until
2533
+ ...
2534
+ 222 ```ruby
2535
+ 223 class ViewStats
2536
+ 224: include Redistat::Model
2537
+ 225
2538
+ 226 depth :sec
2539
+ ...
2540
+ 243 ### Storing / Writing
2541
+ 244
2542
+ 245: Redistat stores all data into a Redis hash keys. The Redis key name the used
2543
+ 246 consists of three parts. The scope, label, and datetime:
2544
+ 247
2545
+ ...
2546
+ 296 ### Fetching / Reading
2547
+ 297
2548
+ 298: By default when fetching statistics, Redistat will figure out how to do the
2549
+ 299 least number of reads from Redis. First it checks how long range you're
2550
+ 300 fetching. If whole days, months or years for example fit within the start and
2551
+ ...
2552
+ 310
2553
+ 311 The buffer is a new, still semi-beta, feature aimed to reduce the number of
2554
+ 312: Redis `hincrby` that Redistat sends. This should only really be useful when
2555
+ 313 you're hitting north of 30,000 Redis requests per second, if your Redis server
2556
+ 314 has limited resources, or against my recommendation you've opted to use 10,
2557
+ ...
2558
+ 318 possible by merging the statistics hashes from all calls and groups them based
2559
+ 319 on scope, label, date depth, and more. You configure the the buffer by setting
2560
+ 320: `Redistat.buffer_size` to an integer higher than 1. This basically tells
2561
+ 321: Redistat how many `store` calls to buffer in memory before writing all data to
2562
+ 322 Redis.
2563
+ 323
2564
+ ...
2565
+ 333
2566
+ 334 [Global Personals](http://globalpersonals.co.uk/) deserves a thank
2567
+ 335: you. Currently the primary user of Redistat, they've allowed me to spend some
2568
+ 336 company time to further develop the project.
2569
+ 337
2570
+
2571
+ /Users/felipeclopes/projects/redisrank/redisrank.gemspec:
2572
+ 5 Gem::Specification.new do |s|
2573
+ 6 s.name = "redisrank"
2574
+ 7: s.version = Redistat::VERSION
2575
+ 8 s.platform = Gem::Platform::RUBY
2576
+ 9 s.authors = ["Jim Myhrberg"]
2577
+
2578
+ /Users/felipeclopes/projects/redisrank/spec/buffer_spec.rb:
2579
+ 1 require "spec_helper"
2580
+ 2
2581
+ 3: describe Redistat::Buffer do
2582
+ 4
2583
+ 5 before(:each) do
2584
+ 6: @class = Redistat::Buffer
2585
+ 7: @buffer = Redistat::Buffer.instance
2586
+ 8 @key = double("Key", :to_s => "Scope/label:2011")
2587
+ 9 @stats = {:count => 1, :views => 3}
2588
+ ..
2589
+ 73 }}
2590
+ 74 item = data.first[1]
2591
+ 75: Redistat::Summary.should_receive(:update).with(@key, @stats, @depth_limit, @opts)
2592
+ 76 @buffer.send(:flush_data, data)
2593
+ 77 end
2594
+
2595
+ /Users/felipeclopes/projects/redisrank/spec/collection_spec.rb:
2596
+ 1 require "spec_helper"
2597
+ 2
2598
+ 3: describe Redistat::Collection do
2599
+ 4
2600
+ 5 it "should initialize properly" do
2601
+ 6 options = {:from => "from", :till => "till", :depth => "depth"}
2602
+ 7: result = Redistat::Collection.new(options)
2603
+ 8 result.from.should == options[:from]
2604
+ 9 result.till.should == options[:till]
2605
+ ..
2606
+ 12
2607
+ 13 it "should have a rank property" do
2608
+ 14: col = Redistat::Collection.new()
2609
+ 15 col.rank.should == {}
2610
+ 16 col.rank = {:foo => "bar"}
2611
+
2612
+ /Users/felipeclopes/projects/redisrank/spec/connection_spec.rb:
2613
+ 1 require "spec_helper"
2614
+ 2: include Redistat
2615
+ 3
2616
+ 4: describe Redistat::Connection do
2617
+ 5
2618
+ 6 before(:each) do
2619
+ 7: @redis = Redistat.redis
2620
+ 8 end
2621
+ 9
2622
+ 10 it "should have a valid Redis client instance" do
2623
+ 11: Redistat.redis.should_not be_nil
2624
+ 12 end
2625
+ 13
2626
+ ..
2627
+ 34 end
2628
+ 35
2629
+ 36: it "should be accessible from Redistat module" do
2630
+ 37: Redistat.redis.should == Connection.get
2631
+ 38: Redistat.redis.should == Redistat.connection
2632
+ 39 end
2633
+ 40
2634
+ 41 it "should handle multiple connections with refs" do
2635
+ 42: Redistat.redis.client.db.should == 15
2636
+ 43: Redistat.connect(:port => 8379, :db => 14, :ref => "Custom")
2637
+ 44: Redistat.redis.client.db.should == 15
2638
+ 45: Redistat.redis("Custom").client.db.should == 14
2639
+ 46 end
2640
+ 47
2641
+ 48 it "should be able to overwrite default and custom refs" do
2642
+ 49: Redistat.redis.client.db.should == 15
2643
+ 50: Redistat.connect(:port => 8379, :db => 14)
2644
+ 51: Redistat.redis.client.db.should == 14
2645
+ 52
2646
+ 53: Redistat.redis("Custom").client.db.should == 14
2647
+ 54: Redistat.connect(:port => 8379, :db => 15, :ref => "Custom")
2648
+ 55: Redistat.redis("Custom").client.db.should == 15
2649
+ 56
2650
+ 57 # Reset the default connection to the testing server or all hell
2651
+ 58 # might brake loose from the rest of the specs
2652
+ 59: Redistat.connect(:port => 8379, :db => 15)
2653
+ 60 end
2654
+ 61
2655
+
2656
+ /Users/felipeclopes/projects/redisrank/spec/database_spec.rb:
2657
+ 1 require "spec_helper"
2658
+ 2
2659
+ 3: describe Redistat::Database do
2660
+ 4: include Redistat::Database
2661
+ 5
2662
+ 6 it "should make #db method available when included" do
2663
+ 7: db.should == Redistat.redis
2664
+ 8 end
2665
+ 9
2666
+
2667
+ /Users/felipeclopes/projects/redisrank/spec/date_spec.rb:
2668
+ 1 require "spec_helper"
2669
+ 2
2670
+ 3: describe Redistat::Date do
2671
+ 4
2672
+ 5 it "should initialize from Time object" do
2673
+ 6 now = Time.now
2674
+ 7: [Redistat::Date.new(now), now.to_rs].each do |rdate|
2675
+ 8: Redistat::Date::DEPTHS.each { |k| rdate.send(k).should == now.send(k) }
2676
+ 9 end
2677
+ 10 end
2678
+ ..
2679
+ 12 it "should initialize from Date object" do
2680
+ 13 today = Date.today
2681
+ 14: [Redistat::Date.new(today), today.to_rs].each do |rdate|
2682
+ 15 [:year, :month, :day].each { |k| rdate.send(k).should == today.send(k) }
2683
+ 16 [:hour, :min, :sec, :usec].each { |k| rdate.send(k).should == 0 }
2684
+ ..
2685
+ 21 now = Time.now.to_i
2686
+ 22 time = Time.at(now)
2687
+ 23: [Redistat::Date.new(now), now.to_rs].each do |rdate|
2688
+ 24 [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == time.send(k) }
2689
+ 25 end
2690
+ ..
2691
+ 28 it "should initialize from String object" do
2692
+ 29 now = Time.now
2693
+ 30: rdate = Redistat::Date.new(now.to_s)
2694
+ 31 [:year, :month, :day, :hour, :min, :sec].each { |k| rdate.send(k).should == now.send(k) }
2695
+ 32 end
2696
+ 33
2697
+ 34: it "should initialize from Redistat date String" do
2698
+ 35 now = Time.now
2699
+ 36: rdate = Redistat::Date.new(now.to_s)
2700
+ 37 [:year, :month, :day, :hour, :min, :sec].each { |k|
2701
+ 38: rdate.to_s(k).should == Redistat::Date.new(rdate.to_s(k)).to_s(k)
2702
+ 39 }
2703
+ 40 end
2704
+ ..
2705
+ 42 it "should convert to Time object" do
2706
+ 43 now = Time.now
2707
+ 44: rdate = Redistat::Date.new(now)
2708
+ 45 rdate.to_time.to_s.should == now.to_s
2709
+ 46 end
2710
+ ..
2711
+ 48 it "should convert to Date object" do
2712
+ 49 today = Date.today
2713
+ 50: rdate = Redistat::Date.new(today)
2714
+ 51 rdate.to_date.to_s.should == today.to_s
2715
+ 52 end
2716
+ ..
2717
+ 54 it "should convert to Fixnum object (UNIX Timestamp)" do
2718
+ 55 now = Time.now
2719
+ 56: rdate = Redistat::Date.new(now)
2720
+ 57 rdate.to_i.should == now.to_i
2721
+ 58 end
2722
+ ..
2723
+ 61 today = Date.today
2724
+ 62 now = Time.now
2725
+ 63: [[now, Redistat::Date.new(now)], [today, Redistat::Date.new(today)]].each do |current, rdate|
2726
+ 64 props = [:year, :month, :day, :hour, :min, :sec, nil]
2727
+ 65 if rdate.usec > 0
2728
+ ..
2729
+ 82 now = Time.now
2730
+ 83
2731
+ 84: date = Redistat::Date.new(now)
2732
+ 85 date.depth.should be_nil
2733
+ 86 date.to_s.should == now.to_rs(:sec).to_s
2734
+ 87 date.to_s.should == now.to_rs.to_s(:sec)
2735
+ 88
2736
+ 89: date = Redistat::Date.new(now, :hour)
2737
+ 90 date.depth.should == :hour
2738
+ 91 date.to_s.should == now.to_rs(:hour).to_s
2739
+
2740
+ /Users/felipeclopes/projects/redisrank/spec/event_spec.rb:
2741
+ 1 require "spec_helper"
2742
+ 2
2743
+ 3: describe Redistat::Event do
2744
+ 4: include Redistat::Database
2745
+ 5
2746
+ 6 before(:each) do
2747
+ .
2748
+ 13 @options = {:depth => :hour}
2749
+ 14 @date = Time.now
2750
+ 15: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta)
2751
+ 16 end
2752
+ 17
2753
+ ..
2754
+ 44
2755
+ 45 it "should increment next_id" do
2756
+ 46: event = Redistat::Event.new("VisitorCount", @label, @date, @stats, @options, @meta)
2757
+ 47 @event.next_id.should == 1
2758
+ 48 event.next_id.should == 1
2759
+ ..
2760
+ 52
2761
+ 53 it "should store event properly" do
2762
+ 54: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta)
2763
+ 55 expect(@event.new?).to be true
2764
+ 56 @event.save
2765
+ 57 expect(@event.new?).to be false
2766
+ 58 keys = db.keys "*"
2767
+ 59: keys.should include("#{@event.scope}#{Redistat::KEY_EVENT}#{@event.id}")
2768
+ 60: keys.should include("#{@event.scope}#{Redistat::KEY_EVENT_IDS}")
2769
+ 61 end
2770
+ 62
2771
+ 63 it "should find event by id" do
2772
+ 64: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options.merge({:store_event => true}), @meta).save
2773
+ 65: fetched = Redistat::Event.find(@scope, @event.id)
2774
+ 66 @event.scope.to_s.should == fetched.scope.to_s
2775
+ 67 @event.label.to_s.should == fetched.label.to_s
2776
+ ..
2777
+ 73 it "should store summarized statistics" do
2778
+ 74 2.times do |i|
2779
+ 75: @event = Redistat::Event.new(@scope, @label, @date, @stats, @options, @meta).save
2780
+ 76: Redistat::Date::DEPTHS.each do |depth|
2781
+ 77 summary = db.zrevrange @event.key.to_s(depth), 0, -1, :with_scores => true
2782
+ 78 expect(summary.count).to be > 0
2783
+
2784
+ /Users/felipeclopes/projects/redisrank/spec/finder/date_set_spec.rb:
2785
+ 1 require "spec_helper"
2786
+ 2
2787
+ 3: describe Redistat::Finder::DateSet do
2788
+ 4
2789
+ 5 before(:all) do
2790
+ 6: @finder = Redistat::Finder::DateSet.new
2791
+ 7 end
2792
+ 8
2793
+ .
2794
+ 10 t_start = Time.utc(2010, 8, 28, 22, 54, 57)
2795
+ 11 t_end = Time.utc(2013, 12, 4, 22, 52, 3)
2796
+ 12: result = Redistat::Finder::DateSet.new(t_start, t_end)
2797
+ 13 result.should == [
2798
+ 14 { :add => ["2010082822", "2010082823"], :rem => [] },
2799
+ ..
2800
+ 26
2801
+ 27 t_end = t_start + 4.hours
2802
+ 28: result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :hour, true)
2803
+ 29 result[0][:add].should == ["2010082818", "2010082819", "2010082820", "2010082821", "2010082822"]
2804
+ 30 result[0][:rem].should == []
2805
+ 31: result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :hour)
2806
+ 32
2807
+ 33 t_end = t_start + 4.days
2808
+ 34: result = Redistat::Finder::DateSet.new.find_date_sets(t_start, t_end, :day, true)
2809
+ 35 result[0][:add].should == ["20100828", "20100829", "20100830", "20100831", "20100901"]
2810
+ 36 result[0][:rem].should == []
2811
+ 37: result.should == Redistat::Finder::DateSet.new(t_start, t_end, nil, :day)
2812
+ 38 end
2813
+ 39
2814
+
2815
+ /Users/felipeclopes/projects/redisrank/spec/finder_spec.rb:
2816
+ 1 require "spec_helper"
2817
+ 2
2818
+ 3: describe Redistat::Finder do
2819
+ 4: include Redistat::Database
2820
+ 5
2821
+ 6 before(:each) do
2822
+ .
2823
+ 9 @label = "about_us"
2824
+ 10 @date = Time.now
2825
+ 11: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
2826
+ 12 @stats = {"user_3" => 3, "user_2" => 2}
2827
+ 13 @stats2 = {"user_3" => 6, "user_2" => 2}
2828
+ ..
2829
+ 19 options = {:scope => "PageViews", :label => "Label", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
2830
+ 20
2831
+ 21: finder = Redistat::Finder.new
2832
+ 22 finder.send(:set_options, options)
2833
+ 23: finder.options[:scope].should be_a(Redistat::Scope)
2834
+ 24 finder.options[:scope].to_s.should == options[:scope]
2835
+ 25: finder.options[:label].should be_a(Redistat::Label)
2836
+ 26 finder.options[:label].to_s.should == options[:label]
2837
+ 27 finder.options.should == options.merge(:scope => finder.options[:scope], :label => finder.options[:label])
2838
+ 28
2839
+ 29: finder = Redistat::Finder.scope("hello")
2840
+ 30 finder.options[:scope].to_s.should == "hello"
2841
+ 31 finder.scope.to_s.should == "hello"
2842
+ 32
2843
+ 33: finder = Redistat::Finder.label("hello")
2844
+ 34 finder.options[:label].to_s.should == "hello"
2845
+ 35 finder.label.to_s.should == "hello"
2846
+ 36
2847
+ 37: finder = Redistat::Finder.dates(@two_hours_ago, @one_hour_ago)
2848
+ 38 finder.options[:from].should == @two_hours_ago
2849
+ 39 finder.options[:till].should == @one_hour_ago
2850
+ 40
2851
+ 41: finder = Redistat::Finder.from(@two_hours_ago)
2852
+ 42 finder.options[:from].should == @two_hours_ago
2853
+ 43 finder.from.should == @two_hours_ago
2854
+ 44
2855
+ 45: finder = Redistat::Finder.till(@one_hour_ago)
2856
+ 46 finder.options[:till].should == @one_hour_ago
2857
+ 47 finder.till.should == @one_hour_ago
2858
+ 48
2859
+ 49: finder = Redistat::Finder.depth(:hour)
2860
+ 50 finder.options[:depth].should == :hour
2861
+ 51 finder.depth.should == :hour
2862
+ 52
2863
+ 53: finder = Redistat::Finder.interval(true)
2864
+ 54 expect(finder.options[:interval]).to be true
2865
+ 55 expect(finder.interval).to be true
2866
+ 56: finder = Redistat::Finder.interval(false)
2867
+ 57 expect(finder.options[:interval]).to be false
2868
+ 58 expect(finder.interval).to be false
2869
+ ..
2870
+ 62 first_stat, last_stat = create_example_stats
2871
+ 63
2872
+ 64: stats = Redistat::Finder.find({:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour})
2873
+ 65 stats.from.should == first_stat
2874
+ 66 stats.till.should == last_stat
2875
+ ..
2876
+ 73 first_stat, last_stat = create_example_stats
2877
+ 74
2878
+ 75: stats = Redistat::Finder.find(:from => first_stat, :till => last_stat, :scope => @scope, :label => @label, :depth => :hour, :interval => :hour)
2879
+ 76 stats.from.should == first_stat
2880
+ 77 stats.till.should == last_stat
2881
+ ..
2882
+ 90
2883
+ 91 it "should return empty hash when attempting to fetch non-existent results" do
2884
+ 92: stats = Redistat::Finder.find({:from => 3.hours.ago, :till => 2.hours.from_now, :scope => @scope, :label => @label, :depth => :hour})
2885
+ 93 stats.rank.should == {}
2886
+ 94 end
2887
+ 95
2888
+ 96 it "should throw error on invalid options" do
2889
+ 97: lambda { Redistat::Finder.find(:from => 3.hours.ago) }.should raise_error(Redistat::InvalidOptions)
2890
+ 98 end
2891
+ 99
2892
+ ...
2893
+ 101 before(:each) do
2894
+ 102 @options = {:scope => "PageViews", :label => "message/public", :from => @two_hours_ago, :till => @one_hour_ago, :depth => :hour, :interval => :hour}
2895
+ 103: @finder = Redistat::Finder.new(@options)
2896
+ 104 end
2897
+ 105
2898
+ 106 it "should return parent finder" do
2899
+ 107 @finder.instance_variable_get("@parent").should be_nil
2900
+ 108: @finder.parent.should be_a(Redistat::Finder)
2901
+ 109 @finder.instance_variable_get("@parent").should_not be_nil
2902
+ 110 @finder.parent.options[:label].to_s.should == 'message'
2903
+ ...
2904
+ 117
2905
+ 118 it "should find children" do
2906
+ 119: Redistat::Key.new("PageViews", "message/public/die").update_index
2907
+ 120: Redistat::Key.new("PageViews", "message/public/live").update_index
2908
+ 121: Redistat::Key.new("PageViews", "message/public/fester").update_index
2909
+ 122: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}message/public") # checking 'message/public'
2910
+ 123: @finder.children.first.should be_a(Redistat::Finder)
2911
+ 124 subs = @finder.children.map { |f| f.options[:label].me }
2912
+ 125 expect(subs.count).to eq(3)
2913
+ ...
2914
+ 135 @first_stat, @last_stat = create_example_stats
2915
+ 136
2916
+ 137: @finder = Redistat::Finder.new
2917
+ 138 @finder.from(@first_stat).till(@last_stat).scope(@scope).label(@label).depth(:hour)
2918
+ 139
2919
+ ...
2920
+ 192
2921
+ 193 def create_example_stats
2922
+ 194: key = Redistat::Key.new(@scope, @label, (first = Time.parse("2010-05-14 13:43")))
2923
+ 195: Redistat::Summary.send(:update_fields, key, @stats, :hour)
2924
+ 196: key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 13:53"))
2925
+ 197: Redistat::Summary.send(:update_fields, key, @stats, :hour)
2926
+ 198: key = Redistat::Key.new(@scope, @label, Time.parse("2010-05-14 14:52"))
2927
+ 199: Redistat::Summary.send(:update_fields, key, @stats, :hour)
2928
+ 200: key = Redistat::Key.new(@scope, @label, (last = Time.parse("2010-05-14 15:02")))
2929
+ 201: Redistat::Summary.send(:update_fields, key, @stats2, :hour)
2930
+ 202 [first - 1.hour, last + 1.hour]
2931
+ 203 end
2932
+
2933
+ /Users/felipeclopes/projects/redisrank/spec/key_spec.rb:
2934
+ 1 require "spec_helper"
2935
+ 2
2936
+ 3: describe Redistat::Key do
2937
+ 4: include Redistat::Database
2938
+ 5
2939
+ 6 before(:each) do
2940
+ .
2941
+ 10 @label_hash = Digest::SHA1.hexdigest(@label)
2942
+ 11 @date = Time.now
2943
+ 12: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour})
2944
+ 13 end
2945
+ 14
2946
+ ..
2947
+ 18 @key.label_hash.should == @label_hash
2948
+ 19 @key.groups.map { |k| k.instance_variable_get("@label") }.should == @key.instance_variable_get("@label").groups
2949
+ 20: @key.date.should be_instance_of(Redistat::Date)
2950
+ 21 @key.date.to_time.to_s.should == @date.to_s
2951
+ 22 end
2952
+ ..
2953
+ 29 props.pop
2954
+ 30 end
2955
+ 31: key = Redistat::Key.new(@scope, nil, @date, {:depth => :hour})
2956
+ 32 key.to_s.should == "#{@scope}:#{key.date.to_s(:hour)}"
2957
+ 33 end
2958
+ 34
2959
+ 35 it "should abide to hashed_label option" do
2960
+ 36: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :hashed_label => true})
2961
+ 37 @key.to_s.should == "#{@scope}/#{@label_hash}:#{@key.date.to_s(:hour)}"
2962
+ 38: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour, :hashed_label => false})
2963
+ 39 @key.to_s.should == "#{@scope}/#{@label}:#{@key.date.to_s(:hour)}"
2964
+ 40 end
2965
+ 41
2966
+ 42 it "should have default depth option" do
2967
+ 43: @key = Redistat::Key.new(@scope, @label, @date)
2968
+ 44 @key.depth.should == :hour
2969
+ 45 end
2970
+ ..
2971
+ 69 before(:each) do
2972
+ 70 @label = "message/public/offensive"
2973
+ 71: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :hour})
2974
+ 72 end
2975
+ 73
2976
+ ..
2977
+ 78 "message" ]
2978
+ 79
2979
+ 80: key = Redistat::Key.new(@scope, label, @date, {:depth => :hour})
2980
+ 81
2981
+ 82 key.groups.map { |k| k.label.to_s }.should == result
2982
+ ..
2983
+ 84
2984
+ 85 it "should know it's parent" do
2985
+ 86: @key.parent.should be_a(Redistat::Key)
2986
+ 87 @key.parent.label.to_s.should == 'message/public'
2987
+ 88: Redistat::Key.new(@scope, 'hello', @date).parent.should be_nil
2988
+ 89 end
2989
+ 90
2990
+ 91 it "should update label index and return children" do
2991
+ 92: db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{@key.label.parent}").should == []
2992
+ 93 @key.children.count.should be(0)
2993
+ 94
2994
+ 95 @key.update_index # indexing 'message/publish/offensive'
2995
+ 96: Redistat::Key.new("PageViews", "message/public/die").update_index # indexing 'message/publish/die'
2996
+ 97: Redistat::Key.new("PageViews", "message/public/live").update_index # indexing 'message/publish/live'
2997
+ 98
2998
+ 99: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{@key.label.parent}") # checking 'message/public'
2999
+ 100 members.count.should be(3)
3000
+ 101 members.should include('offensive')
3001
+ ...
3002
+ 104
3003
+ 105 key = @key.parent
3004
+ 106: key.children.first.should be_a(Redistat::Key)
3005
+ 107 key.children.count.should be(3)
3006
+ 108 key.children.map { |k| k.label.me }.should == members
3007
+ 109
3008
+ 110: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}#{key.label.parent}") # checking 'message'
3009
+ 111 members.count.should be(1)
3010
+ 112 members.should include('public')
3011
+ ...
3012
+ 116 key.children.map { |k| k.label.me }.should == members
3013
+ 117
3014
+ 118: members = db.smembers("#{@scope}#{Redistat::LABEL_INDEX}") # checking ''
3015
+ 119 members.count.should be(1)
3016
+ 120 members.should include('message')
3017
+ 121
3018
+ 122 key.parent.should be_nil
3019
+ 123: key = Redistat::Key.new("PageViews")
3020
+ 124 key.children.count.should be(1)
3021
+ 125 key.children.map { |k| k.label.me }.should include('message')
3022
+
3023
+ /Users/felipeclopes/projects/redisrank/spec/label_spec.rb:
3024
+ 1 require "spec_helper"
3025
+ 2
3026
+ 3: describe Redistat::Label do
3027
+ 4: include Redistat::Database
3028
+ 5
3029
+ 6 before(:each) do
3030
+ 7 db.flushdb
3031
+ 8 @name = "about_us"
3032
+ 9: @label = Redistat::Label.new(@name)
3033
+ 10 end
3034
+ 11
3035
+ ..
3036
+ 16
3037
+ 17 it "should store a label hash lookup key" do
3038
+ 18: label = Redistat::Label.new(@name, {:hashed_label => true}).save
3039
+ 19 label.saved?.should be(true)
3040
+ 20: db.hget(Redistat::KEY_LABELS, label.hash).should == @name
3041
+ 21
3042
+ 22 name = "contact_us"
3043
+ 23: label = Redistat::Label.create(name, {:hashed_label => true})
3044
+ 24 label.saved?.should be(true)
3045
+ 25: db.hget(Redistat::KEY_LABELS, label.hash).should == name
3046
+ 26 end
3047
+ 27
3048
+ 28 it "should join labels" do
3049
+ 29: include Redistat
3050
+ 30: label = Redistat::Label.join('email', 'message', 'public')
3051
+ 31: label.should be_a(Redistat::Label)
3052
+ 32 label.to_s.should == 'email/message/public'
3053
+ 33: label = Redistat::Label.join(Redistat::Label.new('email'), Redistat::Label.new('message'), Redistat::Label.new('public'))
3054
+ 34: label.should be_a(Redistat::Label)
3055
+ 35 label.to_s.should == 'email/message/public'
3056
+ 36: label = Redistat::Label.join('email', '', 'message', nil, 'public')
3057
+ 37: label.should be_a(Redistat::Label)
3058
+ 38 label.to_s.should == 'email/message/public'
3059
+ 39 end
3060
+ 40
3061
+ 41 it "should allow you to use a different group separator" do
3062
+ 42: include Redistat
3063
+ 43: Redistat.group_separator = '|'
3064
+ 44: label = Redistat::Label.join('email', 'message', 'public')
3065
+ 45: label.should be_a(Redistat::Label)
3066
+ 46 label.to_s.should == 'email|message|public'
3067
+ 47: label = Redistat::Label.join(Redistat::Label.new('email'), Redistat::Label.new('message'), Redistat::Label.new('public'))
3068
+ 48: label.should be_a(Redistat::Label)
3069
+ 49 label.to_s.should == 'email|message|public'
3070
+ 50: label = Redistat::Label.join('email', '', 'message', nil, 'public')
3071
+ 51: label.should be_a(Redistat::Label)
3072
+ 52 label.to_s.should == 'email|message|public'
3073
+ 53: Redistat.group_separator = Redistat::GROUP_SEPARATOR
3074
+ 54 end
3075
+ 55
3076
+ ..
3077
+ 57 before(:each) do
3078
+ 58 @name = "message/public/offensive"
3079
+ 59: @label = Redistat::Label.new(@name)
3080
+ 60 end
3081
+ 61
3082
+ 62 it "should know it's parent label group" do
3083
+ 63 @label.parent.to_s.should == 'message/public'
3084
+ 64: Redistat::Label.new('hello').parent.should be_nil
3085
+ 65 end
3086
+ 66
3087
+ ..
3088
+ 72
3089
+ 73 @name = "/message/public/"
3090
+ 74: @label = Redistat::Label.new(@name)
3091
+ 75 @label.name.should == @name
3092
+ 76 @label.groups.map { |l| l.to_s }.should == [ "message/public",
3093
+ ..
3094
+ 78
3095
+ 79 @name = "message"
3096
+ 80: @label = Redistat::Label.new(@name)
3097
+ 81 @label.name.should == @name
3098
+ 82 @label.groups.map { |l| l.to_s }.should == [ "message" ]
3099
+
3100
+ /Users/felipeclopes/projects/redisrank/spec/model_helper.rb:
3101
+ 2
3102
+ 3 class ModelHelper1
3103
+ 4: include Redistat::Model
3104
+ 5
3105
+ 6
3106
+ .
3107
+ 8
3108
+ 9 class ModelHelper2
3109
+ 10: include Redistat::Model
3110
+ 11
3111
+ 12 depth :day
3112
+ ..
3113
+ 17
3114
+ 18 class ModelHelper3
3115
+ 19: include Redistat::Model
3116
+ 20
3117
+ 21 connect_to :port => 8379, :db => 14
3118
+ ..
3119
+ 24
3120
+ 25 class ModelHelper4
3121
+ 26: include Redistat::Model
3122
+ 27
3123
+ 28 scope "FancyHelper"
3124
+
3125
+ /Users/felipeclopes/projects/redisrank/spec/model_spec.rb:
3126
+ 2 require "model_helper"
3127
+ 3
3128
+ 4: describe Redistat::Model do
3129
+ 5: include Redistat::Database
3130
+ 6
3131
+ 7 before(:each) do
3132
+ .
3133
+ 22 one_hour_ago = 1.hour.ago
3134
+ 23 finder = ModelHelper1.find('label', two_hours_ago, one_hour_ago)
3135
+ 24: finder.should be_a(Redistat::Finder)
3136
+ 25 finder.options[:scope].to_s.should == 'ModelHelper1'
3137
+ 26 finder.options[:label].to_s.should == 'label'
3138
+ ..
3139
+ 30
3140
+ 31 it "should #find_event" do
3141
+ 32: Redistat::Event.should_receive(:find).with('ModelHelper1', 1)
3142
+ 33 ModelHelper1.find_event(1)
3143
+ 34 end
3144
+ ..
3145
+ 151 describe "Write Buffer" do
3146
+ 152 before(:each) do
3147
+ 153: Redistat.buffer_size = 20
3148
+ 154 end
3149
+ 155
3150
+ 156 after(:each) do
3151
+ 157: Redistat.buffer_size = 0
3152
+ 158 end
3153
+ 159
3154
+ ...
3155
+ 181 end
3156
+ 182 ModelHelper1.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1)).rank.should == {}
3157
+ 183: Redistat.buffer.flush(true)
3158
+ 184
3159
+ 185 stats = ModelHelper1.fetch("sheep.black", @time.hours_ago(5), @time.hours_since(1))
3160
+
3161
+ /Users/felipeclopes/projects/redisrank/spec/options_spec.rb:
3162
+ 1 require "spec_helper"
3163
+ 2
3164
+ 3: describe Redistat::Options do
3165
+ 4
3166
+ 5 before(:each) do
3167
+ .
3168
+ 24
3169
+ 25 class OptionsHelper
3170
+ 26: include Redistat::Options
3171
+ 27
3172
+ 28 option_accessor :hello
3173
+
3174
+ /Users/felipeclopes/projects/redisrank/spec/result_spec.rb:
3175
+ 1 require "spec_helper"
3176
+ 2
3177
+ 3: describe Redistat::Result do
3178
+ 4
3179
+ 5 it "should should initialize properly" do
3180
+ 6 options = {:from => "from", :till => "till"}
3181
+ 7: result = Redistat::Result.new(options)
3182
+ 8 result.from.should == "from"
3183
+ 9 result.till.should == "till"
3184
+ ..
3185
+ 11
3186
+ 12 it "should have merge_to_max method" do
3187
+ 13: result = Redistat::Result.new
3188
+ 14 result[:world].should be_nil
3189
+ 15 result.merge_to_max(:world, 3)
3190
+
3191
+ /Users/felipeclopes/projects/redisrank/spec/scope_spec.rb:
3192
+ 1 require "spec_helper"
3193
+ 2
3194
+ 3: describe Redistat::Scope do
3195
+ 4: include Redistat::Database
3196
+ 5
3197
+ 6 before(:all) do
3198
+ .
3199
+ 10 before(:each) do
3200
+ 11 @name = "PageViews"
3201
+ 12: @scope = Redistat::Scope.new(@name)
3202
+ 13 end
3203
+ 14
3204
+ ..
3205
+ 18
3206
+ 19 it "should increment next_id" do
3207
+ 20: scope = Redistat::Scope.new("Visitors")
3208
+ 21 @scope.next_id.should == 1
3209
+ 22 scope.next_id.should == 1
3210
+
3211
+ /Users/felipeclopes/projects/redisrank/spec/spec_helper.rb:
3212
+ 14 require 'rspec/autorun'
3213
+ 15
3214
+ 16: # use the test Redistat instance
3215
+ 17: Redistat.connect(:port => 8379, :db => 15, :thread_safe => true)
3216
+ 18: Redistat.redis.flushdb
3217
+ 19
3218
+
3219
+ /Users/felipeclopes/projects/redisrank/spec/summary_spec.rb:
3220
+ 1 require "spec_helper"
3221
+ 2
3222
+ 3: describe Redistat::Summary do
3223
+ 4: include Redistat::Database
3224
+ 5
3225
+ 6 before(:each) do
3226
+ .
3227
+ 9 @label = "about_us"
3228
+ 10 @date = Time.now
3229
+ 11: @key = Redistat::Key.new(@scope, @label, @date, {:depth => :day})
3230
+ 12 @stats = {"views" => 3, "visitors" => 2}
3231
+ 13 @expire = {:hour => 24*3600}
3232
+ ..
3233
+ 15
3234
+ 16 it "should update a single summary properly" do
3235
+ 17: Redistat::Summary.send(:update_fields, @key, @stats, :hour)
3236
+ 18 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
3237
+ 19 expect(summary.count).to be 2
3238
+ ..
3239
+ 25 expect(visitors.last).to be 2.0
3240
+ 26
3241
+ 27: Redistat::Summary.send(:update_fields, @key, @stats, :hour)
3242
+ 28 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
3243
+ 29 expect(summary.count).to be 2
3244
+ ..
3245
+ 37
3246
+ 38 it "should set key expiry properly" do
3247
+ 39: Redistat::Summary.update_all(@key, @stats, :hour,{:expire => @expire})
3248
+ 40 ((24*3600)-1..(24*3600)+1).should include(db.ttl(@key.to_s(:hour)))
3249
+ 41 [:day, :month, :year].each do |depth|
3250
+ ..
3251
+ 44
3252
+ 45 db.flushdb
3253
+ 46: Redistat::Summary.update_all(@key, @stats, :hour, {:expire => {}})
3254
+ 47 [:hour, :day, :month, :year].each do |depth|
3255
+ 48 db.ttl(@key.to_s(depth)).should == -1
3256
+ ..
3257
+ 51
3258
+ 52 it "should update all summaries properly" do
3259
+ 53: Redistat::Summary.update_all(@key, @stats, :sec)
3260
+ 54 [:year, :month, :day, :hour, :min, :sec, :usec].each do |depth|
3261
+ 55 summary = db.zrevrange(@key.to_s(depth), 0, -1, :with_scores => true)
3262
+ ..
3263
+ 69
3264
+ 70 it "should update summaries even if no label is set" do
3265
+ 71: key = Redistat::Key.new(@scope, nil, @date, {:depth => :day})
3266
+ 72: Redistat::Summary.send(:update_fields, key, @stats, :hour)
3267
+ 73 summary = db.zrevrange(key.to_s(:hour), 0, -1, :with_scores => true)
3268
+ 74 views = summary.first
3269
+ ..
3270
+ 84 "death/bomb" => 4, "death/unicorn" => 3,
3271
+ 85 :"od/sugar" => 7, :"od/meth" => 8 }
3272
+ 86: res = Redistat::Summary.send(:inject_group_summaries, hash)
3273
+ 87 res.should == { "count" => 10, "count/hello" => 3, "count/world" => 7,
3274
+ 88 "death" => 7, "death/bomb" => 4, "death/unicorn" => 3,
3275
+ ..
3276
+ 92 it "should properly store key group summaries" do
3277
+ 93 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
3278
+ 94: Redistat::Summary.update_all(@key, stats, :hour)
3279
+ 95 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
3280
+ 96 summary.count.should eq(4)
3281
+ ..
3282
+ 109 it "should not store key group summaries when option is disabled" do
3283
+ 110 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
3284
+ 111: Redistat::Summary.update_all(@key, stats, :hour, {:enable_grouping => false})
3285
+ 112 summary = db.zrevrange(@key.to_s(:hour), 0, -1, :with_scores => true)
3286
+ 113 summary.count.should eq(3)
3287
+ ...
3288
+ 125 stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
3289
+ 126 label = "views/about_us"
3290
+ 127: key = Redistat::Key.new(@scope, label, @date)
3291
+ 128: Redistat::Summary.update_all(key, stats, :hour)
3292
+ 129
3293
+ 130 key.groups[0].label.to_s.should == "views/about_us"
3294
+ ...
3295
+ 134
3296
+ 135 label = "views/contact"
3297
+ 136: key = Redistat::Key.new(@scope, label, @date)
3298
+ 137: Redistat::Summary.update_all(key, stats, :hour)
3299
+ 138
3300
+ 139 key.groups[0].label.to_s.should == "views/contact"
3301
+
3302
+ /Users/felipeclopes/projects/redisrank/spec/synchronize_spec.rb:
3303
+ 1 require "spec_helper"
3304
+ 2
3305
+ 3: module Redistat
3306
+ 4 describe Synchronize do
3307
+ 5
3308
+ .
3309
+ 62
3310
+ 63 describe '.monitor' do
3311
+ 64: it 'defers to Redistat::Synchronize' do
3312
+ 65 klass.should_receive(:monitor).once
3313
+ 66 subject.monitor
3314
+ ..
3315
+ 69
3316
+ 70 describe '.thread_safe' do
3317
+ 71: it ' defers to Redistat::Synchronize' do
3318
+ 72 klass.should_receive(:thread_safe).once
3319
+ 73 subject.thread_safe
3320
+ ..
3321
+ 76
3322
+ 77 describe '.thread_safe=' do
3323
+ 78: it 'defers to Redistat::Synchronize' do
3324
+ 79 klass.should_receive(:thread_safe=).once.with(true)
3325
+ 80 subject.thread_safe = true
3326
+ ..
3327
+ 119
3328
+ 120 end # Synchronize
3329
+ 121: end # Redistat
3330
+ 122
3331
+ 123 class SynchronizeSpecHelper
3332
+ 124: include Redistat::Synchronize
3333
+ 125 end
3334
+ 126
3335
+
3336
+ /Users/felipeclopes/projects/redisrank/spec/thread_safety_spec.rb:
3337
+ 2
3338
+ 3 describe "Thread-Safety" do
3339
+ 4: include Redistat::Database
3340
+ 5
3341
+ 6 before(:each) do
3342
+ .
3343
+ 23 it "should store event in multiple threads" do
3344
+ 24 class ThreadSafetySpec
3345
+ 25: include Redistat::Model
3346
+ 26 end
3347
+ 27 threads = []
3348
+
3349
+ 304 matches across 46 files