lib/minuteman.rb in minuteman-1.0.3 vs lib/minuteman.rb in minuteman-2.0.0.pre
- old
+ new
@@ -1,151 +1,117 @@
-require "redis"
-require "time"
-require "forwardable"
-require "minuteman/time_events"
+require 'redic'
-# Public: Minuteman core classs
-#
-class Minuteman
- extend Forwardable
+module Minuteman
+ LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
+ LUA_OPERATIONS = File.expand_path("../minuteman/lua/operations.lua", __FILE__)
class << self
- attr_accessor :redis, :options
+ def config
+ @_configuration ||= Configuration.new
+ end
- # Public: Prevents a fatal error if the options are set to silent
- #
- def safe(&block)
- yield if block
- rescue Redis::BaseError => e
- raise e unless options[:silent]
+ def configure
+ yield(config)
end
- end
- PREFIX = "minuteman"
+ def prefix
+ config.prefix
+ end
- def_delegators self, :redis, :redis=, :options, :options=, :safe
+ def patterns
+ config.patterns
+ end
- # Public: Initializes Minuteman
- #
- # options - An options hash to change how Minuteman behaves
- #
- def initialize(options = {})
- redis_options = options.delete(:redis) || {}
+ def time_spans
+ @_time_spans = patterns.keys
+ end
- self.options = default_options.merge!(options)
- self.redis = define_connection(redis_options)
+ def track(action, users = nil, time = Time.now.utc)
+ users = Minuteman::User.create if users.nil?
- spans = self.options.fetch(:time_spans, %w[year month week day hour minute])
- @time_spans = generate_spans(spans)
- end
+ Array(users).each do |user|
+ process do
+ time_spans.each do |time_span|
+ event = Minuteman::Event.find_or_create(
+ type: action,
+ time: patterns[time_span].call(time)
+ )
- # Public: Marks an id to a given event on a given time
- #
- # event_name - The event name to be searched for
- # ids - The ids to be tracked
- #
- # Examples
- #
- # analytics = Minuteman.new
- # analytics.track("login", 1)
- # analytics.track("login", [2, 3, 4])
- #
- def track(event_name, ids, time = Time.now.utc)
- event_time = time.kind_of?(Time) ? time : Time.parse(time.to_s)
- time_events = TimeEvents.start(@time_spans, event_name, event_time)
+ event.setbit(user.id)
+ end
+ end
+ end
- track_events(time_events, Array(ids))
- end
+ users
+ end
- # Public: List all the events given the minuteman namespace
- #
- def events
- keys = safe { redis.keys([PREFIX, "*", "????"].join("_")) }
- keys.map { |key| key.split("_")[1] }
- end
+ def add(action, time = Time.now.utc, users = [])
+ time_spans.each do |time_span|
+ process do
+ counter = Minuteman::Counter.create({
+ type: action,
+ time: patterns[time_span].call(time)
+ })
- # Public: List all the operations executed in a given the minuteman namespace
- #
- def operations
- safe { redis.keys([operations_cache_key_prefix, "*"].join("_")) }
- end
+ counter.incr
+ end
+ end
- # Public: Resets the bit operation cache keys
- #
- def reset_operations_cache
- keys = safe { redis.keys([operations_cache_key_prefix, "*"].join("_")) }
- safe { redis.del(keys) } if keys.any?
- end
+ Array(users).each do |user|
+ time_spans.each do |time_span|
+ counter = Minuteman::Counter::User.create({
+ user_id: user.id,
+ type: action,
+ time: patterns[time_span].call(time)
+ })
- # Public: Resets all the used keys
- #
- def reset_all
- keys = safe { redis.keys([PREFIX, "*"].join("_")) }
- safe { redis.del(keys) } if keys.any?
- end
+ counter.incr
+ end
+ end
+ end
- private
+ def analyze(action)
+ analyzers_cache[action]
+ end
- # Public: Generates the methods to fech data
- #
- # spans: An array of timespans corresponding to a TimeSpan class
- #
- def generate_spans(spans)
- spans.map do |method_name|
- constructor = self.class.const_get(method_name.capitalize)
+ def count(action)
+ counters_cache[action]
+ end
- define_singleton_method(method_name) do |*args|
- event_name, date = *args
- date ||= Time.now.utc
+ private
- constructor.new(event_name, date)
+ def process(&block)
+ if !!config.parallel
+ Thread.current(&block)
+ else
+ block.call
end
-
- constructor
end
- end
- # Private: Default configuration options
- #
- def default_options
- { cache: true, silent: false }
- end
-
- # Private: Determines to use or instance a Redis connection
- #
- # object: Can be the options to instance a Redis connection or a connection
- # itself
- #
- def define_connection(object)
- case object
- when Redis, defined?(Redis::Namespace) && Redis::Namespace
- object
- else
- Redis.new(object)
+ def analyzers_cache
+ @_analyzers_cache ||= Hash.new do |h,k|
+ h[k] = Minuteman::Analyzer.new(k)
+ end
end
- end
- # Private: Marks ids for a given time events
- #
- # time_events: A set of TimeEvents
- # ids: The ids to be tracked
- #
- def track_events(time_events, ids)
- safe_multi do
- time_events.each do |event|
- ids.each { |id| safe { redis.setbit(event.key, id, 1) } }
+ def counters_cache
+ @_counters_cache ||= Hash.new do |h,k|
+ h[k] = Minuteman::Analyzer.new(k, Minuteman::Counter)
end
end
end
+end
- # Private: Executes a block within a safe connection using redis.multi
- #
- def safe_multi(&block)
- safe { redis.multi(&block) }
- end
+def Minuteman(action)
+ Minuteman.analyze(action)
+end
- # Private: The prefix key of all the operations
- #
- def operations_cache_key_prefix
- [ PREFIX, Minuteman::KeysMethods::BIT_OPERATION_PREFIX ].join("_")
- end
+def Counterman(action)
+ Minuteman.count(action)
end
+
+require 'minuteman/user'
+require 'minuteman/event'
+require 'minuteman/counter'
+require 'minuteman/result'
+require 'minuteman/analyzer'
+require 'minuteman/configuration'