prop 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -1,96 +1,96 @@
1
1
 
2
- = Prop
2
+ # Prop [![Build Status](https://secure.travis-ci.org/morten/prop.png)](http://travis-ci.org/morten/prop)
3
3
 
4
4
  Prop is a simple gem for rate limiting requests of any kind. It allows you to configure hooks for registering certain actions, such that you can define thresholds, register usage and finally act on exceptions once thresholds get exceeded.
5
5
 
6
6
  To get going with Prop you first define the read and write operations. These define how you write a registered request and how to read the number of requests for a given action. For example do something like the below in a Rails initializer:
7
7
 
8
- Prop.read do |key|
9
- Rails.cache.read(key)
10
- end
8
+ Prop.read do |key|
9
+ Rails.cache.read(key)
10
+ end
11
11
 
12
- Prop.write do |key, value|
13
- Rails.cache.write(key, value)
14
- end
12
+ Prop.write do |key, value|
13
+ Rails.cache.write(key, value)
14
+ end
15
15
 
16
16
  You can choose to rely on a database or Moneta or Redis or whatever you'd like to use for transient storage. Prop does not do any sort of clean up of its key space, so you would have to implement that manually should you be using anything but an LRU cache.
17
17
 
18
- == Defining thresholds
18
+ ## Defining thresholds
19
19
 
20
20
  Once the read and write operations are defined, you can optionally define thresholds. If for example, you want to have a threshold on accepted emails per hour from a given user, you could define a threshold and interval (in seconds) for this like so:
21
21
 
22
- Prop.configure(:mails_per_hour, :threshold => 100, :interval => 1.hour, :description => "Mail rate limit exceeded")
22
+ Prop.configure(:mails_per_hour, :threshold => 100, :interval => 1.hour, :description => "Mail rate limit exceeded")
23
23
 
24
24
  You can now put the throttle to work with this values, by passing the "handle" to the respective methods in Prop:
25
25
 
26
- # Throws Prop::RateLimitExceededError if the threshold/interval has been reached
27
- Prop.throttle!(:mails_per_hour)
26
+ # Throws Prop::RateLimitExceededError if the threshold/interval has been reached
27
+ Prop.throttle!(:mails_per_hour)
28
28
 
29
- # Returns true if the threshold/interval has been reached
30
- Prop.throttled?(:mails_per_hour)
29
+ # Returns true if the threshold/interval has been reached
30
+ Prop.throttled?(:mails_per_hour)
31
31
 
32
- # Sets the throttle "count" to 0
33
- Prop.reset(:mails_per_hour)
32
+ # Sets the throttle "count" to 0
33
+ Prop.reset(:mails_per_hour)
34
34
 
35
- # Returns the value of this throttle, usually a count, but see below for more
36
- Prop.query(:mails_per_hour)
35
+ # Returns the value of this throttle, usually a count, but see below for more
36
+ Prop.query(:mails_per_hour)
37
37
 
38
38
  Prop will raise a RuntimeError if you attempt to operate on an undefined handle.
39
39
 
40
- == Scoping a throttle
40
+ ## Scoping a throttle
41
41
 
42
42
  In many cases you will want to tie a specific key to a defined throttle, for example you can scope the throttling to a specific sender rather than running a global "mails per hour" throttle:
43
43
 
44
- Prop.throttle!(:mails_per_hour, mail.from)
45
- Prop.throttled?(:mails_per_hour, mail.from)
46
- Prop.reset(:mails_per_hour, mail.from)
47
- Prop.query(:mails_per_hour, mail.from)
44
+ Prop.throttle!(:mails_per_hour, mail.from)
45
+ Prop.throttled?(:mails_per_hour, mail.from)
46
+ Prop.reset(:mails_per_hour, mail.from)
47
+ Prop.query(:mails_per_hour, mail.from)
48
48
 
49
49
  The throttle scope can also be an array of values, e.g.:
50
50
 
51
- Prop.throttle!(:mails_per_hour, [ account.id, mail.from ])
51
+ Prop.throttle!(:mails_per_hour, [ account.id, mail.from ])
52
52
 
53
- == Error handling
53
+ ## Error handling
54
54
 
