redis_analytics 0.1.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/CHANGELOG.md +12 -0
  2. data/CONTRIBUTING.md +33 -0
  3. data/Guardfile +10 -0
  4. data/README.md +105 -23
  5. data/Rakefile +3 -11
  6. data/TODO.md +12 -0
  7. data/bin/redis_analytics_dashboard +1 -1
  8. data/config.ru +13 -0
  9. data/lib/redis_analytics.rb +5 -1
  10. data/lib/redis_analytics/analytics.rb +17 -203
  11. data/lib/redis_analytics/api.rb +60 -0
  12. data/lib/redis_analytics/configuration.rb +47 -16
  13. data/lib/redis_analytics/dashboard.rb +28 -89
  14. data/lib/redis_analytics/dashboard/public/{favicon.ico → img/favicon.ico} +0 -0
  15. data/lib/redis_analytics/dashboard/public/javascripts/{bootstrap.min.js → vendor/bootstrap/bootstrap.min.js} +0 -0
  16. data/lib/redis_analytics/dashboard/public/javascripts/{jquery-1.9.1.min.js → vendor/jquery-1.9.1.min.js} +0 -0
  17. data/lib/redis_analytics/dashboard/public/javascripts/{jquery-jvectormap-1.2.2.min.js → vendor/jquery-jvectormap-1.2.2.min.js} +0 -0
  18. data/lib/redis_analytics/dashboard/public/javascripts/{jquery-jvectormap-world-mill-en.js → vendor/jquery-jvectormap-world-mill-en.js} +0 -0
  19. data/lib/redis_analytics/dashboard/public/javascripts/{morris.min.js → vendor/morris.min.js} +0 -0
  20. data/lib/redis_analytics/dashboard/public/javascripts/{raphael-min.js → vendor/raphael-min.js} +0 -0
  21. data/lib/redis_analytics/dashboard/views/activity.erb +7 -0
  22. data/lib/redis_analytics/dashboard/views/dialogs/unique_visits.erb +41 -0
  23. data/lib/redis_analytics/dashboard/views/dialogs/visits.erb +40 -0
  24. data/lib/redis_analytics/dashboard/views/footer.erb +1 -3
  25. data/lib/redis_analytics/dashboard/views/header.erb +17 -42
  26. data/lib/redis_analytics/dashboard/views/layout.erb +5 -22
  27. data/lib/redis_analytics/dashboard/views/visits.erb +38 -143
  28. data/lib/redis_analytics/dashboard/views/visits_js.erb +110 -247
  29. data/lib/redis_analytics/dashboard/views/widgets/bounce_rate.erb +3 -0
  30. data/lib/redis_analytics/dashboard/views/widgets/browsers_donut.erb +8 -0
  31. data/lib/redis_analytics/dashboard/views/widgets/first_visits.erb +3 -0
  32. data/lib/redis_analytics/dashboard/views/widgets/page_depth.erb +3 -0
  33. data/lib/redis_analytics/dashboard/views/widgets/referers_donut.erb +8 -0
  34. data/lib/redis_analytics/dashboard/views/widgets/total_page_views.erb +3 -0
  35. data/lib/redis_analytics/dashboard/views/widgets/total_visits.erb +3 -0
  36. data/lib/redis_analytics/dashboard/views/widgets/unique_visits_line.erb +26 -0
  37. data/lib/redis_analytics/dashboard/views/widgets/visit_duration.erb +3 -0
  38. data/lib/redis_analytics/dashboard/views/widgets/visit_spark.erb +23 -0
  39. data/lib/redis_analytics/dashboard/views/widgets/visitor_recency_slices.erb +39 -0
  40. data/lib/redis_analytics/dashboard/views/widgets/visits_area.erb +30 -0
  41. data/lib/redis_analytics/dashboard/views/widgets/visits_donut.erb +8 -0
  42. data/lib/redis_analytics/dashboard/views/widgets/world_map.erb +50 -0
  43. data/lib/redis_analytics/filter.rb +33 -0
  44. data/lib/redis_analytics/helpers.rb +36 -30
  45. data/lib/redis_analytics/metrics.rb +96 -0
  46. data/lib/redis_analytics/time_ext.rb +72 -2
  47. data/lib/redis_analytics/tracker.rb +13 -5
  48. data/lib/redis_analytics/version.rb +1 -1
  49. data/lib/redis_analytics/visit.rb +122 -0
  50. data/redis_analytics.gemspec +19 -14
  51. data/spec/lib/redis_analytics/analytics_spec.rb +59 -0
  52. data/spec/lib/redis_analytics/configuration_spec.rb +158 -0
  53. data/spec/lib/redis_analytics/dashboard_spec.rb +32 -0
  54. data/spec/lib/redis_analytics/filter_spec.rb +34 -0
  55. data/spec/lib/redis_analytics/tracker_spec.rb +20 -0
  56. data/spec/spec_helper.rb +13 -6
  57. data/spec/support/fakeredis.rb +1 -0
  58. data/wsd.png +0 -0
  59. metadata +268 -126
  60. data/lib/redis_analytics/config.ru +0 -10
  61. data/spec/redis_analytics_spec.rb +0 -57
