throttling 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 466a505eb343b4cd8c1a37f125064bebe09ded2c6a586f1cb191a29d0b786732
4
+ data.tar.gz: 58db8ff3fd65eeec71b4f767e629780719e2b9e0e99b944dbdacb3a6653d0527
5
+ SHA512:
6
+ metadata.gz: ff7d8ec51b2a910a44455a6267859f0310adbb57b55ac0ac8239ed3ea99ebe9cfe7102191cf6c78b11f8bd82e724ab1998f1cc7d554318ce2402bbe22a46d8b4
7
+ data.tar.gz: cecbbd774a4f80f98c976f0dd8151900004532ba3cfb25ae945816f589282e3fbaa0045edb3cbe4b1e3732a990dcd60706cb184aab88d48d9ffe1fdc98e13359
checksums.yaml.gz.sig ADDED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,30 +1,37 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0 (July 6, 2023)
4
+
5
+ - Bump minimum Ruby requirement to 2.7.0
6
+ - Updated codebase to match StandardRB style guide
7
+
1
8
  ## 0.3.1 (April 13, 2012)
2
9
 
3
10
  Features:
4
11
 
5
- - When limit is omitted, no limits will be enforced (`check` always returns true)
12
+ - When limit is omitted, no limits will be enforced (`check` always returns true)
6
13
 
7
14
  Bugfixes:
8
15
 
9
- - Fixed bug when action was allowed `limit + 1` times
10
- - When limit is 0, `check` should always return `false`
16
+ - Fixed bug when action was allowed `limit + 1` times
17
+ - When limit is 0, `check` should always return `false`
11
18
 
12
19
  ## 0.3.0 (April 13, 2012)
13
20
 
14
21
  Features:
15
22
 
16
- - Added ability to retrieve custom value based on number of actions performed in a period of time
23
+ - Added ability to retrieve custom value based on number of actions performed in a period of time
17
24
 
18
25
  ## 0.2.0 (April 12, 2012)
19
26
 
20
27
  Bugfixes:
21
28
 
22
- - Fixed bug when occurrences where increased for larger periods, when smaller ones did not pass
29
+ - Fixed bug when occurrences where increased for larger periods, when smaller ones did not pass
23
30
 
24
31
  ## 0.1.0 (April 12, 2012)
25
32
 
26
33
  Features:
27
34
 
28
- - Allows to throttle actions occurred in period of time
29
- - Allows to specify limits inline or in external configuration file
30
- - 100% test coverage
35
+ - Allows to throttle actions occurred in period of time
36
+ - Allows to specify limits inline or in external configuration file
37
+ - 100% test coverage
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in throttling.gemspec
4
4
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,80 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ throttling (0.4.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ diff-lcs (1.5.0)
11
+ json (2.6.3)
12
+ language_server-protocol (3.17.0.3)
13
+ lint_roller (1.0.0)
14
+ parallel (1.23.0)
15
+ parser (3.2.2.3)
16
+ ast (~> 2.4.1)
17
+ racc
18
+ racc (1.7.1)
19
+ rainbow (3.1.1)
20
+ rake (13.0.6)
21
+ regexp_parser (2.8.1)
22
+ rexml (3.2.5)
23
+ rspec (3.12.0)
24
+ rspec-core (~> 3.12.0)
25
+ rspec-expectations (~> 3.12.0)
26
+ rspec-mocks (~> 3.12.0)
27
+ rspec-core (3.12.2)
28
+ rspec-support (~> 3.12.0)
29
+ rspec-expectations (3.12.3)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.12.0)
32
+ rspec-mocks (3.12.5)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.12.0)
35
+ rspec-support (3.12.1)
36
+ rubocop (1.52.1)
37
+ json (~> 2.3)
38
+ parallel (~> 1.10)
39
+ parser (>= 3.2.2.3)
40
+ rainbow (>= 2.2.2, < 4.0)
41
+ regexp_parser (>= 1.8, < 3.0)
42
+ rexml (>= 3.2.5, < 4.0)
43
+ rubocop-ast (>= 1.28.0, < 2.0)
44
+ ruby-progressbar (~> 1.7)
45
+ unicode-display_width (>= 2.4.0, < 3.0)
46
+ rubocop-ast (1.29.0)
47
+ parser (>= 3.2.1.0)
48
+ rubocop-performance (1.18.0)
49
+ rubocop (>= 1.7.0, < 2.0)
50
+ rubocop-ast (>= 0.4.0)
51
+ ruby-progressbar (1.13.0)
52
+ standard (1.29.0)
53
+ language_server-protocol (~> 3.17.0.2)
54
+ lint_roller (~> 1.0)
55
+ rubocop (~> 1.52.0)
56
+ standard-custom (~> 1.0.0)
57
+ standard-performance (~> 1.1.0)
58
+ standard-custom (1.0.1)
59
+ lint_roller (~> 1.0)
60
+ standard-performance (1.1.0)
61
+ lint_roller (~> 1.0)
62
+ rubocop-performance (~> 1.18.0)
63
+ timecop (0.9.6)
64
+ unicode-display_width (2.4.2)
65
+
66
+ PLATFORMS
67
+ arm64-darwin
68
+ arm64-linux
69
+ x86_64-darwin
70
+ x86_64-linux
71
+
72
+ DEPENDENCIES
73
+ rake (~> 13.0)
74
+ rspec (~> 3.12.0)
75
+ standard (~> 1.29.0)
76
+ throttling!
77
+ timecop (~> 0.9.6)
78
+
79
+ BUNDLED WITH
80
+ 2.3.26
data/README.md CHANGED
@@ -1,74 +1,79 @@
1
1
  # Throttling
2
2
 
