timed-rediscounter 1.0.0 → 1.0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abc6230c879819d52482f8d11b8a7a88b8b5f4a9
4
- data.tar.gz: e9b4a4336ba02e1062f6ababd6f1fe1760a0a8bb
3
+ metadata.gz: 4a7b99e435001e68df58db161216416c209fb6dd
4
+ data.tar.gz: 5abc20bda6f7363fe184041e60c7a2d0015d2ac3
5
5
  SHA512:
6
- metadata.gz: 777ccd32facd6d3028b8355c6d3011a3fbbed8dd541f5254ecdea9f1c37c28aa57da72fc3ff2a0b1100a2a62b215f0aecc14250054dbd6efbb1ee81777a6a07f
7
- data.tar.gz: b0c354cd2aa008f081caa57e327c42e2e7ab0a6594794ebe14ffe75ab2b1344159fbd72817bc55474c04f96a5f93ce520125a9d1d22cca062235efc13d6044e8
6
+ metadata.gz: 9dbd7645ed21eef5fbe2c7c6041fc7e74562e1094afac61e973f88150310ac560678373be955007a800f7f55624157d362fb0b2cfb23ae6b7352de58be23a328
7
+ data.tar.gz: a9b9f7228ea7270461a11d12ba95b17c40f23bdb5ce05a9c161bb1ba0347c5f72f1438b8600972869c8b0bfc66c76a02a2c9f3e7aaa80096af53d08e72a83787
@@ -7,13 +7,15 @@ require 'active_support/core_ext/hash'
7
7
  require "redis"
8
8
 
9
9
  require "timed/rediscounter/version"
10
- require "timed/rediscounter/counter"
10
+
11
11
 
12
12
 
13
13
 
14
14
  module Timed
15
15
  module Rediscounter
16
- extend ActiveSupport::Concern
16
+ def self.included(mod)
17
+ mod.extend(ClassMethods)
18
+ end
17
19
 
18
20
  def self.redis=(r)
19
21
  @redis = r if r.is_a?(Redis)
@@ -64,5 +66,173 @@ module Timed
64
66
  end
65
67
 
66
68
 