@@ -1,3 +1,4 @@
1
+ require 'date'
1
2
  module TimeExtensions
2
3
  %w[ round floor ceil ].each do |_method|
3
4
  define_method _method do |*args|
@@ -6,14 +7,83 @@ module TimeExtensions
6
7
  end
7
8
  end
8
9
 
10
+ def end_of_year
11
+ Time.local(self.year, 12, 31, 23, 59, 59)
12
+ end
13
+
14
+ def beginning_of_year
15
+ Time.local(self.year, 1, 1, 0, 0, 0)
16
+ end
17
+
18
+ def end_of_month
19
+ Time.local(self.year, self.mon + 1, 1, 23, 59, 59) - 1.day
20
+ end
21
+
22
+ def beginning_of_month
23
+ Date.civil(self.year, self.mon, -1).to_time
24
+ end
25
+
26
+ def beginning_of_day
27
+ Time.local(self.year, self.mon, self.day, 0, 0, 0)
28
+ end
29
+
30
+ def end_of_day
31
+ Time.local(self.year, self.mon, self.day, 23, 59, 59)
32
+ end
33
+
34
+ def beginning_of_day
35
+ Time.local(self.year, self.mon, self.day, 0, 0, 0)
36
+ end
37
+
38
+ def end_of_hour
39
+ Time.local(self.year, self.mon, self.day, self.hour, 59, 59)
40
+ end
41
+
42
+ def beginning_of_hour
43
+ Time.local(self.year, self.mon, self.day, self.hour, 0, 0)
44
+ end
45
+
9
46
  def end_of_minute
10
- change(:sec => 59, :usec => 999999.999)
47
+ Time.local(self.year, self.mon, self.day, self.hour, self.min, 59)
11
48
  end
12
49
 
13
50
  def beginning_of_minute
14
- change(:sec => 0, :usec => 0)
51
+ Time.local(self.year, self.mon, self.day, self.hour, self.min, 0)
15
52
  end
16
53
  end
17
54
 
18
55
  Time.send :include, TimeExtensions
19
56
 
57
+ module FixnumExtensions
58
+
59
+ def minute
60
+ self * 60
61
+ end
62
+
63
+ def hour
64
+ minute * 60
65
+ end
66
+
67
+ def day
68
+ hour * 24
69
+ end
70
+
71
+ def week
72
+ day * 7
73
+ end
74
+
75
+ def month
76
+ day * 30
77
+ end
78
+
79
+ def year
80
+ day * 365
81
+ end
82
+
83
+ def ago(time = Time.now)
84
+ time - self
85
+ end
86
+ end
87
+
88
+ Fixnum.send :include, FixnumExtensions
89
+
@@ -4,23 +4,31 @@ module Rack
4
4
 
5
5
  def initialize(app)
6
6
  @app = Rack::Builder.new do
7
+
8
+ if defined?(Dashboard) and RedisAnalytics.dashboard_endpoint
9
+ puts("WARNING: RedisAnalytics.dashboard_endpoint is set as \"/\"") if RedisAnalytics.dashboard_endpoint == '/'
10
+ map RedisAnalytics.dashboard_endpoint do
11
+ run Dashboard.new
12
+ end
13
+ end
14
+
7
15
  map '/' do
8
16
  run Analytics.new(app)
9
17
  end
10
18
 
11
- if defined? Dashboard and RedisAnalytics.dashboard_endpoint
12
- map RedisAnalytics.dashboard_endpoint do
13
- run Dashboard.new
19
+ if defined?(Api) and RedisAnalytics.api_endpoint
20
+ map RedisAnalytics.api_endpoint do
21
+ run Api.new
14
22
  end
15
23
  end
24
+
16
25
  end
