prop 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -60,10 +60,31 @@ If the throttle! method gets called more than "threshold" times within "interval
60
60
  if e.handle == :authorization_attempt
61
61
  render :status => :forbidden, :message => I18n.t(e.description)
62
62
  elsif ...
63
-
63
+
64
64
  end
65
65
  end
66
66
 
67
+ ### Using the Middleware
68
+
69
+ Prop ships with a built in Rack middleware that you can use to do all the exception handling. When a `Prop::RateLimited` error is caught, it will build an HTTP [429 Too Many Requests](http://tools.ietf.org/html/draft-nottingham-http-new-status-02#section-4) response and set the following headers:
70
+
71
+ Retry-After: 32
72
+ Content-Type: text/plain
73
+ Content-Length: 72
74
+
75
+ Where `Retry-After` is the number of seconds the client has to wait before retrying this end point. The body of this response is whatever description Prop has configured for the throttle that got violated, or a default string if there's none configured.
76
+
77
+ If you wish to do manual error messaging in these cases, you can define an error handler in your Prop configuration. Here's how the default error handler looks, feel free to replace it with your own - you can set the error handler to anything that responds to `.call` and takes a `RateLimited` instance as argument:
78
+
79
+ error_handler = Proc.new do |error|
80
+ body = error.description || "This action has been rate limited"
81
+ headers = { "Content-Type" => "text/plain", "Content-Length" => body.size, "Retry-After" => error.retry_after }
82
+
83
+ [ 429, headers, [ body ]]
84
+ end
85
+
86
+ ActionController::Dispatcher.middleware.insert_before(ActionController::ParamsParser, :error_handler => error_handler)
87
+
67
88
  ## Disabling Prop
68
89
 
69
90
  In case you need to perform e.g. a manual bulk operation:
data/lib/prop.rb CHANGED
@@ -2,7 +2,7 @@ require "prop/limiter"
2
2
  require "forwardable"
3
3
 
4
4
  module Prop
5
- VERSION = "0.7.0"
5
+ VERSION = "0.7.1"
6
6
 
7
7
  # Short hand for accessing Prop::Limiter methods
8
8
  class << self
@@ -1,23 +1,32 @@
1
1
  module Prop
2
+
2
3
  # Convenience middleware that conveys the message configured on a Prop handle as well
3
4
  # as time left before the current window has passed in a Retry-After header.
4
5
  class Middleware
5
6
 
6
- def initialize(app)
7
- @app = app
7
+ # Default error handler
8
+ class DefaultErrorHandler
9
+ def self.call(error)
10
+ body = error.description || "This action has been rate limited"
11
+ headers = { "Content-Type" => "text/plain", "Content-Length" => body.size, "Retry-After" => error.retry_after }
12
+
13
+ [ 429, headers, [ body ]]
14
+ end
15
+ end
16
+
17
+ def initialize(app, options = {})
18
+ @app = app
19
+ @options = options
20
+ @handler = options[:error_handler] || DefaultErrorHandler
8
21
  end
9
22
 
10
- def call(env, options = {})
23
+ def call(env)
11
24
  begin
12
25
  @app.call(env)
13
26
  rescue Prop::RateLimited => e
14
- body = e.description || "This action has been rate limited"
15
-
16
- headers = { "Content-Type" => "text/plain", "Content-Length" => body.size }
17
- headers["Retry-After"] = e.retry_after if e.retry_after > 0
18
-
19
- [ 429, headers, [ body ]]
27
+ @handler.call(e)
20
28
  end
21
29
  end
22
30
  end
31
+
23
32
  end
data/prop.gemspec CHANGED
@@ -13,7 +13,7 @@ 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.7.0'
16
+ s.version = '0.7.1'
17
17
  s.date = '2012-04-06'
18
18
  s.rubyforge_project = 'prop'
19
19
 
@@ -32,6 +32,16 @@ class TestMiddleware < Test::Unit::TestCase
32
32
  assert_equal 429, response[0]
33
33
  assert_equal ["Boom!"], response[2]
34
34
  end
35
+
36
+ context "with a custom error handler" do
37
+ setup do
38
+ @middleware = Prop::Middleware.new(@app, :error_handler => Proc.new { |error| "Oops" })
39
+ end
40
+
41
+ should "allow setting a custom error handler" do
42
+ assert_equal "Oops", @middleware.call(@env)
43
+ end
44
+ end
35
45
  end
36
46
  end
37
47
  end
data/test/test_options.rb CHANGED
@@ -35,7 +35,11 @@ class TestOptions < Test::Unit::TestCase
35
35
 
36
36
  should "raise when not given a key" do
37
37
  @args.delete(:key)
38
- assert_raises(IndexError) { Prop::Options.build(@args) }
38
+ begin
39
+ Prop::Options.build(@args)
40
+ fail "Should puke when not given a valid key"
41
+ rescue
42
+ end
39
43
  end
40
44
  end
41
45
  end
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: 3
4
+ hash: 1
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 0
10
- version: 0.7.0
9
+ - 1
10
+ version: 0.7.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Morten Primdahl