bit_analytics 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: 8978bfb9dd2bf699d69081776c673859b7893687
4
+ data.tar.gz: 22dce94749ec582804d3fba2de027effa55de4b9
5
+ !binary "U0hBNTEy":
6
+ metadata.gz: a24a71ba813bdb1b5daf2177450a91bd7fb544d322cbb7e10dd58e82006751678cf6a74a79781606b034b61703f5672b16584c7cbd39aae612076bdbe1a4f039
7
+ data.tar.gz: c5fdc49e40652c6eb5529f1cb23106ce3bf1f3cf5f0557d0112157da15aaf7f1cc4da956ab09c829ed63d08692c03ff6e534686db5add1e01e25a738fdbef3df
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bit_analytics.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,28 @@
1
+ Copyright: 2012 by Doist Ltd., Amir Salihefendic
2
+ Copyright (c) 2014 Jure Triglav.
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification,
6
+ are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of BitAnalytics nor the names of its contributors may be used
16
+ to endorse or promote products derived from this software without
17
+ specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # bit_analytics: a powerful analytics library for Redis for Ruby
2
+
3
+ This Ruby gem (a port of [@amix's bitmapist library for Python](https://github.com/Doist/bitmapist)) makes it possible to implement real-time, highly scalable analytics that can answer following questions:
4
+
5
+ * Has user 123 been online today? This week? This month?
6
+ * Has user 123 performed action "X"?
7
+ * How many users have been active have this month? This hour?
8
+ * How many unique users have performed action "X" this week?
9
+ * How many % of users that were active last week are still active?
10
+ * How many % of users that were active last month are still active this month?
11
+
12
+ This gem is very easy to use and enables you to create your own reports easily.
13
+
14
+ Using Redis bitmaps you can store events for millions of users in a very little amount of memory (megabytes).
15
+ You should be careful about using huge ids (e.g. 2^32 or bigger) as this could require larger amounts of memory.
16
+
17
+ If you want to read more about bitmaps please read following:
18
+
19
+ * http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/
20
+ * http://redis.io/commands/setbit
21
+ * http://en.wikipedia.org/wiki/Bit_array
22
+ * http://www.slideshare.net/crashlytics/crashlytics-on-redis-analytics
23
+ * http://amix.dk/blog/post/19714 [my blog post]
24
+
25
+ Requires Redis 2.6+.
26
+
27
+ # Installation
28
+
29
+ ```
30
+ $ gem install bit_analytics
31
+ ```
32
+
33
+ # Ports
34
+
35
+ * Original Python library: https://github.com/Doist/bitmapist
36
+ * PHP port: https://github.com/jeremyFreeAgent/Bitter
37
+
38
+ # Examples
39
+
40
+ Setting things up:
41
+
42
+ ```ruby
43
+ require 'date'
44
+ now = Time.now.getutc
45
+ last_month = (Date.today << 1).to_time
46
+
47
+ # This connects to the default Redis (localhost:6379)
48
+ @bit_analytics = BitAnalytics.new
49
+
50
+ # You can also use custom Redis options
51
+ @bit_analytics = BitAnalytics.new(host: "10.0.1.1", port: 6380)
52
+ ```
53
+
54
+ Mark user 123 as active and has played a song:
55
+
56
+ ```ruby
57
+ @bit_anaytics.mark_event('active', 123)
58
+ @bit_anaytics.mark_event('song:played', 123)
59
+ ```
60
+
61
+ Answer if user 123 has been active this month:
62
+
63
+ ```ruby
64
+ @bit_analytics.month_events('active', now.year, now.month).includes?(123)
65
+ @bit_analytics.month_events('song:played', now.year, now.month).includes?(123)
66
+ @bit_analytics.month_events('active', now.year, now.month).has_events_marked == true
67
+ ```
68
+
69
+ How many users have been active this week?:
70
+
71
+ ```ruby
72
+ this_week = Time.now.strftime('%V')
73
+ @bit_analytics.week_events('active', now.year, this_week)
74
+ ```
75
+
76
+ Perform bit operations. How many users that have been active last month are still active this month?
77
+
78
+ ```ruby
79
+ active_2_months = @bit_analytics.bit_op_and(
80
+ @bit_analytics.month_events('active', last_month.year, last_month.month),
81
+ @bit_analytics.month_events('active', now.year, now.month)
82
+ )
83
+ puts active_2_months.length
84
+
85
+ # Is 123 active for 2 months?
86
+ active_2_months.includes?(123)
87
+ ```
88
+
89
+ Work with nested bit operations (imagine what you can do with this ;))!
90
+
91
+ ```ruby
92
+ active_2_months = @bit_analytics.bit_op_and(
93
+ @bit_analytics.bit_op_and(
94
+ @bit_analytics.month_events('active', last_month.year, last_month.month),
95
+ @bit_analytics.month_events('active', now.year, now.month)
96
+ ),
97
+ @bit_analytics.month_events('active', now.year, now.month)
98
+ )
99
+ puts active_2_months.length
100
+ active_2_months.includes?(123)
101
+
102
+ # Delete the temporary AND operation
103
+ active_2_months.delete
104
+ ```
105
+
106
+ Tracking hourly is disabled by default to save memory, but you can supply an extra argument to `mark_event` to track events hourly:
107
+
108
+ ```ruby
109
+ @bit_analytics.mark_event('active', 123, track_hourly: true)
110
+ ```
111
+
112
+ Original library: Copyright: 2012 by Doist Ltd. Developer: Amir Salihefendic ( http://amix.dk ) License: BSD
113
+
114
+ Ruby port: Copyright 2014 Jure Triglav License: BSD
115
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.options = "-v"
6
+ t.test_files = FileList["test/*_test.rb"]
7
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bit_analytics/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bit_analytics"
8
+ spec.version = BitAnalytics::VERSION
9
+ spec.authors = ["Jure Triglav"]
10
+ spec.email = ["juretriglav@gmail.com"]
11
+ spec.description = %q{Analytics library built with Redis bitmaps}
12
+ spec.summary = %q{Implements a powerful analytics library on top of Redis's support for bitmaps and bitmap operations.}
13
+ spec.homepage = "http://www.github.com/jure/bit_analytics"
14
+ spec.license = "BSD"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "redis", "~> 3.0"
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "pry"
25
+ end
@@ -0,0 +1,3 @@
1
+ class BitAnalytics
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,259 @@
1
+ require "bit_analytics/version"
2
+ require 'redis'
3
+
4
+ class BitAnalytics
5
+ attr_accessor :redis
6
+
7
+ def initialize(options=nil)
8
+ @redis = if options
9
+ Redis.new(options)
10
+ else
11
+ Redis.new
12
+ end
13
+ end
14
+
15
+ #--- Events marking and deleting ---
16
+ # Marks an event for hours, days, weeks and months.
17
+ # :param :event_name The name of the event, could be "active" or "new_signups"
18
+ # :param :uuid An unique id, typically user id. The id should not be huge, read Redis documentation why (bitmaps)
19
+ # :param :now Which date should be used as a reference point, default is `datetime.utcnow`
20
+ # :param :track_hourly Should hourly stats be tracked, defaults to bitanalytics.TRACK_HOURLY, but an be changed
21
+ # Examples:
22
+ # Mark id 1 as active
23
+ # mark_event('active', 1)
24
+ # Mark task completed for id 252
25
+ # mark_event('tasks:completed', 252)
26
+ def mark_event(event_name, uuid, now: nil, track_hourly: nil)
27
+ # Has memory applications
28
+ track_hourly ||= false
29
+ now ||= Time.now.getutc
30
+ # E.g. ['2014', '03'] for 17th of January 2014
31
+ iso_date = now.strftime('%Y-%V').split('-')
32
+
33
+ events = [
34
+ MonthEvents.new(event_name, now.year, now.month),
35
+ WeekEvents.new(event_name, iso_date[0], iso_date[1]),
36
+ DayEvents.new(event_name, now.year, now.month, now.day),
37
+ ]
38
+
39
+ if track_hourly
40
+ events << HourEvents.new(event_name, now.year, now.month, now.day, now.hour)
41
+ end
42
+
43
+ @redis.pipelined do
44
+ events.each do |event|
45
+ @redis.setbit(event.redis_key, uuid, 1)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Delete all events from the database.
51
+ def delete_all_events
52
+ keys = @redis.keys('bitanalytics_*')
53
+ @redis.del(*keys) unless keys.empty?
54
+ end
55
+
56
+ # Delete all temporary keys that are used when using bit operations.
57
+ def delete_temporary_bitop_keys
58
+ keys = @redis.keys('bitanalytics_bitop_*')
59
+ @redis.del(keys) unless keys.empty?
60
+ end
61
+
62
+ #--- Events ---
63
+
64
+ def month_events(event_name, year, month)
65
+ month_events = MonthEvents.new(event_name, year, month)
66
+ month_events.redis = @redis
67
+ month_events
68
+ end
69
+
70
+ def week_events(event_name, year, week)
71
+ week_events = WeekEvents.new(event_name, year, week)
72
+ week_events.redis = @redis
73
+ week_events
74
+ end
75
+
76
+ def day_events(event_name, year, month, day)
77
+ day_events = DayEvents.new(event_name, year, month, day)
78
+ day_events.redis = @redis
79
+ day_events
80
+ end
81
+
82
+ def hour_events(event_name, year, month, day, hour)
83
+ hour_events = HourEvents.new(event_name, year, month, day, hour)
84
+ hour_events.redis = @redis
85
+ hour_events
86
+ end
87
+
88
+ #--- BitOps ---
89
+
90
+ def bit_op_and(event, *events)
91
+ bit_operation = BitOperation.new('AND', event, *events)
92
+ bit_operation.redis = @redis
93
+ bit_operation.execute
94
+ bit_operation
95
+ end
96
+
97
+ def bit_op_or(event, *events)
98
+ bit_operation = BitOperation.new('OR', event, *events)
99
+ bit_operation.redis = @redis
100
+ bit_operation.execute
101
+ bit_operation
102
+ end
103
+
104
+ def bit_op_xor(event, *events)
105
+ bit_operation = BitOperation.new('XOR', event, *events)
106
+ bit_operation.redis = @redis
107
+ bit_operation.execute
108
+ bit_operation
109
+ end
110
+
111
+ #--- Private ---
112
+
113
+ def _prefix_key(event_name, date)
114
+ return 'bitanalytics_%s_%s' % [event_name, date]
115
+ end
116
+
117
+ #--- Events ---
118
+
119
+ # Extends with an obj.has_events_marked()
120
+ # that returns `True` if there are any events marked,
121
+ # otherwise `False` is returned.
122
+
123
+ # Extens also with a obj.delete()
124
+ # (useful for deleting temporary calculations).
125
+
126
+ module MixinEventsMisc
127
+ def has_events_marked
128
+ @redis.get(@redis_key) != nil
129
+ end
130
+ def delete
131
+ @redis.del(@redis_key)
132
+ end
133
+ end
134
+
135
+ # Extends with an obj.get_count() that uses BITCOUNT to
136
+ # count all the events. Supports also __len__
137
+
138
+ module MixinCounts
139
+ def get_count
140
+ @redis.bitcount(@redis_key)
141
+ end
142
+
143
+ def length
144
+ return get_count
145
+ end
146
+ end
147
+
148
+ # Makes it possible to see if an uuid has been marked.
149
+ # Example:
150
+ # user_active_today = 123 in DayEvents('active', 2012, 10, 23)
151
+ module MixinContains
152
+ def includes?(uuid)
153
+ if @redis.getbit(self.redis_key, uuid) == 1
154
+ true
155
+ else
156
+ false
157
+ end
158
+ end
159
+ end
160
+
161
+ module RedisConnection
162
+ attr_accessor :redis
163
+ attr_reader :redis_key
164
+ end
165
+ end
166
+
167
+
168
+ # Events for a month.
169
+ # Example:
170
+ # MonthEvents('active', 2012, 10)
171
+ class MonthEvents < BitAnalytics
172
+ include RedisConnection
173
+ include MixinCounts
174
+ include MixinContains
175
+ include MixinEventsMisc
176
+
177
+ attr_reader :redis_key
178
+
179
+ def initialize(event_name, year, month)
180
+ @redis_key = _prefix_key(event_name,'%s-%s' % [year, month])
181
+ end
182
+ end
183
+
184
+ # Events for a week.
185
+ # Example:
186
+ # WeekEvents('active', 2012, 48)
187
+ class WeekEvents < BitAnalytics
188
+ include RedisConnection
189
+ include MixinCounts
190
+ include MixinContains
191
+ include MixinEventsMisc
192
+
193
+ def initialize(event_name, year, week)
194
+ @redis_key = _prefix_key(event_name,'W%s-%s' % [year, week])
195
+ end
196
+ end
197
+
198
+ # Events for a day.
199
+ # Example:
200
+ # DayEvents('active', 2012, 10, 23)
201
+ class DayEvents < BitAnalytics
202
+ include RedisConnection
203
+ include MixinCounts
204
+ include MixinContains
205
+ include MixinEventsMisc
206
+
207
+ def initialize(event_name, year, month, day)
208
+ @redis_key = _prefix_key(event_name,'%s-%s-%s' % [year, month, day])
209
+ end
210
+ end
211
+
212
+ # Events for a hour.
213
+ # Example:
214
+ # HourEvents('active', 2012, 10, 23, 13)
215
+ class HourEvents < BitAnalytics
216
+ include RedisConnection
217
+ include MixinCounts
218
+ include MixinContains
219
+ include MixinEventsMisc
220
+
221
+ def initialize(event_name, year, month, day, hour)
222
+ @redis_key = _prefix_key(event_name,'%s-%s-%s-%s' % [year, month, day, hour])
223
+ end
224
+ end
225
+
226
+ #--- Bit operations ---
227
+ # Base class for bit operations (AND, OR, XOR).
228
+ # Please note that each bit operation creates a new key prefixed with `bitanalytics_bitop_`.
229
+ # These temporary keys can be deleted with `delete_temporary_bitop_keys`.
230
+
231
+ # You can even nest bit operations.
232
+ # Example:
233
+ # active_2_months = BitOpAnd(
234
+ # MonthEvents('active', last_month.year, last_month.month),
235
+ # MonthEvents('active', now.year, now.month)
236
+ # )
237
+ # active_2_months = BitOpAnd(
238
+ # BitOpAnd(
239
+ # MonthEvents('active', last_month.year, last_month.month),
240
+ # MonthEvents('active', now.year, now.month)
241
+ # ),
242
+ # MonthEvents('active', now.year, now.month)
243
+ # )
244
+ class BitOperation < BitAnalytics
245
+ include MixinContains
246
+ include MixinCounts
247
+ include MixinEventsMisc
248
+ include RedisConnection
249
+
250
+ def initialize(op_name, *events)
251
+ @op_name = op_name
252
+ @event_redis_keys = events.map(&:redis_key)
253
+ @redis_key = 'bitanalytics_bitop_%s_%s' % [@op_name, @event_redis_keys.join('-')]
254
+ end
255
+
256
+ def execute
257
+ @redis.bitop(@op_name, @redis_key, @event_redis_keys)
258
+ end
259
+ end
@@ -0,0 +1,142 @@
1
+ require 'date'
2
+ require 'test/unit'
3
+ require 'bit_analytics'
4
+
5
+ class BitAnalyticsTest < Test::Unit::TestCase
6
+ def setup
7
+ @bit_analytics = BitAnalytics.new
8
+ end
9
+
10
+ def test_mark_with_diff_days
11
+ @bit_analytics.delete_all_events
12
+ @bit_analytics.mark_event('active', 123, track_hourly: true)
13
+
14
+ now = Time.now.getutc
15
+
16
+ # E.g. ['2014', '03'] for 17th of January 2014
17
+ iso_date = now.strftime('%Y-%V').split('-')
18
+
19
+ # Month
20
+ assert @bit_analytics.month_events('active', now.year, now.month).includes?(123)
21
+ assert !@bit_analytics.month_events('active', now.year, now.month).includes?(124)
22
+
23
+ # Week
24
+ assert @bit_analytics.week_events('active', now.year, iso_date[1]).includes?(123)
25
+ assert !@bit_analytics.week_events('active', now.year, iso_date[1]).includes?(124)
26
+
27
+ # Day
28
+ assert @bit_analytics.day_events('active', now.year, now.month, now.day).includes?(123)
29
+ assert !@bit_analytics.day_events('active', now.year, now.month, now.day).includes?(124)
30
+
31
+ # Hour
32
+ assert @bit_analytics.hour_events('active', now.year, now.month, now.day, now.hour).includes?(123)
33
+ assert !@bit_analytics.hour_events('active', now.year, now.month, now.day, now.hour).includes?(124)
34
+ assert !@bit_analytics.hour_events('active', now.year, now.month, now.day, now.hour-1).includes?(124)
35
+ end
36
+
37
+ def test_mark_counts
38
+ @bit_analytics.delete_all_events
39
+
40
+ now = Time.now.getutc
41
+ assert @bit_analytics.month_events('active', now.year, now.month).get_count == 0
42
+
43
+ @bit_analytics.mark_event('active', 123)
44
+ @bit_analytics.mark_event('active', 23232)
45
+
46
+ assert @bit_analytics.month_events('active', now.year, now.month).length == 2
47
+ end
48
+
49
+ def test_different_dates
50
+ @bit_analytics.delete_all_events
51
+
52
+ now = Time.now.getutc
53
+ yesterday = (Date.today - 1).to_time
54
+
55
+ @bit_analytics.mark_event('active', 123, now: now)
56
+ @bit_analytics.mark_event('active', 23232, now: yesterday)
57
+
58
+ assert @bit_analytics.day_events('active',
59
+ now.year,
60
+ now.month,
61
+ now.day).get_count == 1
62
+
63
+ assert @bit_analytics.day_events('active',
64
+ yesterday.year,
65
+ yesterday.month,
66
+ yesterday.day).get_count == 1
67
+ end
68
+
69
+ def test_different_buckets
70
+ @bit_analytics.delete_all_events
71
+
72
+ now = Time.now.getutc
73
+
74
+ @bit_analytics.mark_event('active', 123)
75
+ @bit_analytics.mark_event('tasks:completed', 23232)
76
+
77
+ assert @bit_analytics.month_events('active', now.year, now.month).get_count == 1
78
+ assert @bit_analytics.month_events('tasks:completed', now.year, now.month).get_count == 1
79
+ end
80
+
81
+ def test_bit_operations
82
+ @bit_analytics.delete_all_events
83
+
84
+ now = Time.now.getutc
85
+ last_month = (Date.today << 1).to_time
86
+
87
+ # 123 has been active for two months
88
+ @bit_analytics.mark_event('active', 123, now: now)
89
+ @bit_analytics.mark_event('active', 123, now: last_month)
90
+
91
+ # 224 has only been active last_month
92
+ @bit_analytics.mark_event('active', 224, now: last_month)
93
+
94
+ # Assert basic premises
95
+ assert @bit_analytics.month_events('active', last_month.year, last_month.month).get_count == 2
96
+ assert @bit_analytics.month_events('active', now.year, now.month).get_count == 1
97
+
98
+ # Try out with bit AND operation
99
+ active_2_months = @bit_analytics.bit_op_and(
100
+ @bit_analytics.month_events('active', last_month.year, last_month.month),
101
+ @bit_analytics.month_events('active', now.year, now.month)
102
+ )
103
+ assert active_2_months.get_count == 1
104
+ assert active_2_months.includes?(123)
105
+ assert !(active_2_months).includes?(224)
106
+ active_2_months.delete
107
+
108
+ # Try out with bit OR operation
109
+ assert @bit_analytics.bit_op_or(
110
+ @bit_analytics.month_events('active', last_month.year, last_month.month),
111
+ @bit_analytics.month_events('active', now.year, now.month)
112
+ ).get_count == 2
113
+
114
+ # Try nested operations
115
+ active_2_months = @bit_analytics.bit_op_and(
116
+ @bit_analytics.bit_op_and(
117
+ @bit_analytics.month_events('active', last_month.year, last_month.month),
118
+ @bit_analytics.month_events('active', now.year, now.month)
119
+ ),
120
+ @bit_analytics.month_events('active', now.year, now.month)
121
+ )
122
+
123
+ assert active_2_months.includes?(123)
124
+ assert !active_2_months.includes?(224)
125
+ active_2_months.delete
126
+ end
127
+
128
+ def test_events_marked
129
+ @bit_analytics.delete_all_events
130
+
131
+ now = Time.now.getutc
132
+
133
+ assert @bit_analytics.month_events('active', now.year, now.month).get_count == 0
134
+ assert @bit_analytics.month_events('active', now.year, now.month).has_events_marked == false
135
+
136
+ @bit_analytics.mark_event('active', 123, now: now)
137
+
138
+ assert @bit_analytics.month_events('active', now.year, now.month).get_count == 1
139
+ assert @bit_analytics.month_events('active', now.year, now.month).has_events_marked == true
140
+ end
141
+ end
142
+
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bit_analytics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jure Triglav
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Analytics library built with Redis bitmaps
70
+ email:
71
+ - juretriglav@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - .gitignore
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - bit_analytics.gemspec
82
+ - lib/bit_analytics.rb
83
+ - lib/bit_analytics/version.rb
84
+ - test/bit_analytics_test.rb
85
+ homepage: http://www.github.com/jure/bit_analytics
86
+ licenses:
87
+ - BSD
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.0.14
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Implements a powerful analytics library on top of Redis's support for bitmaps
109
+ and bitmap operations.
110
+ test_files:
111
+ - test/bit_analytics_test.rb