69
+ class Counter
70
+
71
+ Periods = [:minute, :hour, :day, :month, :year].freeze
72
+
73
+ attr_reader :periods,:key
74
+ def initialize(key,default_options={})
75
+ @key = key
76
+ @periods = (default_options.delete(:periods) || Periods)
77
+ @redis = (default_options.delete(:redis) || Timed::Rediscounter.redis)
78
+ raise_if_not_valid_periods(@periods)
79
+ @default_options = default_options.to_h
80
+ end
81
+
82
+ # Increments all given period keys by a given offset
83
+ # offset is normally 1
84
+ #
85
+ def incr(options={})
86
+ opt = @default_options.merge(options).with_indifferent_access
87
+ offset = opt.fetch(:offset,1).to_i
88
+ time = opt.fetch(:time,Time.current)
89
+ periods = (opt[:periods] || @periods)
90
+ raise_if_not_valid_periods(periods)
91
+
92
+ if offset > 0
93
+ return redis.multi do
94
+ periods.each do |period|
95
+ redis.hincrby( period_key(period), convert_time_to_period_hash_key(time,period), offset)
96
+ end
97
+ end
98
+ end
99
+
100
+ return []
101
+ end
102
+
103
+ # Returns a Hash by a given range or a period
104
+ #
105
+ # example:
106
+ # history(1.hour.ago..Time.now) or history(1.hour.ago)
107
+ #
108
+ #
109
+ # result:
110
+ # {2017-09-22 15:00:00 +0200=>0, 2017-09-22 16:00:00 +0200=>0}
111
+ #
112
+ # optional Parameter period:
113
+ # [:minute, :hour, :day, :month, :year]
114
+ def history(range_arg,period=nil)
115
+ redis_key, hash_keys = build_redishash_arguments(range_arg,period)
116
+ return Hash.new if hash_keys.empty?
117
+
118
+ redis.mapped_hmget(redis_key, *hash_keys).inject({}) do |h,(k,v)|
119
+ h[Time.at(k)] = v.to_i
120
+ h
121
+ end
122
+ end
123
+
124
+ def sum(range_arg,period=nil)
125
+ redis_key, hash_keys = build_redishash_arguments(range_arg,period)
126
+ return 0 if hash_keys.empty?
127
+ redis.hmget(redis_key, *hash_keys).inject(0){|sum,i| sum += i.to_i}
128
+ end
129
+
130
+ #Expiring all period Keys
131
+ #
132
+ #expire_in in seconds
133
+ def expire_keys(expire_in=nil)
134
+ expire_in ||= @default_options.fetch(:expire_in, 1.year).to_i
135
+ redis.multi do
136
+ Periods.each { |period| redis.expire period_key(period), expire_in }
137
+ end
138
+ end
139
+
140
+ #deleting all period keys
141
+ def delete_keys
142
+ redis.multi do
143
+ Periods.each { |period| redis.del period_key(period) }
144
+ end
145
+ end
146
+
147
+ #helper to access redis
148
+ def redis
149
+ @redis
150
+ end
151
+
152
+ private
153
+
154
+ #builds the
155
+ def build_redishash_arguments(range_arg,period=nil)
156
+ case range_arg
157
+ when Time,Date
158
+ range = (range_arg..Time.current)
159
+ when String
160
+ range = (Time.parse(range_arg)..Time.current)
161
+ when Range
162
+ range = range_arg
163
+ else
164
+ ArgumentError.new
165
+ end
166
+ period ||= period_by_range(range)
167
+ raise_if_not_valid_periods(period)
168
+
169
+ off_set = 1.send(period)
170
+ hash_keys = Set.new
171
+
172
+ start_time = range.first.send("beginning_of_#{period}")
173
+ end_time = range.last.send("beginning_of_#{period}")
174
+
175
+ hash_keys << start_time
176
+ while (end_time - start_time) >= off_set
177
+ start_time += off_set
178
+ hash_keys << start_time
179
+ end
180
+
181
+ return period_key(period), hash_keys.collect(&:to_i)
182
+ end
183
+
184
+ Steps = [1.hour, 1.day, 1.month, 1.year, 2.year].freeze
185
+ # Calculate a a valid period by a given range
186
+ def period_by_range(range)
187
+ diff = (range.last - range.first).round
188
+ period = nil
189
+ Steps.each_with_index do |step,i|
190
+ if diff <= step
191
+ period = @periods[i]
192
+ break
193
+ end
194
+ end
195
+ #if not found => fallback
196
+ period ||= ( @periods[Steps.length] || @periods.last )
197
+ end
198
+
199
+ def raise_if_not_valid_periods(a)
200
+ r = case a
201
+ when Array
202
+ return !a.any?{|it| !Periods.include?(it.to_sym)}
203
+ when Symbol,String
204
+ return Periods.include?(a.to_sym)
205
+ else
206
+ false
207
+ end
208
+ raise ArgumentError.new("Not valid periods: #{a} Must contain one or more of #{Periods}") unless r
209
+ end
210
+
211
+
212
+ def period_key(period)
213
+ "#{self.class.name}::#{@key}::#{period}"
214
+ end
215
+
216
+ def convert_time_to_period_hash_key(time,period)
217
+ case time
218
+ when Time
219
+ t = time
220
+ when Date
221
+ t = time.to_time
222
+ when String
223
+ t = Time.parse(time)
224
+ when Fixnum,Float
225
+ t = Time.at(time)
226
+ else
227
+ raise ArgumentError.new("Not valid Time")
228
+ end
229
+ t.send("beginning_of_#{period}").to_i
230
+ end
231
+
232
+
233
+
234
+ end
235
+
236
+
67
237
  end
68
238
  end
@@ -1,5 +1,5 @@
1
1
  module Timed
2
2
  module Rediscounter
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.6"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timed-rediscounter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Geduhn