throttling 0.3.1 → 0.4.1
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 +7 -0
- checksums.yaml.gz.sig +4 -0
- data/CHANGELOG.md +20 -8
- data/Gemfile +1 -1
- data/Gemfile.lock +88 -0
- data/README.md +136 -109
- data/Rakefile +3 -3
- data/certs/kpumuk.pem +21 -0
- data/lib/throttling/base.rb +6 -6
- data/lib/throttling/indifferent_access.rb +31 -22
- data/lib/throttling/version.rb +1 -1
- data/lib/throttling.rb +14 -14
- data/throttling.gemspec +35 -20
- data.tar.gz.sig +2 -0
- metadata +82 -64
- metadata.gz.sig +0 -0
- data/.gitignore +0 -18
- data/Guardfile +0 -6
- data/spec/base_spec.rb +0 -181
- data/spec/fixtures/throttling.yml +0 -28
- data/spec/spec_helper.rb +0 -21
- data/spec/throttling_spec.rb +0 -103
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ed71179ebb7b627ce788a1ced69b28bba67f9d983614724390a95d6df97f2d1
|
4
|
+
data.tar.gz: cafd2ed60cf1758b5527d40d864aa8892d638631a9a95e977161227f34328eb0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3d98584e62d6d179e4f358946f7d4f179e56df6c4a30e338e0bcd8b65a59a2ff9d0cccc9ca392306f3412dab4b5c94d7b64225c949fd31626d8ba45ac8181455
|
7
|
+
data.tar.gz: 7bd43a024a5bfca1a9dcf4d05cf70a255233dd87382b9229f63d04c5ab06c081cd83a8d20b5be0586b5fb42d8293387ff3e41cbb03c8f137be6246fe946c2c11
|
checksums.yaml.gz.sig
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,30 +1,42 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 0.4.1 (September 19, 2025)
|
4
|
+
|
5
|
+
- Multiple rexml fixes ([6](https://github.com/kpumuk/throttling/pull/6), [7](https://github.com/kpumuk/throttling/pull/7), [8](https://github.com/kpumuk/throttling/pull/8), [9](https://github.com/kpumuk/throttling/pull/9), [11](https://github.com/kpumuk/throttling/pull/11/))
|
6
|
+
- Use GitHub actions to build, sign and publish the gem ([11](https://github.com/kpumuk/throttling/pull/11/))
|
7
|
+
|
8
|
+
## 0.4.0 (July 6, 2023)
|
9
|
+
|
10
|
+
- Bump minimum Ruby requirement to 2.7.0
|
11
|
+
- Updated codebase to match StandardRB style guide
|
12
|
+
|
1
13
|
## 0.3.1 (April 13, 2012)
|
2
14
|
|
3
15
|
Features:
|
4
16
|
|
5
|
-
|
17
|
+
- When limit is omitted, no limits will be enforced (`check` always returns true)
|
6
18
|
|
7
19
|
Bugfixes:
|
8
20
|
|
9
|
-
|
10
|
-
|
21
|
+
- Fixed bug when action was allowed `limit + 1` times
|
22
|
+
- When limit is 0, `check` should always return `false`
|
11
23
|
|
12
24
|
## 0.3.0 (April 13, 2012)
|
13
25
|
|
14
26
|
Features:
|
15
27
|
|
16
|
-
|
28
|
+
- Added ability to retrieve custom value based on number of actions performed in a period of time
|
17
29
|
|
18
30
|
## 0.2.0 (April 12, 2012)
|
19
31
|
|
20
32
|
Bugfixes:
|
21
33
|
|
22
|
-
|
34
|
+
- Fixed bug when occurrences where increased for larger periods, when smaller ones did not pass
|
23
35
|
|
24
36
|
## 0.1.0 (April 12, 2012)
|
25
37
|
|
26
38
|
Features:
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
- Allows to throttle actions occurred in period of time
|
41
|
+
- Allows to specify limits inline or in external configuration file
|
42
|
+
- 100% test coverage
|
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
throttling (0.4.1)
|
5
|
+
logger
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.3)
|
11
|
+
diff-lcs (1.6.2)
|
12
|
+
json (2.15.0)
|
13
|
+
language_server-protocol (3.17.0.5)
|
14
|
+
lint_roller (1.1.0)
|
15
|
+
logger (1.7.0)
|
16
|
+
parallel (1.27.0)
|
17
|
+
parser (3.3.9.0)
|
18
|
+
ast (~> 2.4.1)
|
19
|
+
racc
|
20
|
+
prism (1.5.1)
|
21
|
+
racc (1.8.1)
|
22
|
+
rainbow (3.1.1)
|
23
|
+
rake (13.3.0)
|
24
|
+
regexp_parser (2.11.3)
|
25
|
+
rspec (3.13.1)
|
26
|
+
rspec-core (~> 3.13.0)
|
27
|
+
rspec-expectations (~> 3.13.0)
|
28
|
+
rspec-mocks (~> 3.13.0)
|
29
|
+
rspec-core (3.13.5)
|
30
|
+
rspec-support (~> 3.13.0)
|
31
|
+
rspec-expectations (3.13.5)
|
32
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
+
rspec-support (~> 3.13.0)
|
34
|
+
rspec-mocks (3.13.5)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.13.0)
|
37
|
+
rspec-support (3.13.6)
|
38
|
+
rubocop (1.80.2)
|
39
|
+
json (~> 2.3)
|
40
|
+
language_server-protocol (~> 3.17.0.2)
|
41
|
+
lint_roller (~> 1.1.0)
|
42
|
+
parallel (~> 1.10)
|
43
|
+
parser (>= 3.3.0.2)
|
44
|
+
rainbow (>= 2.2.2, < 4.0)
|
45
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
46
|
+
rubocop-ast (>= 1.46.0, < 2.0)
|
47
|
+
ruby-progressbar (~> 1.7)
|
48
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
49
|
+
rubocop-ast (1.47.1)
|
50
|
+
parser (>= 3.3.7.2)
|
51
|
+
prism (~> 1.4)
|
52
|
+
rubocop-performance (1.25.0)
|
53
|
+
lint_roller (~> 1.1)
|
54
|
+
rubocop (>= 1.75.0, < 2.0)
|
55
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
56
|
+
ruby-progressbar (1.13.0)
|
57
|
+
standard (1.51.1)
|
58
|
+
language_server-protocol (~> 3.17.0.2)
|
59
|
+
lint_roller (~> 1.0)
|
60
|
+
rubocop (~> 1.80.2)
|
61
|
+
standard-custom (~> 1.0.0)
|
62
|
+
standard-performance (~> 1.8)
|
63
|
+
standard-custom (1.0.2)
|
64
|
+
lint_roller (~> 1.0)
|
65
|
+
rubocop (~> 1.50)
|
66
|
+
standard-performance (1.8.0)
|
67
|
+
lint_roller (~> 1.1)
|
68
|
+
rubocop-performance (~> 1.25.0)
|
69
|
+
timecop (0.9.10)
|
70
|
+
unicode-display_width (3.2.0)
|
71
|
+
unicode-emoji (~> 4.1)
|
72
|
+
unicode-emoji (4.1.0)
|
73
|
+
|
74
|
+
PLATFORMS
|
75
|
+
arm64-darwin
|
76
|
+
arm64-linux
|
77
|
+
x86_64-darwin
|
78
|
+
x86_64-linux
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
rake (~> 13.0)
|
82
|
+
rspec (~> 3.13.0)
|
83
|
+
standard (~> 1.51.0)
|
84
|
+
throttling!
|
85
|
+
timecop (~> 0.9.6)
|
86
|
+
|
87
|
+
BUNDLED WITH
|
88
|
+
2.3.26
|
data/README.md
CHANGED
@@ -1,74 +1,79 @@
|
|
1
1
|
# Throttling
|
2
2
|
|
3
|
-
[](https://github.com/kpumuk/throttling/actions/workflows/tests.yml)
|
4
|
+
[](https://badge.fury.io/rb/throttling)
|
5
|
+
[](https://badge.fury.io/rb/throttling)
|
6
|
+
[](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
|
-
|
14
|
+
```ruby
|
15
|
+
gem "throttling"
|
16
|
+
```
|
12
17
|
|
13
|
-
And
|
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
|
-
|
26
|
-
|
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
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
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
|
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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
117
|
+
```ruby
|
118
|
+
Throttling.for(:user_signup).check(:user_id, current_user.id) do
|
119
|
+
# Do your stuff here
|
120
|
+
end
|
111
121
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
121
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
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
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
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
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
207
|
+
```ruby
|
208
|
+
Throttling.for("document_priorities").check_user_id(current_user.id)
|
209
|
+
```
|
183
210
|
|
184
211
|
## Contributing
|
185
212
|
|
data/Rakefile
CHANGED
data/certs/kpumuk.pem
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MQ8wDQYDVQQDDAZrcHVt
|
3
|
+
dWsxFjAUBgoJkiaJk/IsZAEZFgZrcHVtdWsxFDASBgoJkiaJk/IsZAEZFgRpbmZv
|
4
|
+
MB4XDTI1MDkyOTE1MDM1M1oXDTI2MDkyOTE1MDM1M1owPzEPMA0GA1UEAwwGa3B1
|
5
|
+
bXVrMRYwFAYKCZImiZPyLGQBGRYGa3B1bXVrMRQwEgYKCZImiZPyLGQBGRYEaW5m
|
6
|
+
bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALw2YroZc+IT+rs8NuPu
|
7
|
+
c13DelrxrpAgPEu1zuRb3l7WaHRNWA4TyS8Z6Aa1G2O+FdUZNMW1n7IwP/QMJ9Mz
|
8
|
+
ahRBiTmhik5kasJ9s0h1lq5/hZiycm0o5OtGioUzCkvk+UEMpzMHbLmVSZCzYciy
|
9
|
+
NDRDbXB0rLLu1eJk+gKgn6Qf5vj93h1w28BdWdaA7YegtbmipZ+pjmzCQAfPActT
|
10
|
+
6uXHG4dSo7Lz9jiFRI5dUizFbGXcRqkQ2b5AB8FFmfcvbqERvzQKBICnybjsKP0N
|
11
|
+
pJ3vGgO2sh5GvJFOPk1Vlur2nX9ZFznPEP1CEAQ+NFrmKRt355Z5sgOkAojSGnIL
|
12
|
+
/1sCAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFPa4
|
13
|
+
VFc1YOlV1u/7EGTwMCAk8YE9MB0GA1UdEQQWMBSBEmtwdW11a0BrcHVtdWsuaW5m
|
14
|
+
bzAdBgNVHRIEFjAUgRJrcHVtdWtAa3B1bXVrLmluZm8wDQYJKoZIhvcNAQELBQAD
|
15
|
+
ggEBAFz/6+efHFEomTCA8V/eMpzaMkbj04cTmFxm28KiUO1F4vgbSIBx0bsMoJkH
|
16
|
+
KI956sPVVJMykwOdDUhRWBrHOVTBCGdkYWdb38KQKfwtkdGd8b/Afrxs5GuPME9r
|
17
|
+
TdfDc1aXCAPdLCajhpmuzfa1g8/W7ORdxwNQidYSSPJ5OvcAGSfxTHJsFseHjrBK
|
18
|
+
9hdoXZgqc4a5defxoOZFD9Im9AUwFqwR8njCBST6FbCGmHIYNHj2hxbwrU/1I2Kg
|
19
|
+
pPzkBOwQl2p1ykAEUe7cwoqJcO+1rPeTHjudNqhOfc3VnMA8A7uXOkTtYNVhvApn
|
20
|
+
oW4hE/8SnZkQm8jzdi0iX9nWxo8=
|
21
|
+
-----END CERTIFICATE-----
|
data/lib/throttling/base.rb
CHANGED
@@ -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 = [[
|
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
|
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, :
|
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
|
-
|
57
|
+
elsif !limit.nil? && hits >= limit
|
58
58
|
# Over limit?
|
59
|
-
return false
|
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
|
-
|
66
|
+
true
|
67
67
|
end
|
68
68
|
|
69
69
|
private
|
@@ -15,7 +15,7 @@ module Throttling
|
|
15
15
|
super()
|
16
16
|
update(constructor)
|
17
17
|
else
|
18
|
-
super
|
18
|
+
super
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -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,13 +95,13 @@ 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
|
-
|
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.
|
102
102
|
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
|
103
103
|
def reverse_merge(other_hash)
|
104
|
-
super
|
104
|
+
super(other_hash.with_indifferent_access)
|
105
105
|
end
|
106
106
|
|
107
107
|
# Removes a specified key from the hash.
|
@@ -109,9 +109,17 @@ module Throttling
|
|
109
109
|
super(convert_key(key))
|
110
110
|
end
|
111
111
|
|
112
|
-
def stringify_keys
|
113
|
-
|
114
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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
|
147
|
+
module HashIndifferentAccess # :nodoc:
|
139
148
|
def with_indifferent_access
|
140
149
|
hash = HashWithIndifferentAccess.new(self)
|
141
|
-
hash.default =
|
150
|
+
hash.default = default
|
142
151
|
hash
|
143
152
|
end
|
144
153
|
end
|
145
154
|
|
146
|
-
class ::Hash
|
155
|
+
class ::Hash # :nodoc:
|
147
156
|
unless respond_to?(:with_indifferent_access)
|
148
157
|
include Throttling::HashIndifferentAccess
|
149
158
|
end
|
data/lib/throttling/version.rb
CHANGED