55
55
  If the throttle! method gets called more than "threshold" times within "interval in seconds" for a given handle and key combination, Prop throws a Prop::RateLimitExceededError. This exception contains a "handle" reference and a "description" if specified during the configuration. The handle allows you to rescue Prop::RateLimitExceededError and differentiate action depending on the handle. For example, in Rails you can use this in e.g. ApplicationController:
56
56
 
57
- rescue_from Prop::RateLimitExceededError do |e|
58
- if e.handle == :authorization_attempt
59
- render :status => :forbidden, :message => I18n.t(e.description)
60
- elsif ...
61
-
57
+ rescue_from Prop::RateLimitExceededError do |e|
58
+ if e.handle == :authorization_attempt
59
+ render :status => :forbidden, :message => I18n.t(e.description)
60
+ elsif ...
61
+
62
+ end
62
63
  end
63
- end
64
64
 
65
- == Disabling Prop
65
+ ## Disabling Prop
66
66
 
67
67
  In case you need to perform e.g. a manual bulk operation:
68
68
 
69
- Prop.disabled do
70
- # No throttles will be tested here
71
- end
69
+ Prop.disabled do
70
+ # No throttles will be tested here
71
+ end
72
72
 
73
- == Threshold settings
73
+ ## Threshold settings
74
74
 
75
75
  You can chose to override the threshold for a given key:
76
76
 
77
- Prop.throttle!(:mails_per_hour, mail.from, :threshold => current_account.mail_throttle_threshold)
77
+ Prop.throttle!(:mails_per_hour, mail.from, :threshold => current_account.mail_throttle_threshold)
78
78
 
79
79
  When the threshold are invoked without argument, the key is nil and as such a scope of its own, i.e. these are equivalent:
80
80
 
81
- Prop.throttle!(:mails_per_hour)
82
- Prop.throttle!(:mails_per_hour, nil)
81
+ Prop.throttle!(:mails_per_hour)
82
+ Prop.throttle!(:mails_per_hour, nil)
83
83
 
84
84
  The default (and smallest possible) increment is 1, you can set that to any integer value using :increment which is handy for building time based throttles:
85
85
 
86
- Prop.setup(:execute_time, :threshold => 10, :interval => 1.minute)
87
- Prop.throttle!(:execute_time, account.id, :increment => (Benchmark.realtime { execute }).to_i)
86
+ Prop.setup(:execute_time, :threshold => 10, :interval => 1.minute)
87
+ Prop.throttle!(:execute_time, account.id, :increment => (Benchmark.realtime { execute }).to_i)
88
88
 
89
- == How it works
89
+ ## How it works
90
90
 
91
91
  Prop uses the interval to define a window of time using simple div arithmetic. This means that it's a worst case throttle that will allow up to 2 times the specified requests within the specified interval.
92
92
 
93
- == Note on Patches/Pull Requests
93
+ ## Note on Patches/Pull Requests
94
94
 
95
95
  * Fork the project.
96
96
  * Make your feature addition or bug fix.
data/lib/prop.rb CHANGED
@@ -7,7 +7,7 @@ class Object
7
7
  end
8
8
 
9
9
  class Prop
10
- VERSION = "0.6.4"
10
+ VERSION = "0.6.5"
11
11
 
12
12
  class RateLimitExceededError < RuntimeError
13
13
  attr_accessor :handle, :retry_after, :description
@@ -103,10 +103,11 @@ class Prop
103
103
 
104
104
  defaults = handles[handle]
105
105
  return {
106
- :key => normalize_cache_key(key),
107
- :increment => defaults[:increment],
108
- :threshold => defaults[:threshold].to_i,
109
- :interval => defaults[:interval].to_i
106
+ :key => normalize_cache_key(key),
107
+ :increment => defaults[:increment],
108
+ :description => defaults[:description],
109
+ :threshold => defaults[:threshold].to_i,
110
+ :interval => defaults[:interval].to_i
110
111
  }.merge(options)
111
112
  end
112
113
 
data/prop.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'prop'
16
- s.version = '0.6.4'
17
- s.date = '2011-11-30'
16
+ s.version = '0.6.5'
17
+ s.date = '2011-12-13'
18
18
  s.rubyforge_project = 'prop'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -43,7 +43,7 @@ Gem::Specification.new do |s|
43
43
  ## Specify any RDoc options here. You'll want to add your README and
