prop 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +9 -1
- data/VERSION +1 -1
- data/lib/prop.rb +13 -2
- data/prop.gemspec +1 -1
- data/test/test_prop.rb +9 -0
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -34,7 +34,15 @@ In many cases you will want to tie a specific key to a defined throttle, for exa
|
|
34
34
|
|
35
35
|
Prop.throttle_mails_per_hour!(mail.from)
|
36
36
|
|
37
|
-
If this method gets called more than "threshold" times within "interval in seconds" Prop throws a Prop::RateLimitExceededError.
|
37
|
+
If this method gets called more than "threshold" times within "interval in seconds" Prop throws a Prop::RateLimitExceededError. You can change the message of this error, which is handy when you are using Prop in multiple locations and want to be able to differentiate further up the stack. For example:
|
38
|
+
|
39
|
+
Prop.setup(:logins, :threshold => 5, :interval => 5.minutes, :message => "Too many invalid login attempts.")
|
40
|
+
|
41
|
+
In Rails you can use this in e.g. ApplicationController:
|
42
|
+
|
43
|
+
rescue_from Prop::RateLimitExceededError do |exception|
|
44
|
+
render :status => 403, :message => exception.message
|
45
|
+
end
|
38
46
|
|
39
47
|
You can chose to override the threshold for a given key:
|
40
48
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.4
|
data/lib/prop.rb
CHANGED
@@ -8,6 +8,14 @@ end
|
|
8
8
|
|
9
9
|
class Prop
|
10
10
|
class RateLimitExceededError < RuntimeError
|
11
|
+
attr_reader :root_message, :retry_after
|
12
|
+
|
13
|
+
def initialize(key, threshold, message)
|
14
|
+
@root_message = "#{key} threshold #{threshold} exceeded"
|
15
|
+
@retry_after = Time.now.to_i % threshold.to_i
|
16
|
+
|
17
|
+
super(message || @root_message)
|
18
|
+
end
|
11
19
|
end
|
12
20
|
|
13
21
|
class << self
|
@@ -46,7 +54,7 @@ class Prop
|
|
46
54
|
counter = count(options)
|
47
55
|
|
48
56
|
if counter >= options[:threshold]
|
49
|
-
raise Prop::RateLimitExceededError.new(
|
57
|
+
raise Prop::RateLimitExceededError.new(options[:key], options[:threshold], options[:message])
|
50
58
|
else
|
51
59
|
writer.call(sanitized_prop_key(options), counter + 1)
|
52
60
|
end
|
@@ -73,7 +81,10 @@ class Prop
|
|
73
81
|
# Sanitizes the option set and sets defaults
|
74
82
|
def sanitized_prop_options(args, defaults)
|
75
83
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
76
|
-
{
|
84
|
+
return {
|
85
|
+
:key => normalize_cache_key(args), :message => defaults[:message],
|
86
|
+
:threshold => defaults[:threshold].to_i, :interval => defaults[:interval].to_i
|
87
|
+
}.merge(options)
|
77
88
|
end
|
78
89
|
|
79
90
|
# Simple key expansion only supports arrays and primitives
|
data/prop.gemspec
CHANGED
data/test/test_prop.rb
CHANGED
@@ -126,6 +126,15 @@ class TestProp < Test::Unit::TestCase
|
|
126
126
|
assert_raises(Prop::RateLimitExceededError) do
|
127
127
|
Prop.throttle!(:key => 'hello', :threshold => 5, :interval => 10)
|
128
128
|
end
|
129
|
+
|
130
|
+
begin
|
131
|
+
Prop.throttle!(:key => 'hello', :threshold => 5, :interval => 10, :message => "Wibble")
|
132
|
+
fail
|
133
|
+
rescue Prop::RateLimitExceededError => e
|
134
|
+
assert_equal "Wibble", e.message
|
135
|
+
assert_equal "hello threshold 5 exceeded", e.root_message
|
136
|
+
assert e.retry_after
|
137
|
+
end
|
129
138
|
end
|
130
139
|
end
|
131
140
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 4
|
10
|
+
version: 0.3.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Morten Primdahl
|