redisrank 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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