44
44
  ## LICENSE files to the extra_rdoc_files list.
45
45
  s.rdoc_options = ["--charset=UTF-8"]
46
- s.extra_rdoc_files = %w[README.rdoc LICENSE]
46
+ s.extra_rdoc_files = %w[README.md LICENSE]
47
47
 
48
48
  ## List your runtime dependencies here. Runtime dependencies are those
49
49
  ## that are needed for an end user to actually USE your code.
@@ -61,8 +61,9 @@ Gem::Specification.new do |s|
61
61
  ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
62
62
  # = MANIFEST =
63
63
  s.files = %w[
64
+ Gemfile
64
65
  LICENSE
65
- README.rdoc
66
+ README.md
66
67
  Rakefile
67
68
  lib/prop.rb
68
69
  prop.gemspec
data/test/test_prop.rb CHANGED
@@ -152,15 +152,17 @@ class TestProp < Test::Unit::TestCase
152
152
  end
153
153
 
154
154
  should "raise Prop::RateLimitExceededError when the threshold is exceeded" do
155
+ Prop.configure(:hello, :threshold => 5, :interval => 10, :description => "Boom!")
156
+
155
157
  5.times do |i|
156
- Prop.throttle!(:hello, nil, :threshold => 5, :interval => 10)
158
+ Prop.throttle!(:hello, nil)
157
159
  end
158
160
  assert_raises(Prop::RateLimitExceededError) do
159
- Prop.throttle!(:hello, nil, :threshold => 5, :interval => 10)
161
+ Prop.throttle!(:hello, nil)
160
162
  end
161
163
 
162
164
  begin
163
- Prop.throttle!(:hello, nil, :threshold => 5, :interval => 10, :description => "Boom!")
165
+ Prop.throttle!(:hello, nil)
164
166
  fail
165
167
  rescue Prop::RateLimitExceededError => e
166
168
  assert_equal :hello, e.handle
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: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 4
10
- version: 0.6.4
9
+ - 5
10
+ version: 0.6.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Morten Primdahl
@@ -15,13 +15,13 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-30 00:00:00 -08:00
18
+ date: 2011-12-13 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: rake
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
23
+ type: :development
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
27
  - - ">="
@@ -30,12 +30,12 @@ dependencies:
30
30
  segments:
31
31
  - 0
32
32
  version: "0"
33
- type: :development
34
- version_requirements: *id001
33
+ prerelease: false
34
+ requirement: *id001
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: bundler
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
37
+ type: :development
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ">="
@@ -44,12 +44,12 @@ dependencies:
44
44
  segments:
45
45
  - 0
46
46
  version: "0"
47
- type: :development
48
- version_requirements: *id002
47
+ prerelease: false
48
+ requirement: *id002
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: shoulda
51
- prerelease: false
52
- requirement: &id003 !ruby/object:Gem::Requirement
51
+ type: :development
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ">="
@@ -58,12 +58,12 @@ dependencies:
58
58
  segments:
59
59
  - 0
60
60
  version: "0"
61
- type: :development
62
- version_requirements: *id003
61
+ prerelease: false
62
+ requirement: *id003
63
63
  - !ruby/object:Gem::Dependency
64
64
  name: mocha
65
- prerelease: false
66
- requirement: &id004 !ruby/object:Gem::Requirement
65
+ type: :development
66
+ version_requirements: &id004 !ruby/object:Gem::Requirement
67
67
  none: false
68
68
  requirements:
69
69
  - - ">="
@@ -72,8 +72,8 @@ dependencies:
72
72
  segments:
73
73
  - 0
74
74
  version: "0"
75
- type: :development
76
- version_requirements: *id004
75
+ prerelease: false
76
+ requirement: *id004
77
77
  description: Gem for implementing rate limits.
78
78
  email: primdahl@me.com
79
79
  executables: []
@@ -81,11 +81,12 @@ executables: []
81
81
  extensions: []
82
82
 
83
83
  extra_rdoc_files:
84
- - README.rdoc
84
+ - README.md
85
85
  - LICENSE
86
86
  files:
87
+ - Gemfile
87
88
  - LICENSE
88
- - README.rdoc
89
+ - README.md
89
90
  - Rakefile
90
91
  - lib/prop.rb
91
92
  - prop.gemspec