3
- [![Travis-CI build status](https://secure.travis-ci.org/kpumuk/throttling.png)](http://travis-ci.org/kpumuk/throttling)
3
+ [![Tests](https://github.com/kpumuk/throttling/actions/workflows/tests.yml/badge.svg)](https://github.com/kpumuk/throttling/actions/workflows/tests.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/throttling.svg)](https://badge.fury.io/rb/throttling)
5
+ [![Gem Downloads](https://img.shields.io/gem/dt/throttling.svg)](https://badge.fury.io/rb/throttling)
6
+ [![Changelog](https://img.shields.io/badge/Changelog-latest-blue.svg)](https://github.com/kpumuk/throttling/blob/main/CHANGELOG.md)
4
7
 
5
8
  Throttling gem provides basic, but very powerful way to throttle various user actions in your application. Basically you can specify how many times some action could be performed over a specified period(s) of time.
6
9
 
7
10
  ## Installation
8
11
 
9
- Add this line to your application's Gemfile:
12
+ Add this line to your application's `Gemfile`:
10
13
 
11
- gem 'throttling'
14
+ ```ruby
15
+ gem "throttling"
16
+ ```
12
17
 
13
- And then execute:
14
-
15
- $ bundle
16
-
17
- Or install it yourself as:
18
-
19
- $ gem install throttling
18
+ And run `bundle install` command.
20
19
 
21
20
  ## Configuration
22
21
 
23
- You can configure Throttling parameters by accessing attributes of `Throttling` module. Currently it supports only Memcached through `Rails.cache`.
22
+ You can configure Throttling parameters by accessing attributes of `Throttling` module. Currently it supports only Memcached and Redis through `Rails.cache`.
24
23
 
25
- Throttling.storage = Rails.cache
26
- Throttling.logger = Rails.logger
24
+ ```ruby
25
+ Throttling.storage = Rails.cache
26
+ Throttling.logger = Rails.logger
27
+ ```
27
28
 
28
29
  Throttling limits could be stored in a configuration file in `config/throttling.yml`. You can also specify another file to read limits from:
29
30
 
30
- Throttling.limits_config = "#{Rails.root}/config/throttling.yml"
31
+ ```ruby
32
+ Throttling.limits_config = "#{Rails.root}/config/throttling.yml"
33
+ ```
31
34
 
32
35
  The basic structure of the file is:
33
36
 
34
- user_signup:
35
- limit: 20
36
- period: 3600
37
-
38
- search_requests:
39
- minutely:
40
- limit: 300
41
- period: 600
42
- hourly:
43
- limit: 1000
44
- period: 3600
45
- daily:
46
- limit: 10000
47
- period: 86400
48
-
49
- request_priority:
50
- period: 86400
51
- default_value: 25
52
- values:
53
- high_priority:
54
- limit: 5
55
- value: 10
56
- medium_priority:
57
- limit: 15
58
- value: 15
59
- low_priority:
60
- limit: 100
61
- value: 20
37
+ ```yaml
38
+ user_signup:
39
+ limit: 20
40
+ period: 3600
41
+
42
+ search_requests:
43
+ minutely:
44
+ limit: 300
45
+ period: 600
46
+ hourly:
47
+ limit: 1000
48
+ period: 3600
49
+ daily:
50
+ limit: 10000
51
+ period: 86400
52
+
53
+ request_priority:
54
+ period: 86400
55
+ default_value: 25
56
+ values:
57
+ high_priority:
58
+ limit: 5
59
+ value: 10
60
+ medium_priority:
61
+ limit: 15
62
+ value: 15
63
+ low_priority:
64
+ limit: 100
65
+ value: 20
66
+ ```
62
67
 
63
68
  This example covers three different scenarios:
64
69
 
65
- 1. Single period. In this case only 20 actions will be allowed in a period of
70
+ 1. **Single period**. In this case only 20 actions will be allowed in a period of
66
71
  one hour (3600 seconds).
67
72
 
68
- 2. Multiple periods. Action will be allowed to perform 300 times in 10 minutes,
73
+ 2. **Multiple periods**. Action will be allowed to perform 300 times in 10 minutes,
69
74
  1000 times an hour, and 10000 times a day.
70
75
 
71
- 3. This special case covers following scenario: based on the number of actions,
76
+ 3. **Complex scenario**. This special case covers following scenario: based on the number of actions,
72
77
  it returns a value, or default value when largest limit is reached. In this
73
78
  case it will return 10, when there were 5 or less requests (including current one),
74
79
  15 for up to 15 requests, 20 for up to 100 requests, and 25 when there were
@@ -76,110 +81,132 @@ This example covers three different scenarios:
76
81
 
77
82
  You can also specify limits as a Hash:
78
83
 
79
- Throttling.limits = {
80
- :user_signup => {
81
- :limit => 20,
82
- :period => 3600
83
- },
84
- :search_requests => {
85
- :minutely => {
86
- :limit => 20,
87
- :period => 3600
88
- },
89
- :hourly => {
90
- :limit => 1000,
91
- :period => 3600
92
- },
93
- :daily =>
94
- :limit => 10000,
95
- :period => 86400
96
- }
97
- }
84
+ ```ruby
85
+ Throttling.limits = {
86
+ user_signup: {
87
+ limit: 20,
88
+ period: 3600
89
+ },
90
+ search_requests: {
91
+ minutely: {
92
+ limit: 20,
93
+ period: 3600
94
+ },
95
+ hourly: {
96
+ limit: 1000,
97
+ period: 3600
98
+ },
99
+ daily: {
100
+ limit: 10000,
101
+ period: 86400
98
102
  }
103
+ }
104
+ }
105
+ ```
99
106
 
100
107
  You can completely disable throttling by setting `enabled` to `false`:
101
108
 
102
- Throttling.enabled = false
109
+ ```ruby
110
+ Throttling.enabled = false
111
+ ```
103
112
 
104
113
  ## Usage
105
114
 
106
115
  The basic usage of Throttling gem is following:
107
116
 
108
- Throttling.for(:user_signup).check(:user_id, current_user.id) do
109
- # Do your stuff here
110
- end
117
+ ```ruby
118
+ Throttling.for(:user_signup).check(:user_id, current_user.id) do
119
+ # Do your stuff here
120
+ end
111
121
 
112
- if Throttling.for(:user_signup).check(:user_id, current_user.id)
113
- # Action allowed
114
- else
115
- # Action denied
116
- end
122
+ if Throttling.for(:user_signup).check(:user_id, current_user.id)
123
+ # Action allowed
124
+ else
125
+ # Action denied
126
+ end
127
+ ```
117
128
 
118
129
  For convenience, there are some simplified methods:
119
130
 
120
- Throttling.for(:user_signup).check_ip(request.remote_ip)
121
- Throttling.for(:user_signup).check_user_id(current_user.id)
131
+ ```ruby
132
+ Throttling.for(:user_signup).check_ip(request.remote_ip)
133
+ Throttling.for(:user_signup).check_user_id(current_user.id)
134
+ ```
122
135
 
123
136
  You can add more helpers like this:
124
137
 
125
- Throttling::Base.class_eval do
126
- def check_user_id_and_document_id(user_id, doc_id)
127
- check("user_id:doc_id", "#{user_id}:#{doc_id}")
128
- end
129
- end
138
+ ```ruby
139
+ Throttling::Base.class_eval do
140
+ def check_user_id_and_document_id(user_id, doc_id)
141
+ check("user_id:doc_id", "#{user_id}:#{doc_id}")
142
+ end
143
+ end
144
+ ```
130
145
 
131
146
  ## Use cases
132
147
 
133
148
  ### Limiting number of sign-ups
134
149
 
135
- user_signup:
136
- limit: 20
137
- period: 3600
150
+ ```yaml
151
+ user_signup:
152
+ limit: 20
153
+ period: 3600
154
+ ```
138
155
 
139
156
  Limit the number of sign-ups to 20 per hour per IP address:
140
157
 
141
- Throttling.for('user_signup').check_ip(request.remote_ip)
158
+ ```ruby
159
+ Throttling.for("user_signup").check_ip(request.remote_ip)
160
+ ```
142
161
 
143
162
  ### Limiting number of document uploads
144
163
 
145
- document_uploads:
146
- minutely:
147
- limit: 5
148
- period: 600
149
- hourly:
150
- limit: 10
151
- period: 3600
152
- daily:
153
- limit: 50
154
- period: 86400
164
+ ```yaml
165
+ document_uploads:
166
+ minutely:
167
+ limit: 5
168
+ period: 600
169
+ hourly:
170
+ limit: 10
171
+ period: 3600
172
+ daily:
173
+ limit: 50
174
+ period: 86400
175
+ ```
155
176
 
156
177
  In this case user will be allowed to upload 5 documents in 10 minutes, 10 documents
157
178
  in an hour, or 50 documents a day:
158
179
 
159
- Throttling.for('document_uploads').check_user_id(current_user.id)
180
+ ```ruby
181
+ Throttling.for("document_uploads").check_user_id(current_user.id)
182
+ ```
160
183
 
161
184
  ### Prioritizing uploads based on number of uploads
162
185
 
163
- document_priorities:
164
- period: 86400
165
- default_value: 25
166
- values:
167
- high_priority:
168
- limit: 5
169
- value: 10
170
- medium_priority:
171
- limit: 15
172
- value: 15
173
- low_priority:
174
- limit: 100
175
- value: 20
186
+ ```yaml
187
+ document_priorities:
188
+ period: 86400
189
+ default_value: 25
190
+ values:
191
+ high_priority:
192
+ limit: 5
193
+ value: 10
194
+ medium_priority:
195
+ limit: 15
196
+ value: 15
197
+ low_priority:
198
+ limit: 100
199
+ value: 20
200
+ ```
176
201
 
177
202
  All documents could be prioritized based on the number of uploads: if user uploads
178
203
  less than 5 documents a day, they all will have priority 10. Next 10 documents
179
204
  (first five keep their original priority) will receive priority 15. Documents
180
205
  16 to 100 will get priority 20, and everything else will get priority 25.
181
206
 
182
- Throttling.for('document_priorities').check_user_id(current_user.id)
207
+ ```ruby
208
+ Throttling.for("document_priorities").check_user_id(current_user.id)
209
+ ```
183
210
 
184
211
  ## Contributing
185
212
 
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env rake
2
2
  require "bundler/gem_tasks"
3
3
 
4
- require 'rspec/core/rake_task'
4
+ require "rspec/core/rake_task"
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
- task :test => :spec
8
- task :default => :spec
7
+ task test: :spec
8
+ task default: :spec
@@ -15,7 +15,7 @@ module Throttling
15
15
  if @limits[:values]
16
16
  @limits[:values] = @limits[:values].sort_by { |name, params| params && params[:limit] }
17
17
  end
18
- @limits = [[ 'global', @limits ]]
18
+ @limits = [["global", @limits]]
19
19
  else
20
20
  @limits = @limits.sort_by { |name, params| params && params[:period] }
21
21
  end
@@ -35,7 +35,7 @@ module Throttling
35
35
 
36
36
  limits.each do |period_name, params|
37
37
  period = params[:period].to_i
38
- limit = params[:limit].nil? ? nil : params[:limit].to_i
38
+ limit = params[:limit]&.to_i
39
39
  values = params[:values]
40
40
 
41
41
  raise ArgumentError, "Invalid or no 'period' parameter in the limits[#{action}][#{period_name}] config: #{limit.inspect}" if period < 1
@@ -44,7 +44,7 @@ module Throttling
44
44
  key = hits_store_key(check_type, check_value, period_name, period)
45
45
 
46
46
  # Retrieve current value
47
- hits = Throttling.storage.fetch(key, :expires_in => hits_store_ttl(period), :raw => true) { '0' }.to_i
47
+ hits = Throttling.storage.fetch(key, expires_in: hits_store_ttl(period), raw: true) { "0" }.to_i
48
48
 
49
49
  if values
50
50
  value = params[:default_value] || false
@@ -54,16 +54,16 @@ module Throttling
54
54
  break
55
55
  end
56
56
  end
57
- else
57
+ elsif !limit.nil? && hits >= limit
58
58
  # Over limit?
59
- return false if !limit.nil? && hits >= limit
59
+ return false
60
60
  end
61
61
 
62
62
  Throttling.storage.increment(key) if auto_increment
63
63
  return value if values
64
64
  end
65
65
 
66
- return true
66
+ true
67
67
  end
68
68
 
69
69
  private
@@ -84,7 +84,7 @@ module Throttling
84
84
  # hash.values_at("a", "b") # => ["x", "y"]
85
85
  #
86
86
  def values_at(*indices)
87
- indices.collect {|key| self[convert_key(key)]}
87
+ indices.collect { |key| self[convert_key(key)] }
88
88
  end
89
89
 
90
90
  # Returns an exact copy of the hash.
@@ -95,7 +95,7 @@ module Throttling
95
95
  # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
96
96
  # Does not overwrite the existing hash.
97
97
  def merge(hash)
98
- self.dup.update(hash)
98
+ dup.update(hash)
99
99
  end
100
100
 
101
101
  # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
@@ -109,9 +109,17 @@ module Throttling
109
109
  super(convert_key(key))
110
110
  end
111
111
 
112
- def stringify_keys!; self end
113
- def symbolize_keys!; self end
114
- def to_options!; self end
112
+ def stringify_keys!
113
+ self
114
+ end
115
+
116
+ def symbolize_keys!
117
+ self
118
+ end
119
+
120
+ def to_options!
121
+ self
122
+ end
115
123
 
116
124
  # Convert to a Hash with String keys.
117
125
  def to_hash
@@ -119,31 +127,32 @@ module Throttling
119
127
  end
120
128
 
121
129
  protected
122
- def convert_key(key)
123
- key.kind_of?(Symbol) ? key.to_s : key
124
- end
125
130
 
126
- def convert_value(value)
127
- case value
128
- when Hash
129
- value.with_indifferent_access
130
- when Array
131
- value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
132
- else
133
- value
134
- end
131
+ def convert_key(key)
132
+ key.is_a?(Symbol) ? key.to_s : key
133
+ end
134
+
135
+ def convert_value(value)
136
+ case value
137
+ when Hash
138
+ value.with_indifferent_access
139
+ when Array
140
+ value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
141
+ else
142
+ value
135
143
  end
144
+ end
136
145
  end
137
146
 
138
- module HashIndifferentAccess #:nodoc:
147
+ module HashIndifferentAccess # :nodoc:
139
148
  def with_indifferent_access
140
149
  hash = HashWithIndifferentAccess.new(self)
141
- hash.default = self.default
150
+ hash.default = default
142
151
  hash
143
152
  end
144
153
  end
145
154
 
146
- class ::Hash #:nodoc:
155
+ class ::Hash # :nodoc:
147
156
  unless respond_to?(:with_indifferent_access)
148
157
  include Throttling::HashIndifferentAccess
149
158
  end
@@ -1,3 +1,3 @@
1
1
  module Throttling
2
- VERSION = '0.3.1'
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/throttling.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'logger'
2
- require 'yaml'
1
+ require "logger"
2
+ require "yaml"
3
3
 
4
4
  # Simple throttling library to limit number of actions in time.
5
5
  module Throttling
@@ -8,7 +8,7 @@ module Throttling
8
8
  # (if it is a Rails application).
9
9
  def storage
10
10
  @@storage ||= (defined?(Rails) && Rails.respond_to?(:cache) && Rails.cache) || nil
11
- raise ArgumentError, 'Throttling.storage is not specified' unless @@storage
11
+ raise ArgumentError, "Throttling.storage is not specified" unless @@storage
12
12
  @@storage
13
13
  end
14
14
 
@@ -25,7 +25,7 @@ module Throttling
25
25
 
26
26
  # Gets the logger used to output errors or warnings.
27
27
  def logger
28
- @@logger ||= (defined?(Rails) && Rails.respond_to(:logger) && Rails.logger) || Logger.new(STDOUT)
28
+ @@logger ||= (defined?(Rails) && Rails.respond_to(:logger) && Rails.logger) || Logger.new($stdout)
29
29
  end
30
30
 
31
31
  # Sets the logger used to output errors or warnings.
@@ -52,14 +52,14 @@ module Throttling
52
52
 
53
53
  # Sets current throttling limits.
54
54
  def limits=(limits)
55
- @@limits = limits && limits.with_indifferent_access
55
+ @@limits = limits&.with_indifferent_access
56
56
  end
57
57
 
58
58
  # Get the value indicating whether throttling is enabled.
59
59
  def enabled?
60
60
  !!@@enabled
61
61
  end
62
- alias :enabled :enabled?
62
+ alias_method :enabled, :enabled?
63
63
 
64
64
  # Sets the value indicating whether throttling is enabled.
65
65
  def enabled=(enabled)
@@ -83,20 +83,20 @@ module Throttling
83
83
 
84
84
  # Resets all values to their default state (mostly for testing purpose).
85
85
  def reset_defaults!
86
- @@enabled = true
87
- @@logger = nil
88
- @@storage = nil
86
+ @@enabled = true
87
+ @@logger = nil
88
+ @@storage = nil
89
89
  @@limits_config = nil
90
90
 
91
91
  # Internal variables
92
- @@instances = {}
93
- @@config = nil
92
+ @@instances = {}
93
+ @@config = nil
94
94
  end
95
95
 
96
96
  private
97
97
 
98
98
  def load_config(path)
99
- return nil unless File.exists?(path)
99
+ return nil unless File.exist?(path)
100
100
  YAML.load_file(path).with_indifferent_access
101
101
  end
102
102
  end
@@ -104,6 +104,6 @@ module Throttling
104
104
  reset_defaults!
105
105
  end
106
106
 
107
- require 'throttling/indifferent_access'
108
- require 'throttling/base'
107
+ require "throttling/indifferent_access"
108
+ require "throttling/base"
109
109
  require "throttling/version"
data/throttling.gemspec CHANGED
@@ -1,24 +1,38 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/throttling/version', __FILE__)
1
+ require File.expand_path("../lib/throttling/version", __FILE__)
3
2
 
4
- Gem::Specification.new do |gem|
5
- gem.authors = ["Dmytro Shteflyuk", "Oleksiy Kovyrin"]
6
- gem.email = ["kpumuk@kpumuk.info"]
7
- gem.description = %q{Throttling gem provides basic, but very powerful way to throttle various user actions in your application}
8
- gem.summary = %q{Easy throttling for Ruby applications}
9
- gem.homepage = "https://github.com/kpumuk/throttling"
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "throttling"
5
+ spec.version = Throttling::VERSION
6
+ spec.authors = ["Dmytro Shteflyuk", "Oleksiy Kovyrin"]
7
+ spec.email = ["kpumuk@kpumuk.info"]
10
8
 
11
- gem.add_development_dependency 'rake'
12
- gem.add_development_dependency 'rspec'
13
- gem.add_development_dependency 'timecop'
14
- gem.add_development_dependency 'guard-rspec'
15
- gem.add_development_dependency 'rb-fsevent'
16
- gem.add_development_dependency 'growl'
9
+ spec.summary = "Easy throttling for Ruby applications"
10
+ spec.description = "Throttling gem provides basic, but very powerful way to throttle various user actions in your application"
11
+ spec.homepage = "https://github.com/kpumuk/throttling"
12
+ spec.license = "MIT"
13
+ spec.platform = Gem::Platform::RUBY
14
+ spec.required_ruby_version = ">= 2.7.0"
17
15
 
18
- gem.files = `git ls-files`.split($\) - %w[.travis.yml]
19
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + %w[Guardfile]
21
- gem.name = "throttling"
22
- gem.require_paths = ["lib"]
23
- gem.version = Throttling::VERSION
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(\.|(bin|test|spec|features)/)}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "rake", "~> 13.0"
22
+ spec.add_development_dependency "rspec", "~> 3.12.0"
23
+ spec.add_development_dependency "timecop", "~> 0.9.6"
24
+ # Code style
25
+ spec.add_development_dependency "standard", "~> 1.29.0"
26
+
27
+ spec.cert_chain = ["certs/kpumuk.pem"]
28
+ spec.signing_key = File.expand_path("~/.ssh/gem-kpumuk.pem") if $PROGRAM_NAME.end_with?("gem")
29
+
30
+ spec.metadata = {
31
+ "bug_tracker_uri" => "https://github.com/kpumuk/throttling/issues/",
32
+ "changelog_uri" => "https://github.com/kpumuk/throttling/blob/main/CHANGELOG.md",
33
+ "documentation_uri" => "https://rubydoc.info/github/kpumuk/throttling/",
34
+ "homepage_uri" => "https://github.com/kpumuk/throttling/",
35
+ "source_code_uri" => "https://github.com/kpumuk/throttling/",
36
+ "rubygems_mfa_required" => "true"
37
+ }
24
38
  end
data.tar.gz.sig ADDED
Binary file
metadata CHANGED
@@ -1,83 +1,94 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: throttling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Dmytro Shteflyuk
9
8
  - Oleksiy Kovyrin
10
- autorequire:
11
- bindir: bin
12
- cert_chain: []
13
- date: 2012-04-13 00:00:00.000000000 Z
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain:
12
+ - |
13
+ -----BEGIN CERTIFICATE-----
14
+ MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MQ8wDQYDVQQDDAZrcHVt
15
+ dWsxFjAUBgoJkiaJk/IsZAEZFgZrcHVtdWsxFDASBgoJkiaJk/IsZAEZFgRpbmZv
16
+ MB4XDTIzMDcwNjEyMjY0MVoXDTI0MDcwNTEyMjY0MVowPzEPMA0GA1UEAwwGa3B1
17
+ bXVrMRYwFAYKCZImiZPyLGQBGRYGa3B1bXVrMRQwEgYKCZImiZPyLGQBGRYEaW5m
18
+ bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALw2YroZc+IT+rs8NuPu
19
+ c13DelrxrpAgPEu1zuRb3l7WaHRNWA4TyS8Z6Aa1G2O+FdUZNMW1n7IwP/QMJ9Mz
20
+ ahRBiTmhik5kasJ9s0h1lq5/hZiycm0o5OtGioUzCkvk+UEMpzMHbLmVSZCzYciy
21
+ NDRDbXB0rLLu1eJk+gKgn6Qf5vj93h1w28BdWdaA7YegtbmipZ+pjmzCQAfPActT
22
+ 6uXHG4dSo7Lz9jiFRI5dUizFbGXcRqkQ2b5AB8FFmfcvbqERvzQKBICnybjsKP0N
23
+ pJ3vGgO2sh5GvJFOPk1Vlur2nX9ZFznPEP1CEAQ+NFrmKRt355Z5sgOkAojSGnIL
24
+ /1sCAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFPa4
25
+ VFc1YOlV1u/7EGTwMCAk8YE9MB0GA1UdEQQWMBSBEmtwdW11a0BrcHVtdWsuaW5m
26
+ bzAdBgNVHRIEFjAUgRJrcHVtdWtAa3B1bXVrLmluZm8wDQYJKoZIhvcNAQELBQAD
27
+ ggEBALwivjTzGErFzBtgPEQe7uO6DMysgm/OIF5jLFkvRiuFbuueHM2cUZZBx2Rd
28
+ 2R5uQS4uiZ5KA+3SkgWQOFOzpFlo7ywS5264ULCcvfix6NQpb2aIDsZuzWGBIDbs
29
+ ixS+8wYslrzsOgUSn/RjF0sVB0dw4wv6G8YnVrR/Jf2SaO+Q2lYuKEOKfj52I+Yt
30
+ TdFiOjR+WwXSxs/XdSdFtqK2q/THbZdk+HkAe8guvXYtD/fzO2mBlk2AQ0hV1Pxu
31
+ ovz1LEphwrX/6v635mteXvl+OKWrNo1Q78sU364BgY5MvJMxFytmUrKMgO6RAiIM
32
+ N9+lhJiLa7+h0LrvPPDZRhV8ze0=
33
+ -----END CERTIFICATE-----
34
+ date: 2023-07-06 00:00:00.000000000 Z
14
35
  dependencies:
15
36
  - !ruby/object:Gem::Dependency
16
37
  name: rake
17
- requirement: &70097466944080 !ruby/object:Gem::Requirement
18
- none: false
38
+ requirement: !ruby/object:Gem::Requirement
19
39
  requirements:
20
- - - ! '>='
40
+ - - "~>"
21
41
  - !ruby/object:Gem::Version
22
- version: '0'
42
+ version: '13.0'
23
43
  type: :development
24
44
  prerelease: false
25
- version_requirements: *70097466944080
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '13.0'
26
50
  - !ruby/object:Gem::Dependency
27
51
  name: rspec
28
- requirement: &70097466943660 !ruby/object:Gem::Requirement
29
- none: false
52
+ requirement: !ruby/object:Gem::Requirement
30
53
  requirements:
31
- - - ! '>='
54
+ - - "~>"
32
55
  - !ruby/object:Gem::Version
33
- version: '0'
56
+ version: 3.12.0
34
57
  type: :development
35
58
  prerelease: false
36
- version_requirements: *70097466943660
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: 3.12.0
37
64
  - !ruby/object:Gem::Dependency
38
65
  name: timecop
39
- requirement: &70097466943240 !ruby/object:Gem::Requirement
40
- none: false
66
+ requirement: !ruby/object:Gem::Requirement
41
67
  requirements:
42
- - - ! '>='
68
+ - - "~>"
43
69
  - !ruby/object:Gem::Version
44
- version: '0'
70
+ version: 0.9.6
45
71
  type: :development
46
72
  prerelease: false
47
- version_requirements: *70097466943240
48
- - !ruby/object:Gem::Dependency
49
- name: guard-rspec
50
- requirement: &70097466942820 !ruby/object:Gem::Requirement
51
- none: false
73
+ version_requirements: !ruby/object:Gem::Requirement
52
74
  requirements:
53
- - - ! '>='
75
+ - - "~>"
54
76
  - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
57
- prerelease: false
58
- version_requirements: *70097466942820
77
+ version: 0.9.6
59
78
  - !ruby/object:Gem::Dependency
60
- name: rb-fsevent
61
- requirement: &70097466942400 !ruby/object:Gem::Requirement
62
- none: false
79
+ name: standard
80
+ requirement: !ruby/object:Gem::Requirement
63
81
  requirements:
64
- - - ! '>='
82
+ - - "~>"
65
83
  - !ruby/object:Gem::Version
66
- version: '0'
84
+ version: 1.29.0
67
85
  type: :development
68
86
  prerelease: false
69
- version_requirements: *70097466942400
70
- - !ruby/object:Gem::Dependency
71
- name: growl
72
- requirement: &70097466941980 !ruby/object:Gem::Requirement
73
- none: false
87
+ version_requirements: !ruby/object:Gem::Requirement
74
88
  requirements:
75
- - - ! '>='
89
+ - - "~>"
76
90
  - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :development
79
- prerelease: false
80
- version_requirements: *70097466941980
91
+ version: 1.29.0
81
92
  description: Throttling gem provides basic, but very powerful way to throttle various
82
93
  user actions in your application
83
94
  email:
@@ -86,10 +97,9 @@ executables: []
86
97
  extensions: []
87
98
  extra_rdoc_files: []
88
99
  files:
89
- - .gitignore
90
100
  - CHANGELOG.md
91
101
  - Gemfile
92
- - Guardfile
102
+ - Gemfile.lock
93
103
  - LICENSE
94
104
  - README.md
95
105
  - Rakefile
@@ -97,38 +107,34 @@ files:
97
107
  - lib/throttling/base.rb
98
108
  - lib/throttling/indifferent_access.rb
99
109
  - lib/throttling/version.rb
100
- - spec/base_spec.rb
101
- - spec/fixtures/throttling.yml
102
- - spec/spec_helper.rb
103
- - spec/throttling_spec.rb
104
110
  - throttling.gemspec
105
111
  homepage: https://github.com/kpumuk/throttling
106
- licenses: []
107
- post_install_message:
112
+ licenses:
113
+ - MIT
114
+ metadata:
115
+ bug_tracker_uri: https://github.com/kpumuk/throttling/issues/
116
+ changelog_uri: https://github.com/kpumuk/throttling/blob/main/CHANGELOG.md
117
+ documentation_uri: https://rubydoc.info/github/kpumuk/throttling/
118
+ homepage_uri: https://github.com/kpumuk/throttling/
119
+ source_code_uri: https://github.com/kpumuk/throttling/
120
+ rubygems_mfa_required: 'true'
121
+ post_install_message:
108
122
  rdoc_options: []
109
123
  require_paths:
110
124
  - lib
111
125
  required_ruby_version: !ruby/object:Gem::Requirement
112
- none: false
113
126
  requirements:
114
- - - ! '>='
127
+ - - ">="
115
128
  - !ruby/object:Gem::Version
116
- version: '0'
129
+ version: 2.7.0
117
130
  required_rubygems_version: !ruby/object:Gem::Requirement
118
- none: false
119
131
  requirements:
120
- - - ! '>='
132
+ - - ">="
121
133
  - !ruby/object:Gem::Version
122
134
  version: '0'
123
135
  requirements: []
124
- rubyforge_project:
125
- rubygems_version: 1.8.15
126
- signing_key:
127
- specification_version: 3
136
+ rubygems_version: 3.4.10
137
+ signing_key:
138
+ specification_version: 4
128
139
  summary: Easy throttling for Ruby applications
129
- test_files:
130
- - spec/base_spec.rb
131
- - spec/fixtures/throttling.yml
132
- - spec/spec_helper.rb
133
- - spec/throttling_spec.rb
134
- - Guardfile
140
+ test_files: []
metadata.gz.sig ADDED
Binary file
data/.gitignore DELETED
@@ -1,18 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- .idea
7
- Gemfile.lock
8
- InstalledFiles
9
- _yardoc
10
- coverage
11
- doc/
12
- lib/bundler/man
13
- pkg
14
- rdoc
15
- spec/reports
16
- test/tmp
17
- test/version_tmp
18
- tmp
data/Guardfile DELETED
@@ -1,6 +0,0 @@
1
- guard 'rspec', :version => 2, :cli => '--color --fail-fast --drb' do
2
- watch(%r{^spec/.+_spec\.rb})
3
- watch('lib/throttling.rb') { 'spec'}
4
- watch('spec/spec_helper.rb') { 'spec'}
5
- watch(%r{^lib/throttling/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
6
- end
data/spec/base_spec.rb DELETED
@@ -1,181 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Throttling do
4
- before do
5
- Throttling.reset_defaults!
6
- @storage = Throttling.storage = TestStorage.new
7
- end
8
-
9
- describe 'instance methods' do
10
- before do
11
- Throttling.limits = { 'foo' => {'limit' => 5, 'period' => 2} }
12
- @t = Throttling.for('foo')
13
- end
14
-
15
- { :check_ip => '127.0.0.1', :check_user_id => 123 }.each do |check_method, valid_value|
16
- describe check_method do
17
- it 'should return true for nil check_values' do
18
- @t.send(check_method, nil).should be_true
19
- end
20
-
21
- it 'should return true if no limit specified in configs' do
22
- Throttling.limits['foo']['limit'] = nil
23
- @storage.should_receive(:fetch).and_return(1000)
24
- @t.send(check_method, valid_value).should be_true
25
- end
26
-
27
- it 'should return false if limit is 0' do
28
- Throttling.limits['foo']['limit'] = 0
29
- @storage.should_receive(:fetch).and_return(0)
30
- @t.send(check_method, valid_value).should be_false
31
- end
32
-
33
- it 'should raise an exception if no period specified in configs' do
34
- Throttling.limits['foo']['period'] = nil
35
- lambda { @t.send(check_method, valid_value) }.should raise_error(ArgumentError)
36
- end
37
-
38
- it 'should raise an exception if invalid period specified in configs' do
39
- Throttling.limits['foo']['period'] = -1
40
- lambda { @t.send(check_method, valid_value) }.should raise_error(ArgumentError)
41
-
42
- Throttling.limits['foo']['period'] = 'foo'
43
- lambda { @t.send(check_method, valid_value) }.should raise_error(ArgumentError)
44
- end
45
-
46
- it 'should return true if throttling limit is not passed' do
47
- @storage.should_receive(:fetch).and_return(1)
48
- @t.send(check_method, valid_value).should be_true
49
- end
50
-
51
- it 'should return false if throttling limit is passed' do
52
- @storage.should_receive(:fetch).and_return(Throttling.limits['foo']['limit'] + 1)
53
- @t.send(check_method, valid_value).should be_false
54
- end
55
-
56
- context 'around limit' do
57
- it 'should increase hit counter when values equals to limit - 1' do
58
- @storage.should_receive(:fetch).and_return(Throttling.limits['foo']['limit'] - 1)
59
- @storage.should_receive(:increment)
60
- @t.send(check_method, valid_value)
61
- end
62
-
63
- it 'should not increase hit counter when values equals to limit' do
64
- @storage.should_receive(:fetch).and_return(Throttling.limits['foo']['limit'])
65
- @storage.should_not_receive(:increment)
66
- @t.send(check_method, valid_value)
67
- end
68
-
69
- it 'should not increase hit counter when values equals to limit + 1' do
70
- @storage.should_receive(:fetch).and_return(Throttling.limits['foo']['limit'] + 1)
71
- @storage.should_not_receive(:increment)
72
- @t.send(check_method, valid_value)
73
- end
74
-
75
- it 'should allow exactly limit actions' do
76
- 5.times { @t.send(check_method, valid_value).should be_true }
77
- @storage.should_not_receive(:increment)
78
- @t.send(check_method, valid_value).should be_false
79
- end
80
- end
81
- end
82
- end
83
- end
84
-
85
- describe 'with multi-level limits' do
86
- before do
87
- Throttling.limits = { 'foo' => { 'two' => { 'limit' => 10, 'period' => 20 }, 'one' => { 'limit' => 5, 'period' => 2 } } }
88
- end
89
-
90
- it 'should return false if at least one limit is reached' do
91
- @storage.should_receive(:fetch).and_return(1, 100)
92
- Throttling.for('foo').check_ip('127.0.0.1').should be_false
93
- end
94
-
95
- it 'should return true if none limits reached' do
96
- @storage.should_receive(:fetch).and_return(1, 2)
97
- Throttling.for('foo').check_ip('127.0.0.1').should be_true
98
- end
99
-
100
- it 'should sort limits by period' do
101
- @storage.should_receive(:fetch).ordered.with(/\:one\:/, anything).and_return(0)
102
- @storage.should_receive(:fetch).ordered.with(/\:two\:/, anything).and_return(0)
103
- Throttling.for('foo').check_ip('127.0.0.1').should be_true
104
- end
105
-
106
- it 'should return as soon as limit reached' do
107
- @storage.should_receive(:fetch).ordered.with(/\:one\:/, anything).and_return(10)
108
- @storage.should_not_receive(:fetch).with(/\:two\:/)
109
- Throttling.for('foo').check_ip('127.0.0.1').should be_false
110
- end
111
- end
112
-
113
- context 'with values specified' do
114
- before do
115
- Throttling.limits_config = File.expand_path('../fixtures/throttling.yml', __FILE__)
116
- end
117
-
118
- it 'should return value when limit is not reached' do
119
- @storage.should_receive(:fetch).and_return(0)
120
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 10
121
- @storage.should_receive(:fetch).and_return(4)
122
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 10
123
-
124
- @storage.should_receive(:fetch).and_return(5)
125
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 15
126
- @storage.should_receive(:fetch).and_return(14)
127
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 15
128
-
129
- @storage.should_receive(:fetch).and_return(15)
130
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 20
131
- @storage.should_receive(:fetch).and_return(99)
132
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 20
133
-
134
- @storage.should_receive(:fetch).and_return(100)
135
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 25
136
- @storage.should_receive(:fetch).and_return(1000)
137
- Throttling.for('request_priority').check_ip('127.0.0.1').should == 25
138
- end
139
-
140
- it 'should increase hit counter' do
141
- @storage.should_receive(:fetch).and_return(4)
142
- @storage.should_receive(:increment)
143
- Throttling.for('request_priority').check_ip('127.0.0.1')
144
-
145
- @storage.should_receive(:fetch).and_return(1000)
146
- @storage.should_receive(:increment)
147
- Throttling.for('request_priority').check_ip('127.0.0.1')
148
- end
149
-
150
- it 'should return false when highest limit reached' do
151
- Throttling.limits['request_priority'].delete('default_value')
152
- @storage.should_receive(:fetch).and_return(1000)
153
- Throttling.for('request_priority').check_ip('127.0.0.1').should be_false
154
- end
155
- end
156
-
157
- context do
158
- before do
159
- Throttling.limits = { 'foo' => {'limit' => 5, 'period' => 86400} }
160
- @timestamp = 1334261569
161
- end
162
-
163
- describe 'key name' do
164
- it 'should include type, value, name, and period start' do
165
- Timecop.freeze(Time.at(@timestamp)) do
166
- Throttling.for('foo').check_ip('127.0.0.1')
167
- end
168
- @storage.values.keys.first.should == 'throttle:foo:ip:127.0.0.1:global:15442'
169
- end
170
- end
171
-
172
- describe 'key expiration' do
173
- it 'should calculate expiration time' do
174
- Timecop.freeze(Time.at(@timestamp)) do
175
- Throttling.for('foo').check_ip('127.0.0.1')
176
- end
177
- @storage.values.values.first[:expires_in].should == 13631
178
- end
179
- end
180
- end
181
- end
@@ -1,28 +0,0 @@
1
- user_signup:
2
- limit: 20
3
- period: 3600
4
-
5
- search_requests:
6
- minutely:
7
- limit: 300
8
- period: 600
9
- hourly:
10
- limit: 1000
11
- period: 3600
12
- daily:
13
- limit: 10000
14
- period: 86400
15
-
16
- request_priority:
17
- period: 86400
18
- default_value: 25
19
- values:
20
- high_priority:
21
- limit: 5
22
- value: 10
23
- medium_priority:
24
- limit: 15
25
- value: 15
26
- low_priority:
27
- limit: 100
28
- value: 20
data/spec/spec_helper.rb DELETED
@@ -1,21 +0,0 @@
1
- require 'bundler/setup'
2
- require 'throttling'
3
- require 'timecop'
4
-
5
- class TestStorage
6
- attr_reader :values
7
-
8
- def fetch(key, options = {}, &block)
9
- @values ||= {}
10
- value = @values.fetch(key, &block)
11
- value = { :value => value.to_s } unless Hash === value
12
- @values[key] = value.merge(options)
13
- value[:value]
14
- end
15
-
16
- def increment(key)
17
- @values ||= {}
18
- @values[key] ||= { :value => 0 }
19
- @values[key][:value] = (@values[key][:value].to_i + 1).to_s
20
- end
21
- end
@@ -1,103 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Throttling do
4
- after :each do
5
- Throttling.reset_defaults!
6
- end
7
-
8
- context 'with defaults' do
9
- it 'should create logger' do
10
- Throttling.logger.should be_a(Logger)
11
- end
12
-
13
- it 'should be enabled' do
14
- Throttling.enabled?.should be_true
15
- Throttling.enabled.should be_true
16
- end
17
-
18
- it 'should set config file path' do
19
- Throttling.limits_config.should == "#{Dir.pwd}/config/throttling.yml"
20
- end
21
- end
22
-
23
- context 'setters' do
24
- it 'should allow to enabled and disable client' do
25
- Throttling.enabled = false
26
- Throttling.should_not be_enabled
27
-
28
- Throttling.enable!
29
- Throttling.should be_enabled
30
-
31
- Throttling.disable!
32
- Throttling.should_not be_enabled
33
-
34
- Throttling.enabled = true
35
- Throttling.should be_enabled
36
- end
37
-
38
- it 'should allow to change logger' do
39
- mock = Throttling.logger = mock('Logger')
40
- Throttling.logger.should be(mock)
41
- end
42
-
43
- it 'should allow to set limits' do
44
- limits = { 'foo' => {'limit' => 5, 'period' => 2} }
45
- Throttling.limits = limits
46
- Throttling.limits.should == limits
47
- end
48
-
49
- it 'should allow to change config file path' do
50
- path = File.expand_path('../fixtures/throttling.yml', __FILE__)
51
- Throttling.limits_config = path
52
- Throttling.limits_config.should == path
53
- end
54
- end
55
-
56
- describe '.for' do
57
- it "should return a throttling class instance" do
58
- Throttling.limits = { 'foo' => {'limit' => 5, 'period' => 2} }
59
- Throttling.for('foo').should be_instance_of(Throttling::Base)
60
- end
61
-
62
- it "should raise an exception if no throttling_limits found in config" do
63
- Throttling.limits = nil
64
- lambda { Throttling.for('foo') }.should raise_error(ArgumentError)
65
- end
66
-
67
- it "should raise an exception if no throttling_limits[action] found in config" do
68
- Throttling.limits = { 'foo' => nil }
69
- lambda { Throttling.for('foo') }.should raise_error(ArgumentError)
70
- end
71
- end
72
-
73
- describe 'limits' do
74
- context 'when set using .limits' do
75
- it 'should convert Hash to HashWithIndifferentAccess' do
76
- Throttling.limits = { 'foo' => {'limit' => 5, 'period' => 2} }
77
- Throttling.limits.should have_key(:foo)
78
- Throttling.limits.should have_key('foo')
79
- Throttling.limits[:foo].should have_key(:limit)
80
- Throttling.limits[:foo].should have_key('limit')
81
- end
82
- end
83
-
84
- context 'when set using .limits_config' do
85
- before do
86
- Throttling.limits_config = File.expand_path('../fixtures/throttling.yml', __FILE__)
87
- end
88
-
89
- it 'should load limits from configuration file' do
90
- Throttling.limits.should be_kind_of(Hash)
91
- Throttling.limits.should have_key('search_requests')
92
- Throttling.limits.should have_key('user_signup')
93
- end
94
-
95
- it 'should convert Hash to HashWithIndifferentAccess' do
96
- Throttling.limits.should have_key(:search_requests)
97
- Throttling.limits.should have_key('search_requests')
98
- Throttling.limits[:search_requests].should have_key(:daily)
99
- Throttling.limits[:search_requests].should have_key('daily')
100
- end
101
- end
102
- end
103
- end