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'