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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +297 -0
- data/Rakefile +69 -0
- data/lib/redisrank.rb +106 -0
- data/lib/redisrank/buffer.rb +110 -0
- data/lib/redisrank/collection.rb +20 -0
- data/lib/redisrank/connection.rb +89 -0
- data/lib/redisrank/core_ext.rb +5 -0
- data/lib/redisrank/core_ext/bignum.rb +8 -0
- data/lib/redisrank/core_ext/date.rb +8 -0
- data/lib/redisrank/core_ext/fixnum.rb +8 -0
- data/lib/redisrank/core_ext/hash.rb +20 -0
- data/lib/redisrank/core_ext/time.rb +3 -0
- data/lib/redisrank/date.rb +88 -0
- data/lib/redisrank/event.rb +98 -0
- data/lib/redisrank/finder.rb +245 -0
- data/lib/redisrank/finder/date_set.rb +99 -0
- data/lib/redisrank/key.rb +84 -0
- data/lib/redisrank/label.rb +69 -0
- data/lib/redisrank/mixins/database.rb +11 -0
- data/lib/redisrank/mixins/date_helper.rb +8 -0
- data/lib/redisrank/mixins/options.rb +41 -0
- data/lib/redisrank/mixins/synchronize.rb +52 -0
- data/lib/redisrank/model.rb +77 -0
- data/lib/redisrank/result.rb +18 -0
- data/lib/redisrank/scope.rb +18 -0
- data/lib/redisrank/summary.rb +90 -0
- data/lib/redisrank/version.rb +3 -0
- data/redisrank.gemspec +31 -0
- data/spec/Find Results +3349 -0
- data/spec/buffer_spec.rb +104 -0
- data/spec/collection_spec.rb +20 -0
- data/spec/connection_spec.rb +67 -0
- data/spec/core_ext/hash_spec.rb +26 -0
- data/spec/database_spec.rb +10 -0
- data/spec/date_spec.rb +95 -0
- data/spec/event_spec.rb +86 -0
- data/spec/finder/date_set_spec.rb +527 -0
- data/spec/finder_spec.rb +205 -0
- data/spec/key_spec.rb +129 -0
- data/spec/label_spec.rb +86 -0
- data/spec/model_helper.rb +31 -0
- data/spec/model_spec.rb +191 -0
- data/spec/options_spec.rb +36 -0
- data/spec/redis-test.conf +9 -0
- data/spec/result_spec.rb +23 -0
- data/spec/scope_spec.rb +27 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/summary_spec.rb +177 -0
- data/spec/synchronize_spec.rb +125 -0
- data/spec/thread_safety_spec.rb +39 -0
- metadata +235 -0
@@ -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,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
|
data/redisrank.gemspec
ADDED
@@ -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
|
data/spec/Find Results
ADDED
@@ -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 'redisrank/mixins/options'</code>
|
302
|
+
435 </li>
|
303
|
+
436
|
304
|
+
...
|
305
|
+
438 <span class="hits">1</span>
|
306
|
+
439
|
307
|
+
440: <code class="ruby">require 'redisrank/mixins/synchronize'</code>
|
308
|
+
441 </li>
|
309
|
+
442
|
310
|
+
...
|
311
|
+
444 <span class="hits">1</span>
|
312
|
+
445
|
313
|
+
446: <code class="ruby">require 'redisrank/mixins/database'</code>
|
314
|
+
447 </li>
|
315
|
+
448
|
316
|
+
...
|
317
|
+
450 <span class="hits">1</span>
|
318
|
+
451
|
319
|
+
452: <code class="ruby">require 'redisrank/mixins/date_helper'</code>
|
320
|
+
453 </li>
|
321
|
+
454
|
322
|
+
...
|
323
|
+
462 <span class="hits">1</span>
|
324
|
+
463
|
325
|
+
464: <code class="ruby">require 'redisrank/connection'</code>
|
326
|
+
465 </li>
|
327
|
+
466
|
328
|
+
...
|
329
|
+
468 <span class="hits">1</span>
|
330
|
+
469
|
331
|
+
470: <code class="ruby">require 'redisrank/buffer'</code>
|
332
|
+
471 </li>
|
333
|
+
472
|
334
|
+
...
|
335
|
+
474 <span class="hits">1</span>
|
336
|
+
475
|
337
|
+
476: <code class="ruby">require 'redisrank/collection'</code>
|
338
|
+
477 </li>
|
339
|
+
478
|
340
|
+
...
|
341
|
+
480 <span class="hits">1</span>
|
342
|
+
481
|
343
|
+
482: <code class="ruby">require 'redisrank/date'</code>
|
344
|
+
483 </li>
|
345
|
+
484
|
346
|
+
...
|
347
|
+
486 <span class="hits">1</span>
|
348
|
+
487
|
349
|
+
488: <code class="ruby">require 'redisrank/event'</code>
|
350
|
+
489 </li>
|
351
|
+
490
|
352
|
+
...
|
353
|
+
492 <span class="hits">1</span>
|
354
|
+
493
|
355
|
+
494: <code class="ruby">require 'redisrank/finder'</code>
|
356
|
+
495 </li>
|
357
|
+
496
|
358
|
+
...
|
359
|
+
498 <span class="hits">1</span>
|
360
|
+
499
|
361
|
+
500: <code class="ruby">require 'redisrank/key'</code>
|
362
|
+
501 </li>
|
363
|
+
502
|
364
|
+
...
|
365
|
+
504 <span class="hits">1</span>
|
366
|
+
505
|
367
|
+
506: <code class="ruby">require 'redisrank/label'</code>
|
368
|
+
507 </li>
|
369
|
+
508
|
370
|
+
...
|
371
|
+
510 <span class="hits">1</span>
|
372
|
+
511
|
373
|
+
512: <code class="ruby">require 'redisrank/model'</code>
|
374
|
+
513 </li>
|
375
|
+
514
|
376
|
+
...
|
377
|
+
516 <span class="hits">1</span>
|
378
|
+
517
|
379
|
+
518: <code class="ruby">require 'redisrank/result'</code>
|
380
|
+
519 </li>
|
381
|
+
520
|
382
|
+
...
|
383
|
+
522 <span class="hits">1</span>
|
384
|
+
523
|
385
|
+
524: <code class="ruby">require 'redisrank/scope'</code>
|
386
|
+
525 </li>
|
387
|
+
526
|
388
|
+
...
|
389
|
+
528 <span class="hits">1</span>
|
390
|
+
529
|
391
|
+
530: <code class="ruby">require 'redisrank/summary'</code>
|
392
|
+
531 </li>
|
393
|
+
532
|
394
|
+
...
|
395
|
+
534 <span class="hits">1</span>
|
396
|
+
535
|
397
|
+
536: <code class="ruby">require 'redisrank/version'</code>
|
398
|
+
537 </li>
|
399
|
+
538
|
400
|
+
...
|
401
|
+
546 <span class="hits">1</span>
|
402
|
+
547
|
403
|
+
548: <code class="ruby">require 'redisrank/core_ext'</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 = "Redistat.labels:" # used for reverse label hash lookup</code>
|
416
|
+
591 </li>
|
417
|
+
592
|
418
|
+
...
|
419
|
+
858
|
420
|
+
859
|
421
|
+
860: <code class="ruby"> puts "WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead."</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 'redisrank/core_ext/hash'</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 'redisrank/core_ext/bignum'</code>
|
482
|
+
2349 </li>
|
483
|
+
2350
|
484
|
+
....
|
485
|
+
2352 <span class="hits">1</span>
|
486
|
+
2353
|
487
|
+
2354: <code class="ruby">require 'redisrank/core_ext/date'</code>
|
488
|
+
2355 </li>
|
489
|
+
2356
|
490
|
+
....
|
491
|
+
2358 <span class="hits">1</span>
|
492
|
+
2359
|
493
|
+
2360: <code class="ruby">require 'redisrank/core_ext/fixnum'</code>
|
494
|
+
2361 </li>
|
495
|
+
2362
|
496
|
+
....
|
497
|
+
2364 <span class="hits">1</span>
|
498
|
+
2365
|
499
|
+
2366: <code class="ruby">require 'redisrank/core_ext/hash'</code>
|
500
|
+
2367 </li>
|
501
|
+
2368
|
502
|
+
....
|
503
|
+
2370 <span class="hits">1</span>
|
504
|
+
2371
|
505
|
+
2372: <code class="ruby">require 'redisrank/core_ext/time'</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 'redisrank/finder/date_set'</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?) ? "" : "#{parent}#{Redistat.group_separator}") + 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 [](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 = "Redistat.labels:" # used for reverse label hash lookup</code>
|
2025
|
+
591 </li>
|
2026
|
+
592
|
2027
|
+
...
|
2028
|
+
858
|
2029
|
+
859
|
2030
|
+
860: <code class="ruby"> puts "WARNING: Redistat.flush is deprecated. Use Redistat.redis.flushdb instead."</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?) ? "" : "#{parent}#{Redistat.group_separator}") + 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 [](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
|