prop 0.7.2 → 0.7.3

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.
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