prop 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -56,7 +56,7 @@ The throttle scope can also be an array of values, e.g.:
56
56
 
57
57
  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::RateLimited error which is a subclass of StandardError. This exception contains a "handle" reference and a "description" if specified during the configuration. The handle allows you to rescue Prop::RateLimited and differentiate action depending on the handle. For example, in Rails you can use this in e.g. ApplicationController:
58
58
 
59
- rescue_from Prop::RateLimitExceededError do |e|
59
+ rescue_from Prop::RateLimited do |e|
60
60
  if e.handle == :authorization_attempt
61
61
  render :status => :forbidden, :message => I18n.t(e.description)
62
62
  elsif ...
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.2"
5
+ VERSION = "0.7.3"
6
6
 
7
7
  # Short hand for accessing Prop::Limiter methods
8
8
  class << self
data/lib/prop/limiter.rb CHANGED
@@ -45,19 +45,26 @@ module Prop
45
45
  # handle - the registered handle associated with the action
46
46
  # key - a custom request specific key, e.g. [ account.id, "download", request.remote_ip ]
47
47
  # options - request specific overrides to the defaults configured for this handle
48
+ # blk - an optional block of code that this throttle is guarding
48
49
  #
49
50
  # Raises Prop::RateLimited if the number if the threshold for this handle has been reached
50
- def throttle!(handle, key = nil, options = {})
51
+ # Returns the value of the block if given a such, otherwise the current count of the throttle
52
+ def throttle!(handle, key = nil, options = {}, &blk)
51
53
  options, cache_key = prepare(handle, key, options)
52
-
53
54
  counter = reader.call(cache_key).to_i
54
55
 
55
- return counter if disabled?
56
+ unless disabled?
57
+ if at_threshold?(counter, options[:threshold])
58
+ raise Prop::RateLimited.new(options.merge(:cache_key => cache_key, :handle => handle))
59
+ else
60
+ counter = writer.call(cache_key, counter + [ 1, options[:increment].to_i ].max)
61
+ end
62
+ end
56
63
 
57
- if counter >= options[:threshold]
58
- raise Prop::RateLimited.new(options.merge(:cache_key => cache_key, :handle => handle))
64
+ if block_given?
65
+ yield
59
66
  else
60
- writer.call(cache_key, counter + [ 1, options[:increment].to_i ].max)
67
+ counter
61
68
  end
62
69
  end
63
70
 
@@ -97,6 +104,10 @@ module Prop
97
104
 
98
105
  private
99
106
 
107
+ def at_threshold?(mark, threshold)
108
+ mark >= threshold
109
+ end
110
+
100
111
  def disabled?
101
112
  !!@disabled
102
113
  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.2'
16
+ s.version = '0.7.3'
17
17
  s.date = '2012-04-06'
18
18
  s.rubyforge_project = 'prop'
19
19
 
@@ -74,6 +74,7 @@ Gem::Specification.new do |s|
74
74
  prop.gemspec
75
75
  test/helper.rb
76
76
  test/test_key.rb
77
+ test/test_limiter.rb
77
78
  test/test_middleware.rb
78
79
  test/test_options.rb
79
80
  test/test_prop.rb
@@ -0,0 +1,83 @@
1
+ require 'helper'
2
+
3
+ class TestLimiter < Test::Unit::TestCase
4
+
5
+ context Prop::Limiter do
6
+ setup do
7
+ @store = {}
8
+
9
+ Prop::Limiter.read { |key| @store[key] }
10
+ Prop::Limiter.write { |key, value| @store[key] = value }
11
+ Prop::Limiter.configure(:something, :threshold => 10, :interval => 10)
12
+
13
+ @start = Time.now
14
+ Time.stubs(:now).returns(@start)
15
+ end
16
+
17
+ context "#throttle!" do
18
+ setup do
19
+ Prop.reset(:something)
20
+ end
21
+
22
+ context "when disabled" do
23
+ setup { Prop::Limiter.expects(:disabled?).returns(true) }
24
+
25
+ [ true, false ].each do |threshold_reached|
26
+ context "and threshold has #{"not " unless threshold_reached}been reached" do
27
+ setup { Prop::Limiter.stubs(:at_threshold?).returns(threshold_reached) }
28
+
29
+ context "given a block" do
30
+ should "execute that block" do
31
+ assert_equal "wibble", Prop.throttle!(:something) { "wibble" }
32
+ end
33
+ end
34
+
35
+ context "not given a block" do
36
+ should "return the current throttle count" do
37
+ assert_equal Prop.count(:something), Prop.throttle!(:something)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ context "when not disabled" do
45
+ setup { Prop::Limiter.expects(:disabled?).returns(false) }
46
+
47
+ context "and threshold has been reached" do
48
+ setup { Prop::Limiter.expects(:at_threshold?).returns(true) }
49
+
50
+ context "given a block" do
51
+ should "raise Prop::RateLimited" do
52
+ assert_raises(Prop::RateLimited) { Prop.throttle!(:something) { "wibble" }}
53
+ end
54
+ end
55
+
56
+ context "not given a block" do
57
+ should "raise Prop::RateLimited" do
58
+ assert_raises(Prop::RateLimited) { Prop.throttle!(:something) }
59
+ end
60
+ end
61
+ end
62
+
63
+ context "and threshold has not been reached" do
64
+ setup do
65
+ Prop::Limiter.expects(:at_threshold?).returns(false)
66
+ end
67
+
68
+ context "given a block" do
69
+ should "execute that block" do
70
+ assert_equal "wibble", Prop.throttle!(:something) { "wibble" }
71
+ end
72
+ end
73
+
74
+ context "not given a block" do
75
+ should "return the updated throttle count" do
76
+ assert_equal Prop.count(:something) + 1, Prop.throttle!(:something)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
data/test/test_prop.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'helper'
2
2
 
3
+ # Integration level tests
3
4
  class TestProp < Test::Unit::TestCase
4
5
 
5
6
  context "Prop" do
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: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 2
10
- version: 0.7.2
9
+ - 3
10
+ version: 0.7.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Morten Primdahl
@@ -96,6 +96,7 @@ files:
96
96
  - prop.gemspec
97
97
  - test/helper.rb
98
98
  - test/test_key.rb
99
+ - test/test_limiter.rb
99
100
  - test/test_middleware.rb
100
101
  - test/test_options.rb
101
102
  - test/test_prop.rb
@@ -135,6 +136,7 @@ specification_version: 2
135
136
  summary: Gem for implementing rate limits.
136
137
  test_files:
137
138
  - test/test_key.rb
139
+ - test/test_limiter.rb
138
140
  - test/test_middleware.rb
139
141
  - test/test_options.rb
140
142
  - test/test_prop.rb