minuteman 1.0.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gems +3 -0
  3. data/.travis.yml +4 -3
  4. data/ORIGIN.md +21 -0
  5. data/README.md +115 -122
  6. data/Rakefile +3 -3
  7. data/SPEC.md +21 -0
  8. data/lib/minuteman.rb +88 -122
  9. data/lib/minuteman/analyzable.rb +96 -0
  10. data/lib/minuteman/analyzer.rb +21 -0
  11. data/lib/minuteman/configuration.rb +25 -0
  12. data/lib/minuteman/counter.rb +21 -0
  13. data/lib/minuteman/event.rb +12 -0
  14. data/lib/minuteman/lua/operations.lua +37 -0
  15. data/lib/minuteman/model.rb +36 -0
  16. data/lib/minuteman/result.rb +12 -0
  17. data/lib/minuteman/trigger.rb +4 -0
  18. data/lib/minuteman/user.rb +38 -0
  19. data/minuteman.gemspec +4 -5
  20. data/test/helper.rb +2 -0
  21. data/test/minuteman_bench.rb +72 -0
  22. data/test/minuteman_test.rb +204 -0
  23. metadata +44 -73
  24. data/Gemfile +0 -4
  25. data/Gemfile.lock +0 -30
  26. data/lib/minuteman/bit_operations.rb +0 -97
  27. data/lib/minuteman/bit_operations/data.rb +0 -33
  28. data/lib/minuteman/bit_operations/operation.rb +0 -115
  29. data/lib/minuteman/bit_operations/plain.rb +0 -34
  30. data/lib/minuteman/bit_operations/result.rb +0 -15
  31. data/lib/minuteman/bit_operations/with_data.rb +0 -56
  32. data/lib/minuteman/keys_methods.rb +0 -23
  33. data/lib/minuteman/time_events.rb +0 -18
  34. data/lib/minuteman/time_span.rb +0 -36
  35. data/lib/minuteman/time_spans.rb +0 -7
  36. data/lib/minuteman/time_spans/day.rb +0 -17
  37. data/lib/minuteman/time_spans/hour.rb +0 -19
  38. data/lib/minuteman/time_spans/minute.rb +0 -19
  39. data/lib/minuteman/time_spans/month.rb +0 -17
  40. data/lib/minuteman/time_spans/week.rb +0 -18
  41. data/lib/minuteman/time_spans/year.rb +0 -17
  42. data/test/bench/minuteman_bench.rb +0 -37
  43. data/test/test_helper.rb +0 -9
  44. data/test/unit/minuteman_test.rb +0 -225
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 33273982b184b97986adee038d64bc71a5ebf868
4
+ data.tar.gz: 1787e29f6314d78e1967140a1194692b58fc678c
5
+ SHA512:
6
+ metadata.gz: 8e3d61fa6e931eceb2935d14ca8d734494e945e04d7a8676565e8c1c5e47454cfffdc336d71724e9c05ccfa2ac17e4f79fe69c4d4054bb1223988653a63c9d2a
7
+ data.tar.gz: 4925693e4ed12b00efe943693c0940296eb6c7d762e5a8697be551381ce0711b1feee081e778867f7a3c1d24db99c914c3a13da7cd0b9f69acb77ea9f3af9119
data/.gems ADDED
@@ -0,0 +1,3 @@
1
+ redic:1.5.0
2
+ ohm:2.3.0
3
+ cutest:1.2.2
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
+ sudo: false
3
+ install: bash <(curl -s https://raw.githubusercontent.com/elcuervo/rpm/master/bin/rpm-install)
2
4
  rvm:
3
- - "1.9.3"
4
- - "jruby-19mode"
5
- - "rbx-19mode"
5
+ - "2.0.0"
6
+ - "2.2.2"
6
7
  services:
7
8
  - "redis-server"
@@ -0,0 +1,21 @@
1
+ # Origin
2
+
3
+ _Freenode - #cuba.rb - 2012/10/30 15:20 UYT_
4
+
5
+ > **conanbatt:** anyone here knows some good web app metrics tool ?
6
+
7
+ > **conanbatt:** i use google analytics for the page itself, and its good, but for the webapp its really not useful
8
+
9
+ > **tizoc: conanbatt:** http://amix.dk/blog/post/19714 you can port this (if an equivalent doesn't exist already)
10
+
11
+ > **conanbatt:** the metrics link is excellent but its python and released 5 days ago lol
12
+
13
+ > **elcuervo: tizoc:** the idea it's awesome
14
+
15
+ > **elcuervo:** interesting...
16
+
17
+ ## Inspiration
18
+
19
+ * http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/
20
+ * http://amix.dk/blog/post/19714
21
+ * http://en.wikipedia.org/wiki/Bit_array
data/README.md CHANGED
@@ -2,172 +2,165 @@
2
2
 
3
3
  # Minuteman
4
4
  [![Code Climate](https://codeclimate.com/github/elcuervo/minuteman.png)](https://codeclimate.com/github/elcuervo/minuteman)
5
- [![Build Status](https://secure.travis-ci.org/elcuervo/minuteman.png?branch=master)](https://travis-ci.org/elcuervo/minuteman)
6
5
 
7
- _Wikipedia_: Minutemen were members of teams from Massachusetts that were well-prepared
6
+ [![Build Status](https://travis-ci.org/elcuervo/minuteman.svg)](https://travis-ci.org/elcuervo/minuteman)
7
+
8
+ > Minutemen were members of teams from Massachusetts that were well-prepared
8
9
  militia companies of select men from the American colonial partisan militia
9
10
  during the American Revolutionary War. _They provided a highly mobile, rapidly
10
11
  deployed force that allowed the colonies to respond immediately to war threats,
11
12
  hence the name._
12
13
 
13
- ## Origin
14
- Freenode - #cuba.rb - 2012/10/30 15:20 UYT
15
-
16
- **conanbatt:** anyone here knows some good web app metrics tool ?
17
-
18
- **conanbatt:** i use google analytics for the page itself, and its good, but for the webapp its really not useful
19
-
20
- **tizoc: conanbatt:** http://amix.dk/blog/post/19714 you can port this (if an equivalent doesn't exist already)
21
-
22
- **conanbatt:** the metrics link is excellent but its python and released 5 days ago lol
23
-
24
- **elcuervo: tizoc:** the idea it's awesome
25
-
26
- **elcuervo:** interesting...
27
-
28
-
29
- ## Inspiration
30
-
31
- * http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/
32
- * http://amix.dk/blog/post/19714
33
- * http://en.wikipedia.org/wiki/Bit_array
34
-
35
14
  ## Installation
36
15
 
37
- ### Important!
38
-
39
- Depends on Redis 2.6 for the `bitop` operation. You can install it using:
40
-
41
- ```bash
42
- brew install redis
43
- ```
44
-
45
- or upgrading your current version:
46
-
47
- ```bash
48
- brew upgrade redis
49
- ```
50
-
51
- And then install the gem
52
-
53
16
  ```bash
54
17
  gem install minuteman
55
18
  ```
56
19
 
57
- ## Usage
58
-
59
- Currently Minutemen supports two options `:silent (default: false)` and `:redis
60
- (default: {})`
20
+ ### Configuration
61
21
 
62
- ### Options
22
+ Configuration exists within the `config` block:
63
23
 
64
- **silent**: when `true` the operations will not raise errors to prevent failures
24
+ ```ruby
25
+ Minuteman.configure do |config|
26
+ # You need to use Redic to define a new Redis connection
27
+ config.redis = Redic.new("redis://127.0.0.1:6379/1")
28
+
29
+ # The prefix affects operations
30
+ config.prefix = "Tomato"
31
+
32
+ # The patterns is what Minuteman uses for the tracking/counting and the
33
+ # different analyzers
34
+ config.patterns = {
35
+ dia: -> (time) { time.strftime("%Y-%m-%d") }
36
+ }
37
+ end
38
+ ```
65
39
 
66
- **time_spans**: an `Array` of Minuteman compatible `TimeSpan`. Eg. `%w[year month
67
- day]` will only track events on that timespans. Ignoring the rest
40
+ ## Tracking
68
41
 
69
- **redis**: can be a Hash with the options to be sent to `Redis.new` or a `Redis`
70
- connection already established (`Redis::Namespace` works as well).
42
+ Tracking is the most basic scenario for Minuteman:
71
43
 
72
44
  ```ruby
73
- require "minuteman"
45
+ # This will create the "landing:new" event in all the defined patterns and since
46
+ # there is no user here it will create an annonymous one.
47
+ # This user only exists in the Minuteman context.
48
+ user = Minuteman.track("landing:new")
74
49
 
75
- # Accepts an options[:redis] hash that will be sent as is to Redis.new
76
- analytics = Minuteman.new
50
+ # The id it's an internal representation, not useful for you
51
+ user.id # => "1"
77
52
 
78
- # You can also reuse your Redis or Redis::Namespace connection
79
- analytics = Minuteman.new(redis: Redis::Namespace.new(:mm, redis: Redis.new))
53
+ # This is the unique id. With this you can have an identifier for the user
54
+ user.uid # => "787c8770-0ac2-4654-9fa4-e57d152fa341"
80
55
 
81
- # Mark an event for a given id
82
- analytics.track("login:successful", user.id)
83
- analytics.track("login:successful", other_user.id)
56
+ # You can use the `user` to keep tracking things:
57
+ user.track("register:page")
84
58
 
85
- # Mark in bulk
86
- analytics.track("programming:love:ruby", User.where(favorite: "ruby").pluck(:id))
59
+ # Or use it as an argument
60
+ Minuteman.track("help:page", user)
87
61
 
88
- # Fetch events for a given time (default is Time.now.utc)
89
- today_events = analytics.day("login:successful", Time.now.utc)
62
+ # Or track several users at once
63
+ Minuteman.track("help:page", [user1, user2, user3])
90
64
 
91
- # This also exists
92
- analytics.year("login:successful")
93
- analytics.month("login:successful")
94
- analytics.week("login:successful")
95
- analytics.day("login:successful")
96
- analytics.hour("login:successful")
97
- analytics.minute("login:successful")
98
-
99
- # Lists all the tracked events
100
- analytics.events
101
- #=> ["login:successful", "programming:login:ruby"]
65
+ # By default all the tracking and counting events are triggered with `Time.now.utc`
66
+ # but you can change that as well:
67
+ Minuteman.track("setup:account", user, Time.new(2010, 2, 10))
68
+ ```
102
69
 
103
- # Check event length on a given time
104
- today_events.length
105
- #=> 2
70
+ ## Analysis
106
71
 
107
- # Check for existance
108
- today_events.include?(user.id)
109
- #=> true
110
- today_events.include?(admin.id)
111
- #=> false
72
+ There is a powerful engine behind all the operations which is Redis + Lua <3
112
73
 
113
- # Bulk check
114
- today_events.include?(User.all.pluck(:id))
115
- #=> [true, true, false, false]
74
+ ```ruby
75
+ # The analysis of information relies on `Minuteman.patterns` and if you don't
76
+ # change it you'll get acess to `year`, `month`, `day`, `hour`, `minute`.
77
+ # To get information about `register:page` for today:
78
+ Minuteman.analyze("register:page").day
79
+
80
+ # You can always pass a `Time` instance to set the time you need information.
81
+ Minuteman.analyze("register:page").day(Time.new(2004, 2, 12))
82
+
83
+ # You also have a shorthand for analysis:
84
+ register_page_month = Minuteman("register:page").month
85
+
86
+ # And the power of Minuteman relies on the operations you can do with that.
87
+ # Counting the amount:
88
+ register_page_month.count # => 10
89
+
90
+ # Or knowing if a user is included in that set:
91
+ register_page_month.include?(User[42]) # => true
92
+
93
+ # But the most important part is the ability to do bit operations on that:
94
+ # You can intersect sets using bitwise AND(`&`), OR(`|`), NOT(`~`, `-`) and XOR(`^`).
95
+ # Also you can use plus(`+`) and minus(`-`) operations.
96
+ # In this example we'll get all the users that accessed our site via a promo
97
+ # invite but didn't buy anything
98
+ (
99
+ Minuteman("promo:email").day & Minuteman("promo:google").day
100
+ ) - Minuteman("buy:success").day
116
101
  ```
117
102
 
118
- ## Bitwise operations
103
+ ## Counting
119
104
 
120
- You can intersect sets using bitwise AND(`&`), OR(`|`), NOT(`~`, `-`) and XOR(`^`).
121
- Also you can use plus(`+`) and minus(`-`) operations.
105
+ Since Minuteman 2.0 there's the possibility to have counters.
122
106
 
123
107
  ```ruby
124
- set1 + set2
125
- set1 - set2
126
- set1 & set2
127
- set1 | set2
128
- set1 ^ set2
129
-
130
- ~set1 \
131
- |==> This are the same
132
- -set1 /
133
- ```
108
+ # Counting works in a very similar way to tracking but with some important
109
+ # differences. Trackings are idempotent unlike countings and they do not provide
110
+ # operations between sets... you can use plain ruby for that.
111
+ # This will add 1 to the `hits:page` counter:
112
+ Minuteman.add("hits:page")
134
113
 
135
- ### Intersecting with arrays
114
+ # You can also pass a `Time` instance to define when this tracking ocurred:
115
+ Minuteman.add("hits:page", Time.new(2012, 20, 01))
136
116
 
137
- Let's assume this scenario:
117
+ # And you can also send users to also count the times that given user did that
118
+ # event
119
+ Minuteman.add("hits:page", Time.new(2012, 20, 01), user)
138
120
 
139
- You have a list of users and want to know which of them have been going throught
140
- some of the tracks you made.
121
+ # You can access counting information similar to tracking:
122
+ Minuteman.count("hits:page").day.count # => 201
141
123
 
142
- ```ruby
143
- paid = analytics.month("buy:complete")
144
- payed_from_miami = paid & User.find_all_by_state("MIA").map(&:id)
145
- payed_from_miami.size
146
- #=> 43
147
- payed_users_from_miami = payed_from_miami.map { |id| User.find(id) }
124
+ # Or with a shorthand:
125
+ Counterman("hits:page").day.count # => 201
148
126
  ```
149
127
 
150
- Currently the supported commands to interact with arrays are `&` and `-`
128
+ ## Users
151
129
 
152
- ### Example
130
+ Minuteman 2.0 adds the concept of users which can be annonymous or have a
131
+ relation with your own database.
153
132
 
154
133
  ```ruby
155
- invited = analytics.month("email:invitation")
156
- successful_buys = analytics.month("buy:complete")
134
+ # This will create an annonymous user
135
+ user = Minuteman::User.create
157
136
 
158
- successful_buys_after_invitation = invited & successful_buys
159
- successful_buys_after_invitation.include?(user.id)
137
+ # Users are just a part of Minuteman and do not interfere with your own.
138
+ # They do have some properties like a unique identifier you can use to find it
139
+ # in the future
140
+ user.uid # => "787c8770-0ac2-4654-9fa4-e57d152fa341"
160
141
 
161
- # Clean up all the operations cache
162
- analytics.reset_operations_cache
163
- ```
142
+ # User lookup works like this:
143
+ # And you can use that unique identifier as a key in a cookie to see what your
144
+ # uses do when no one is looking
145
+ Minuteman::User['787c8770-0ac2-4654-9fa4-e57d152fa341']
164
146
 
165
- Also you can write more complex set operations
147
+ # But since the point is to be able to get tied to your data you can promote a
148
+ # user, from anonymous to "real"
149
+ user.promote(123)
166
150
 
167
- ```ruby
168
- invited = analytics.month("email:invitation")
169
- from_adsense = analytics.month("adsense:promo")
170
- successful_buys = analytics.month("buy:complete")
151
+ # Lookups also work with promoted ids
152
+ Minuteman::User["123"]
153
+
154
+ # Having a user you can do all the same operations minus the hussle.
155
+ # Like tracking:
156
+ user.track("user:login")
157
+
158
+ # or adding:
159
+ user.add("failed:login")
160
+
161
+ # or counting
162
+ user.count("failed:login").month.count # => 23
171
163
 
172
- conversion_rate = (invited | from_adsense) & successful_buys
164
+ # But also the counted events go to the big picture
165
+ Counterman("failed:login").month.count # => 512
173
166
  ```
data/Rakefile CHANGED
@@ -1,13 +1,13 @@
1
1
  require "rake/testtask"
2
2
 
3
- Rake::TestTask.new("spec") do |t|
3
+ Rake::TestTask.new("test") do |t|
4
+ t.libs << "test"
4
5
  t.pattern = "test/**/*_test.rb"
5
6
  end
6
7
 
7
8
  Rake::TestTask.new("bench") do |t|
8
- t.pattern = "test/bench/*_bench.rb"
9
+ t.pattern = "test/**/*_bench.rb"
9
10
  end
10
11
 
11
12
  task :default => [:test]
12
13
  task :all => [:test, :bench]
13
- task :test => [:spec]
data/SPEC.md ADDED
@@ -0,0 +1,21 @@
1
+ ```ruby
2
+ # Track an event
3
+ minuteman_user = Minuteman.track("login:successfull")
4
+ minuteman_user.promote(user.id)
5
+
6
+ # Trigger an event in the pipeline
7
+ Minuteman.trigger("event:name")
8
+
9
+ # Gets an event analyzer
10
+ analyzer = Minuteman.analyze("event:name")
11
+ # Counts unique users in that given time
12
+ analyze.day(Time.now.utc)
13
+
14
+ Minuteman("event:name").day | Minuteman("event2:name).day
15
+ ```
16
+
17
+ Caching:
18
+ Cache ids in events:
19
+
20
+ Minuteman::Operation:50:AND:20, Minuteman::Operation:50:OR:20
21
+ Minuteman::Operation:(50:AND:20):AND:14
@@ -1,151 +1,117 @@
1
- require "redis"
2
- require "time"
3
- require "forwardable"
4
- require "minuteman/time_events"
1
+ require 'redic'
5
2
 
6
- # Public: Minuteman core classs
7
- #
8
- class Minuteman
9
- extend Forwardable
3
+ module Minuteman
4
+ LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
5
+ LUA_OPERATIONS = File.expand_path("../minuteman/lua/operations.lua", __FILE__)
10
6
 
11
7
  class << self
12
- attr_accessor :redis, :options
13
-
14
- # Public: Prevents a fatal error if the options are set to silent
15
- #
16
- def safe(&block)
17
- yield if block
18
- rescue Redis::BaseError => e
19
- raise e unless options[:silent]
8
+ def config
9
+ @_configuration ||= Configuration.new
20
10
  end
21
- end
22
-
23
- PREFIX = "minuteman"
24
11
 
25
- def_delegators self, :redis, :redis=, :options, :options=, :safe
26
-
27
- # Public: Initializes Minuteman
28
- #
29
- # options - An options hash to change how Minuteman behaves
30
- #
31
- def initialize(options = {})
32
- redis_options = options.delete(:redis) || {}
12
+ def configure
13
+ yield(config)
14
+ end
33
15
 
34
- self.options = default_options.merge!(options)
35
- self.redis = define_connection(redis_options)
16
+ def prefix
17
+ config.prefix
18
+ end
36
19
 
37
- spans = self.options.fetch(:time_spans, %w[year month week day hour minute])
38
- @time_spans = generate_spans(spans)
39
- end
20
+ def patterns
21
+ config.patterns
22
+ end
40
23
 
41
- # Public: Marks an id to a given event on a given time
42
- #
43
- # event_name - The event name to be searched for
44
- # ids - The ids to be tracked
45
- #
46
- # Examples
47
- #
48
- # analytics = Minuteman.new
49
- # analytics.track("login", 1)
50
- # analytics.track("login", [2, 3, 4])
51
- #
52
- def track(event_name, ids, time = Time.now.utc)
53
- event_time = time.kind_of?(Time) ? time : Time.parse(time.to_s)
54
- time_events = TimeEvents.start(@time_spans, event_name, event_time)
55
-
56
- track_events(time_events, Array(ids))
57
- end
24
+ def time_spans
25
+ @_time_spans = patterns.keys
26
+ end
58
27
 
59
- # Public: List all the events given the minuteman namespace
60
- #
61
- def events
62
- keys = safe { redis.keys([PREFIX, "*", "????"].join("_")) }
63
- keys.map { |key| key.split("_")[1] }
64
- end
28
+ def track(action, users = nil, time = Time.now.utc)
29
+ users = Minuteman::User.create if users.nil?
65
30
 
66
- # Public: List all the operations executed in a given the minuteman namespace
67
- #
68
- def operations
69
- safe { redis.keys([operations_cache_key_prefix, "*"].join("_")) }
70
- end
31
+ Array(users).each do |user|
32
+ process do
33
+ time_spans.each do |time_span|
34
+ event = Minuteman::Event.find_or_create(
35
+ type: action,
36
+ time: patterns[time_span].call(time)
37
+ )
71
38
 
72
- # Public: Resets the bit operation cache keys
73
- #
74
- def reset_operations_cache
75
- keys = safe { redis.keys([operations_cache_key_prefix, "*"].join("_")) }
76
- safe { redis.del(keys) } if keys.any?
77
- end
39
+ event.setbit(user.id)
40
+ end
41
+ end
42
+ end
78
43
 
79
- # Public: Resets all the used keys
80
- #
81
- def reset_all
82
- keys = safe { redis.keys([PREFIX, "*"].join("_")) }
83
- safe { redis.del(keys) } if keys.any?
84
- end
44
+ users
45
+ end
85
46
 
86
- private
47
+ def add(action, time = Time.now.utc, users = [])
48
+ time_spans.each do |time_span|
49
+ process do
50
+ counter = Minuteman::Counter.create({
51
+ type: action,
52
+ time: patterns[time_span].call(time)
53
+ })
87
54
 
88
- # Public: Generates the methods to fech data
89
- #
90
- # spans: An array of timespans corresponding to a TimeSpan class
91
- #
92
- def generate_spans(spans)
93
- spans.map do |method_name|
94
- constructor = self.class.const_get(method_name.capitalize)
55
+ counter.incr
56
+ end
57
+ end
95
58
 
96
- define_singleton_method(method_name) do |*args|
97
- event_name, date = *args
98
- date ||= Time.now.utc
59
+ Array(users).each do |user|
60
+ time_spans.each do |time_span|
61
+ counter = Minuteman::Counter::User.create({
62
+ user_id: user.id,
63
+ type: action,
64
+ time: patterns[time_span].call(time)
65
+ })
99
66
 
100
- constructor.new(event_name, date)
67
+ counter.incr
68
+ end
101
69
  end
70
+ end
102
71
 
103
- constructor
72
+ def analyze(action)
73
+ analyzers_cache[action]
104
74
  end
105
- end
106
75
 
107
- # Private: Default configuration options
108
- #
109
- def default_options
110
- { cache: true, silent: false }
111
- end
76
+ def count(action)
77
+ counters_cache[action]
78
+ end
112
79
 
113
- # Private: Determines to use or instance a Redis connection
114
- #
115
- # object: Can be the options to instance a Redis connection or a connection
116
- # itself
117
- #
118
- def define_connection(object)
119
- case object
120
- when Redis, defined?(Redis::Namespace) && Redis::Namespace
121
- object
122
- else
123
- Redis.new(object)
80
+ private
81
+
82
+ def process(&block)
83
+ if !!config.parallel
84
+ Thread.current(&block)
85
+ else
86
+ block.call
87
+ end
124
88
  end
125
- end
126
89
 
127
- # Private: Marks ids for a given time events
128
- #
129
- # time_events: A set of TimeEvents
130
- # ids: The ids to be tracked
131
- #
132
- def track_events(time_events, ids)
133
- safe_multi do
134
- time_events.each do |event|
135
- ids.each { |id| safe { redis.setbit(event.key, id, 1) } }
90
+ def analyzers_cache
91
+ @_analyzers_cache ||= Hash.new do |h,k|
92
+ h[k] = Minuteman::Analyzer.new(k)
136
93
  end
137
94
  end
138
- end
139
95
 
140
- # Private: Executes a block within a safe connection using redis.multi
141
- #
142
- def safe_multi(&block)
143
- safe { redis.multi(&block) }
96
+ def counters_cache
97
+ @_counters_cache ||= Hash.new do |h,k|
98
+ h[k] = Minuteman::Analyzer.new(k, Minuteman::Counter)
99
+ end
100
+ end
144
101
  end
102
+ end
145
103
 
146
- # Private: The prefix key of all the operations
147
- #
148
- def operations_cache_key_prefix
149
- [ PREFIX, Minuteman::KeysMethods::BIT_OPERATION_PREFIX ].join("_")
150
- end
104
+ def Minuteman(action)
105
+ Minuteman.analyze(action)
151
106
  end
107
+
108
+ def Counterman(action)
109
+ Minuteman.count(action)
110
+ end
111
+
112
+ require 'minuteman/user'
113
+ require 'minuteman/event'
114
+ require 'minuteman/counter'
115
+ require 'minuteman/result'
116
+ require 'minuteman/analyzer'
117
+ require 'minuteman/configuration'