17
26
  end
18
27
 
19
28
  def call(env)
20
29
  @app.call(env)
21
30
  end
22
-
31
+
23
32
  end
24
33
  end
25
34
  end
26
-
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module RedisAnalytics
3
- VERSION = '0.1.0'
3
+ VERSION = '0.6.0'
4
4
  end
5
5
  end
@@ -0,0 +1,122 @@
1
+ module Rack
2
+ module RedisAnalytics
3
+ class Visit
4
+ include Metrics
5
+
6
+ # This class represents one unique visit
7
+ # User may have never visited the site
8
+ # User may have visited before but his visit is expired
9
+ # Everything counted here is unique for a visit
10
+
11
+ # helpers
12
+ def for_each_time_range(t)
13
+ RedisAnalytics.redis_key_timestamps.map{|x, y| t.strftime(x)}.each do |ts|
14
+ yield(ts)
15
+ end
16
+ end
17
+
18
+ def first_visit_info
19
+ cookie = @rack_request.cookies[RedisAnalytics.first_visit_cookie_name]
20
+ return cookie ? cookie.split('.') : []
21
+ end
22
+
23
+ def current_visit_info
24
+ cookie = @rack_request.cookies[RedisAnalytics.current_visit_cookie_name]
25
+ return cookie ? cookie.split('.') : []
26
+ end
27
+
28
+ # method used in analytics.rb to initialize visit
29
+ def initialize(request, response)
30
+ @t = Time.now
31
+ @redis_key_prefix = "#{RedisAnalytics.redis_namespace}:"
32
+ @rack_request = request
33
+ @rack_response = response
34
+ @first_visit_seq = first_visit_info[0] || current_visit_info[0]
35
+ @current_visit_seq = current_visit_info[1]
36
+
37
+ @first_visit_time = first_visit_info[1]
38
+ @last_visit_time = first_visit_info[2]
39
+
40
+ @page_view_seq_no = current_visit_info[2] || 0
41
+ @last_visit_start_time = current_visit_info[3]
42
+ @last_visit_end_time = current_visit_info[4]
43
+ end
44
+
45
+ # called from analytics.rb
46
+ def record
47
+ if @current_visit_seq
48
+ track("visit_time", @t.to_i - @last_visit_end_time.to_i)
49
+ else
50
+ @current_visit_seq ||= counter("visits")
51
+ track("visits", 1) # track core 'visit' metric
52
+ if @first_visit_seq
53
+ track("repeat_visits", 1)
54
+ else
55
+ @first_visit_seq ||= counter("unique_visits")
56
+ track("first_visits", 1)
57
+ track("unique_visits", @first_visit_seq)
58
+ end
59
+ exec_custom_methods('visit') # custom methods that are measured on a per-visit basis
60
+ end
61
+ exec_custom_methods('hit') # custom methods that are measured on a per-page-view (per-hit) basis
62
+ track("page_views", 1) # track core 'page_view' metric
63
+ track("second_page_views", 1) if @page_view_seq_no.to_i == 1 # @last_visit_start_time and (@last_visit_start_time.to_i == @last_visit_end_time.to_i)
64
+ @rack_response
65
+ end
66
+
67
+ def exec_custom_methods(type)
68
+ Metrics.public_instance_methods.each do |meth|
69
+ if m = meth.to_s.match(/^([a-z_]*)_(count|ratio)_per_#{type}$/)
70
+ begin
71
+ return_value = self.send(meth)
72
+ track(m.to_a[1], return_value) if return_value
73
+ rescue => e
74
+ warn "#{meth} resulted in an exception #{e}"
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ # helpers
81
+ def counter(metric_name)
82
+ n = RedisAnalytics.redis_connection.incr("#{@redis_key_prefix}#{metric_name}")
83
+ # to debug, uncomment this line
84
+ # puts "COUNT #{metric_name} -> #{n}"
85
+ return n
86
+ end
87
+
88
+ def updated_current_visit_info
89
+ value = [@first_visit_seq.to_i, @current_visit_seq.to_i, @page_view_seq_no.to_i + 1, (@last_visit_start_time || @t).to_i, @t.to_i]
90
+ # to debug, uncomment this line
91
+ # puts "UPDATING VCN COOKIE -> #{value}"
92
+ expires = @t + (RedisAnalytics.visit_timeout.to_i * 60)
93
+ {:value => value.join('.'), :expires => expires}
94
+ end
95
+
96
+ def updated_first_visit_info
97
+ value = [@first_visit_seq.to_i, (@first_visit_time || @t).to_i, @t.to_i]
98
+ # to debug, uncomment this line
99
+ # puts "UPDATING RUCN COOKIE -> #{value}"
100
+ expires = @t + (60 * 60 * 24 * 5) # 5 hours
101
+ {:value => value.join('.'), :expires => expires}
102
+ end
103
+
104
+ def track(metric_name, metric_value)
105
+ n = 0
106
+ RedisAnalytics.redis_connection.hmset("#{@redis_key_prefix}#METRICS", metric_name, metric_value.class)
107
+ for_each_time_range(@t) do |ts|
108
+ key = "#{@redis_key_prefix}#{metric_name}:#{ts}"
109
+ if metric_value.is_a?(Fixnum)
110
+ n = RedisAnalytics.redis_connection.incrby(key, metric_value)
111
+ else
112
+ n = RedisAnalytics.redis_connection.zincrby(key, 1, metric_value)
113
+ end
114
+ end
115
+ # to debug, uncomment this line
116
+ # puts "TRACK #{metric_name} -> #{n}"
117
+ return n
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -1,3 +1,4 @@
1
+
1
2
  # -*- encoding: utf-8 -*-
2
3
  $:.push File.expand_path("../lib", __FILE__)
3
4
  require 'redis_analytics/version'
@@ -5,11 +6,11 @@ require 'redis_analytics/version'
5
6
  Gem::Specification.new do |spec|
6
7
  spec.name = "redis_analytics"
7
8
  spec.version = Rack::RedisAnalytics::VERSION
8
- spec.date = '2013-02-15'
9
+ spec.date = Time.now.strftime('%Y-%m-%d')
9
10
  spec.authors = ["Schubert Cardozo"]
10
11
  spec.email = ["cardozoschubert@gmail.com"]
11
12
  spec.homepage = "https://github.com/saturnine/redis_analytics"
12
- spec.summary = %q{A gem that provides a Redis based web analytics solution for your rack-compliant apps}
13
+ spec.summary = %q{Fast and efficient web analytics for Rack apps}
13
14
  spec.description = %q{A gem that provides a Redis based web analytics solution for your rack-compliant apps. It gives you detailed analytics about visitors, unique visitors, browsers, OS, visitor recency, traffic sources and more}
14
15
 
15
16
  spec.rubyforge_project = "redis_analytics"
@@ -20,18 +21,22 @@ Gem::Specification.new do |spec|
20
21
  spec.default_executable = 'redis_analytics_dashboard'
21
22
  spec.require_paths = ["lib"]
22
23
 
23
- spec.add_runtime_dependency('rack', '>= 1.4.0')
24
- spec.add_runtime_dependency('redis', '>= 3.0.2')
25
- spec.add_runtime_dependency('browser', '>= 0.1.6')
26
- spec.add_runtime_dependency('sinatra', '>= 1.3.3')
27
- spec.add_runtime_dependency('geoip', '>= 1.2.1')
28
- spec.add_runtime_dependency('json', '>= 1.7.7')
29
- spec.add_runtime_dependency('activesupport', '>= 3.2.0')
30
-
31
- spec.add_development_dependency('rake', '>= 10.0.3')
32
- spec.add_development_dependency('rspec', '>= 2.11.0')
33
- spec.add_development_dependency('mocha', '>= 0.12.7')
34
- spec.add_development_dependency('rack-test', '>= 0.6.2')
24
+ spec.add_runtime_dependency('rack')
25
+ spec.add_runtime_dependency('redis')
26
+ spec.add_runtime_dependency('browser')
27
+ spec.add_runtime_dependency('sinatra')
28
+ spec.add_runtime_dependency('sinatra-assetpack')
29
+ spec.add_runtime_dependency('geoip')
30
+ spec.add_runtime_dependency('json')
31
+
32
+ spec.add_development_dependency('fakeredis')
33
+ spec.add_development_dependency('rake')
34
+ spec.add_development_dependency('rspec')
35
+ spec.add_development_dependency('guard-rspec')
36
+ spec.add_development_dependency('mocha')
37
+ spec.add_development_dependency('rack-test')
38
+ spec.add_development_dependency('simplecov')
39
+ spec.add_development_dependency('coveralls')
35
40
 
36
41
  spec.required_ruby_version = '>= 1.9.2'
37
42
  end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::RedisAnalytics::Analytics do
4
+
5
+ subject(:app) {
6
+ Rack::Builder.app do
7
+ use Rack::RedisAnalytics::Analytics
8
+ run Proc.new { |env| [200, {'Content-Type' => 'text/html'}, "Hello!"] }
9
+ end
10
+ }
11
+
12
+ before(:each) do
13
+ clear_cookies
14
+ end
15
+
16
+ # Spec for Cookies
17
+ context "when a user makes 2 visits and the current visit cookie and first visit cookie are not expired" do
18
+ def cookie
19
+ last_response.original_headers['Set-Cookie']
20
+ end
21
+ it "should count as the same visit in the cookie" do
22
+ t1 = Time.now
23
+ Time.stubs(:now).returns(t1)
24
+ get '/'
25
+ cookie.should match("#{Rack::RedisAnalytics.current_visit_cookie_name}=1.1.1.#{t1.to_i}.#{t1.to_i}")
26
+ cookie.should match("#{Rack::RedisAnalytics.first_visit_cookie_name}=1.#{t1.to_i}.#{t1.to_i}")
27
+ t2 = t1 + 5 # just adding 5 seconds
28
+ Time.stubs(:now).returns(t2)
29
+ get '/'
30
+ cookie.should match("#{Rack::RedisAnalytics.current_visit_cookie_name}=1.1.2.#{t1.to_i}.#{t2.to_i}")
31
+ cookie.should match("#{Rack::RedisAnalytics.first_visit_cookie_name}=1.#{t1.to_i}.#{t2.to_i}")
32
+ end
33
+ end
34
+
35
+ context "when a user makes 2 visits, but current visit cookie and first visit cookie are both non-existent" do
36
+ def cookie
37
+ last_response.original_headers['Set-Cookie']
38
+ end
39
+ it "should count as a separate and new visit in the cookie" do
40
+ t1 = Time.now
41
+ Time.stubs(:now).returns(t1)
42
+ get '/'
43
+ cookie.should match("#{Rack::RedisAnalytics.current_visit_cookie_name}=1.1.1.#{t1.to_i}.#{t1.to_i}")
44
+ cookie.should match("#{Rack::RedisAnalytics.first_visit_cookie_name}=1.#{t1.to_i}.#{t1.to_i}")
45
+ clear_cookies
46
+
47
+ t2 = t1 + 5 # just adding 5 seconds
48
+ Time.stubs(:now).returns(t2)
49
+ get '/'
50
+ cookie.should match("#{Rack::RedisAnalytics.current_visit_cookie_name}=2.2.1.#{t2.to_i}.#{t2.to_i}")
51
+ cookie.should match("#{Rack::RedisAnalytics.first_visit_cookie_name}=2.#{t2.to_i}.#{t2.to_i}")
52
+ end
53
+ end
54
+
55
+ context "when a user makes 2 visits, and visit cookie is expired but the returning user cookie exists" do
56
+ it "should count as a separate visit but not a new visit"
57
+ end
58
+
59
+ end
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::RedisAnalytics::Configuration do
4
+
5
+ context 'property redis_connection' do
6
+ subject(:connection) { Rack::RedisAnalytics.redis_connection }
7
+ it 'should not be nil' do
8
+ connection.should_not be_nil
9
+ end
10
+ it 'should be an instance of Redis' do
11
+ connection.instance_of? Redis
12
+ end
13
+ end
14
+
15
+ context 'property redis_namespace' do
16
+ subject(:namespace) { Rack::RedisAnalytics.redis_namespace }
17
+ it 'should not be nil' do
18
+ namespace.should_not be_nil
19
+ end
20
+ it 'should have an default value' do
21
+ namespace.should be == "_ra_test_namespace"
22
+ end
23
+ it 'can be set to another value' do
24
+ namespace = "test_ra"
25
+ namespace.should be == "test_ra"
26
+ end
27
+ end
28
+
29
+ context 'property first_visit_cookie_name' do
30
+ subject(:return_cookie) { Rack::RedisAnalytics.first_visit_cookie_name }
31
+ it 'should not be nil' do
32
+ return_cookie.should_not be_nil
33
+ end
34
+ it 'should have an default value' do
35
+ return_cookie.should be == "_rucn"
36
+ end
37
+ it 'has an setter method' do
38
+ return_cookie = "rucn"
39
+ return_cookie.should be == "rucn"
40
+ end
41
+ end
42
+
43
+ context 'property current_visit_cookie_name' do
44
+ subject(:current_visit_cookie_name) { Rack::RedisAnalytics.current_visit_cookie_name }
45
+ it 'should not be nil' do
46
+ current_visit_cookie_name.should_not be_nil
47
+ end
48
+ it 'should have an default value' do
49
+ current_visit_cookie_name.should be == "_vcn"
50
+ end
51
+ it 'can be set to another value' do
52
+ current_visit_cookie_name = "test_vcn"
53
+ current_visit_cookie_name.should be == "test_vcn"
54
+ end
55
+ end
56
+
57
+ context 'property visit_timeout' do
58
+ subject(:visit_timeout) { Rack::RedisAnalytics.visit_timeout }
59
+ it 'should not be nil' do
60
+ visit_timeout.should_not be_nil
61
+ end
62
+ it 'should have an default value' do
63
+ visit_timeout.should be == 1
64
+ end
65
+ it 'can be set to another value' do
66
+ visit_timeout = 5
67
+ visit_timeout.should be == 5
68
+ end
69
+ end
70
+
71
+ context 'property visitor_recency_slices' do
72
+ subject(:visitor_recency_slices) { Rack::RedisAnalytics.visitor_recency_slices }
73
+ it 'should not be nil' do
74
+ visitor_recency_slices.should_not be_nil
75
+ end
76
+ it 'should be an Array of Fixnum' do
77
+ visitor_recency_slices.instance_of? Array
78
+ visitor_recency_slices.each do |value|
79
+ value.instance_of? Fixnum
80
+ end
81
+ end
82
+ it 'can be set to another value' do
83
+ visitor_recency_slices = [3, 7, 9]
84
+ expect(visitor_recency_slices).to eq([3, 7, 9])
85
+ end
86
+ end
87
+
88
+ context 'property default_range' do
89
+ subject(:default_range) { Rack::RedisAnalytics.default_range }
90
+ it 'should not be nil' do
91
+ default_range.should_not be_nil
92
+ end
93
+ it 'should be an symbol' do
94
+ default_range.instance_of? Symbol
95
+ end
96
+ it 'should have an value' do
97
+ default_range.should be == :day
98
+ end
99
+ it 'can be set to another value' do
100
+ default_range = :month
101
+ default_range.should be :month
102
+ end
103
+ end
104
+
105
+ context 'property redis_key_timestamps' do
106
+ subject(:redis_key_timestamps) { Rack::RedisAnalytics.redis_key_timestamps }
107
+ it 'should not be nil' do
108
+ redis_key_timestamps.should_not be_nil
109
+ end
110
+ it 'should be an instance of Array' do
111
+ redis_key_timestamps.instance_of? Array
112
+ end
113
+ it 'can be set to another value' do
114
+ redis_key_timestamps = ['one', 'two']
115
+ expect(redis_key_timestamps).to eq(['one','two'])
116
+ end
117
+ end
118
+
119
+ context 'property time_range_formats' do
120
+ subject(:time_range_formats) { Rack::RedisAnalytics.time_range_formats }
121
+ it 'should not be nil' do
122
+ time_range_formats.should_not be_nil
123
+ end
124
+ it 'should be an Array of Array' do
125
+ time_range_formats.instance_of? Array
126
+ time_range_formats.each do |range|
127
+ range.instance_of? Array
128
+ end
129
+ end
130
+ it 'can be set to another value' do
131
+ time_range_formats = "nothing"
132
+ expect(time_range_formats).to eq("nothing")
133
+ end
134
+ end
135
+
136
+ context 'method add_filter' do
137
+ subject(:filters) { Rack::RedisAnalytics.filters }
138
+ it 'should add a new filter' do
139
+ proc = Proc.new {}
140
+ Rack::RedisAnalytics.configure do |c|
141
+ c.add_filter(&proc)
142
+ end
143
+ filters[0].should be_an_instance_of Rack::RedisAnalytics::Filter
144
+ end
145
+ end
146
+
147
+ context 'method add_path_filter' do
148
+ subject(:path_filters) { Rack::RedisAnalytics.path_filters }
149
+ it 'should add a new path filter' do
150
+ path = '/hello'
151
+ Rack::RedisAnalytics.configure do |c|
152
+ c.add_path_filter(path)
153
+ end
154
+ path_filters[0].should be_an_instance_of Rack::RedisAnalytics::PathFilter
155
+ end
156
+ end
157
+
158
+ end