minuteman 1.0.3 → 2.0.0.pre

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 (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'