fine_tune 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p194
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.1.8
4
+ - 1.9.3
5
5
  before_install: gem install bundler -v 1.12.5
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016 Laknath
3
+ Copyright (c) 2016 Vesess Inc. (laknath [at] vesess [dot] com)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,41 +1,109 @@
1
- # FineTune
1
+ [![Build Status](https://travis-ci.org/laknath/fine_tune.svg?branch=master)](https://travis-ci.org/laknath/fine_tune)
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/fine_tune`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ # FineTune - a flexible rate limiting/monitoring library
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ FineTune can be used to limit the rate of any given activity/event
6
+ stream such as outgoing emails for a user. It's not fixed on a
7
+ particular implementation of throttling, rather it provides a framework
8
+ to add custom implementations/algorithms.
9
+
10
+ The main difference with other rate limiting libraries is the
11
+ flexibility of using custom throttling algorithms and external
12
+ data/cache stores. Also it doesn't need to be configured first, all
13
+ options can be passed in each throttling request.
6
14
 
7
15
  ## Installation
8
16
 
9
- Add this line to your application's Gemfile:
17
+ $ gem install fine_tune
10
18
 
11
- ```ruby
12
- gem 'fine_tune'
13
- ```
19
+ ## Usage
14
20
 
15
- And then execute:
21
+ Throttle represents an occurrence of a defined event. It will return true
22
+ if the threshold has reached. If not the count will be increased by one
23
+ and will return false.
16
24
 
17
- $ bundle
25
+ ```
26
+ $ FineTune.throttle(:transactions_per_hour, user_id, options)
27
+ ```
18
28
 
19
- Or install it yourself as:
29
+ * :transactions_per_hour - the name for the event
30
+ * user_id - some unique identifier for a resource (ie: user)
31
+ * options - configurations for the throttling implementation
20
32
 
21
- $ gem install fine_tune
33
+ An additional block can be passed, which will be called with event
34
+ details. ie:
22
35
 
23
- ## Usage
36
+ ```
37
+ $ FineTune.throttle(:transactions_per_hour, user_id, options) do
38
+ | count, comparison, id, strategy, options |
39
+ #something...
40
+ end
41
+ ```
42
+
43
+ In addition, there's a more charged version - throttle! which will raise
44
+ a MaxRateError when reached the threshold. Same as throttle, it takes a
45
+ block.
24
46
 
25
- TODO: Write usage instructions here
47
+ ```
48
+ $ FineTune.throttle!(:transactions_per_hour, user_id, options)
49
+ ```
26
50
 
27
- ## Development
51
+ To get the current count of events:
52
+
53
+ ```
54
+ $ FineTune.count(:emails_per_day, user_id, options)
55
+ ```
56
+
57
+ To check whether threshold has reached:
58
+
59
+ ```
60
+ $ FineTune.rate_exceeded?(:emails_per_day, user_id, options)
61
+ ```
62
+
63
+ To reset the count of events for a resource:
64
+
65
+ ```
66
+ $ FineTune.reset(:emails_per_day, user_id, options)
67
+ ```
68
+
69
+ ###(Optional)
28
70
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
71
+ To configure default options:
30
72
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
73
+ ```
74
+ $ FineTune.add_limit(:hourly_emails, window: 3600, limit: 25)
75
+ ```
76
+ Options passed here will be overridden by any options passed in
77
+ the individual calls.
78
+
79
+ To remove a pre-defined rule:
80
+
81
+ ```
82
+ $ FineTune.remove_limit(:hourly_emails, window: 3600, limit: 25)
83
+ ```
84
+
85
+ ###Supported implementations:
86
+
87
+ * [Leaky Bucket algorithm](https://en.wikipedia.org/wiki/Leaky_bucket)
88
+
89
+
90
+ ## Development
91
+
92
+ After checking out the repo, run `bundle` to install dependencies. Then, run `rake test` to run the tests.
32
93
 
33
94
  ## Contributing
34
95
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fine_tune. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
96
+ Bug reports and pull requests are welcome on GitHub at https://github.com/laknath/fine_tune. This project
97
+ is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
98
+ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
99
+
100
+ ## Credits
101
+
102
+ Some of the behaviours were inspired by [Props](https://github.com/zendesk/prop).
103
+
104
+ Thanks you!
36
105
 
37
106
 
38
107
  ## License
39
108
 
40
109
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
-
data/fine_tune.gemspec CHANGED
@@ -17,9 +17,10 @@ Gem::Specification.new do |spec|
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_development_dependency "bundler", "~> 1.12"
21
- spec.add_development_dependency "rake", "~> 10.0"
20
+ spec.add_development_dependency "bundler"
21
+ spec.add_development_dependency "rake"
22
22
  spec.add_development_dependency "minitest", "~> 5.0"
23
- spec.add_development_dependency "minitest-reporters", "~> 1.1.9"
24
- spec.add_development_dependency "mocha", "~> 0.14.0"
23
+ spec.add_development_dependency "minitest-reporters", "~> 1.1"
24
+ spec.add_development_dependency "mocha", "~> 0.14"
25
+ spec.add_development_dependency "activesupport", "~> 4.2"
25
26
  end
@@ -1,15 +1,69 @@
1
+ #
2
+ # FineTune::Base provides a set of public methods and helpers to throttle
3
+ # and fetch the event count through a singleton object. The mechanism used to
4
+ # throttle and event counting is delegated to the defined strategy.
5
+ #
6
+ # Strategies can be defined for the entire library through
7
+ # FineTune.default_strategy=. Strategy can also be defined for each
8
+ # throttling call by passing <tt>:strategy</tt> option.
9
+ #
10
+ # Additionally, the datastore used to maintain event counts can be
11
+ # also customized by setting FineTune.adapter=. It takes an
12
+ # ActiveSupport::Cache::Store[http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html]
13
+ # as an adapter.
14
+
1
15
  module FineTune
2
16
  class Base
3
17
  include Singleton
4
18
 
5
- class << self; attr_accessor :default_strategy; end
19
+ class << self;
20
+ # Used to set a default strategy for all calls.
21
+ attr_accessor :default_strategy
22
+
23
+ # Used to set the external data store.
24
+ attr_accessor :adapter
25
+
26
+ def registry #:nodoc:
27
+ @@registry
28
+ end
29
+
30
+ def find_strategy(strategy) #:nodoc:
31
+ registry.fetch(strategy, default_strategy).instance
32
+ end
33
+ end
6
34
 
35
+ # Currently supported strategies:
36
+ # * Leaky bucket algorithm
7
37
  @@registry = {
8
38
  :leaky_bucket => ::FineTune::Strategies::LeakyBucket,
9
39
  :sliding_window => ::FineTune::Strategies::SlidingWindow
10
40
  }
11
41
  @default_strategy = ::FineTune::Strategies::LeakyBucket
12
42
 
43
+ # Calling throttle represents an occurance of an event.
44
+ # Depends on the strategy used for the actual calculations.
45
+ # Returns true if the event should be throttled.
46
+ #
47
+ # ==== Attributes
48
+ #
49
+ # * +name+ - Name of the rule ie: emails_sent
50
+ # * +id+ - Identifier for a specific resource ie: abc@example.com
51
+ # * +options+ - Options for the strategy. Depends on the strategy choosen
52
+ #
53
+ # ==== Options
54
+ #
55
+ # * +:strategy+ - The strategy chosen. Valid options are:
56
+ # - leaky_bucket
57
+ #
58
+ # Optionally, a block can be passed and it will be called with
59
+ # calculated values
60
+ #
61
+ # ==== Examples
62
+ # FineTune.throttle(:emails_sent, "abc@example.com",
63
+ # {strategy: :leaky_bucket}) do |count, comparison, key, strategy, options|
64
+ # # some calculation ...
65
+ # end
66
+
13
67
  def throttle(name, id, options)
14
68
  strategy, key, options = current_strategy(name, id, options)
15
69
  count = strategy.increment(key, options)
@@ -20,46 +74,72 @@ module FineTune
20
74
  comp >= 0
21
75
  end
22
76
 
23
- def throttle!(name, id, options)
24
- block = Proc.new if block_given?
77
+ # The more forceful variant of throttle. Will raise a MaxRateError if the
78
+ # defined threshold is exceeds.
79
+ #
80
+ # Attributes and options are same as for +throttle+.
25
81
 
26
- throttle(name, id, options) do |count, comp, key, strategy, options|
27
- block.call(count, comp, key, strategy, options) if block
82
+ def throttle!(name, id, options)
83
+ throttle(name, id, options) do |count, comp, key, strategy, opts|
84
+ yield count, comp, key, strategy, opts if block_given?
28
85
 
29
- raise MaxRateError.new(key, count, comp, strategy, options) if comp >= 0
86
+ raise MaxRateError.new(key, count, comp, strategy, opts) if comp >= 0
30
87
  end
31
88
  end
32
89
 
90
+ # Returns true if current count exceeds the given limits.
91
+ #
92
+ # Attributes and options are same as for +throttle+.
33
93
  def rate_exceeded?(name, id, options)
34
94
  strategy, key, options = current_strategy(name, id, options)
35
95
  strategy.compare?(strategy.count(key, options), options) >= 0
36
96
  end
37
97
 
98
+ # Returns the current event count.
99
+ #
100
+ # Attributes and options are same as for +throttle+.
38
101
  def count(name, id, options)
39
102
  strategy, key, options = current_strategy(name, id, options)
40
103
  strategy.count(key, options)
41
104
  end
42
105
 
106
+ # Resets the counter for the given resource identifer to 0.
107
+ #
108
+ # Attributes and options are same as for +throttle+.
43
109
  def reset(name, id, options)
44
110
  strategy, key, options = current_strategy(name, id, options)
45
111
  strategy.reset(key, options)
46
112
  end
47
113
 
114
+ # Adds a preconfigured rule and options to the rule. These configs
115
+ # can be overridden by passing different option values later when
116
+ # calling +throttle+.
117
+ #
118
+ # ==== Attributes
119
+ #
120
+ # * +name+ - Name of the rule ie: emails_sent
121
+ # * +options+ - Default options for the rule
122
+ #
123
+ # ==== Examples
124
+ # FineTune.add_limit(:emails_sent_per_hour, {window: 3600})
125
+ #
48
126
  def add_limit(name, options = {})
49
127
  limits[name] ||= {}
50
128
  limits[name].merge!(options)
51
129
  end
52
130
 
131
+ # Removes a preconfigured rule and options.
53
132
  def remove_limit(name)
54
133
  limits.delete(name)
55
134
  end
56
135
 
136
+ # Returns all default limits defined
57
137
  def limits
58
138
  @limits ||= {}
59
139
  end
60
140
 
61
141
  private
62
- def current_strategy(name, id, options)
142
+ def current_strategy(name, id, options) #:nodoc:
63
143
  options = (limits[name] || {}).merge(options)
64
144
  strategy = self.class.find_strategy(options[:strategy])
65
145
 
@@ -71,13 +151,5 @@ module FineTune
71
151
 
72
152
  [strategy, key, options]
73
153
  end
74
-
75
- def self.find_strategy(strategy)
76
- registry.fetch(strategy, default_strategy).instance
77
- end
78
-
79
- def self.registry
80
- @@registry
81
- end
82
154
  end
83
155
  end
@@ -1,4 +1,5 @@
1
1
  module FineTune
2
+ # MaxRateError is thrown when a defined limit has reached
2
3
  class MaxRateError < StandardError
3
4
  attr_accessor :key, :comparison, :count, :strategy, :options
4
5
 
@@ -1,5 +1,11 @@
1
1
  module FineTune
2
2
  module Strategies
3
+ # This class is only for the purpose of extending and implementing
4
+ # own strategies. Any subclass should implement:
5
+ # * +identifier+
6
+ # * +increment+
7
+ # * +count+
8
+ # * +reset+
3
9
  class Base
4
10
  include Singleton
5
11
 
@@ -8,7 +14,15 @@ module FineTune
8
14
  end
9
15
 
10
16
  def build_key(name, id, options)
11
- [name, id].flatten.join('-')
17
+ [:fine_tune, name, identifier, id].flatten.join('/')
18
+ end
19
+
20
+ def adapter
21
+ FineTune.adapter
22
+ end
23
+
24
+ def identifier
25
+ raise "not defined"
12
26
  end
13
27
 
14
28
  def increment(key, options)
@@ -20,7 +34,11 @@ module FineTune
20
34
  end
21
35
 
22
36
  def validate?(options)
23
- false
37
+ if adapter.nil?
38
+ raise "no adapter given"
39
+ end
40
+
41
+ true
24
42
  end
25
43
 
26
44
  def reset(key, options)
@@ -1,6 +1,132 @@
1
1
  module FineTune
2
2
  module Strategies
3
+
4
+ # Implements {LeakyBucket algorithm}[https://en.wikipedia.org/wiki/Leaky_bucket]
5
+ # as a FineTune::Strategy.
3
6
  class LeakyBucket < Base
7
+
8
+ class << self
9
+ # Set default values for window, average and maximum values so
10
+ # they won't need to be passed in every call
11
+ attr_accessor :default_window, :default_average, :default_maximum
12
+ end
13
+
14
+ # compares the count given and the burst value.
15
+ # Returns 0 if equal, -1 less and 1 greater
16
+ #
17
+ # ====== Attributes
18
+ #
19
+ # * +count+ - the current count
20
+ # * +options+ - Optional if default_maximum is set
21
+ #
22
+ # ====== Options
23
+ # * +:maximum - can be used to override default_maximum
24
+ def compare?(count, options)
25
+ count <=> maximum(options)
26
+ end
27
+
28
+ # Returns the current count incremented by one if it does not exceed the
29
+ # maximum value given. If it exceeds the maximum value, then it returns
30
+ # the maximum value.
31
+ #
32
+ # ====== Attributes
33
+ #
34
+ # * +key+ - the identifier for the resource in cache store
35
+ # * +options+ - Optional if default_maximum, default_window and default_average set
36
+ #
37
+ # ====== Options
38
+ # * +:maximum+ - can be used to override default_maximum ie: 20
39
+ # * +:average+ - can be used to override default_average ie: 10
40
+ # * +:window+ - can be used to override default_window ie: 3600 (one hour)
41
+ def increment(key, options)
42
+ count = count(key, options)
43
+ count = [maximum(options), count + 1].min
44
+ adapter.write(key, {count: count, timestamp: Time.now.to_i})
45
+ count
46
+ end
47
+
48
+ # Returns the current count after discounting for the time since
49
+ # last access.
50
+ #
51
+ # Attributes and options are same as +increment+
52
+ def count(key, options)
53
+ resource = adapter.fetch(key, options) do
54
+ zero_counts
55
+ end
56
+
57
+ loss = loss(Time.now.to_i, resource[:timestamp], average(options),
58
+ window(options))
59
+ count = resource[:count] - loss
60
+ count > 0 ? count : 0
61
+ end
62
+
63
+ # Validates the options given. Window, average and maximum values must be set
64
+ # either through default values or the options
65
+ #
66
+ # Options are same as +increment+
67
+ def validate?(options)
68
+ super(options)
69
+ error = nil
70
+ window, average, maximum = window(options), average(options), maximum(options)
71
+
72
+ error = if !window || !average || !maximum
73
+ "window, average and maximum options are required"
74
+ elsif !positive_integer?(window)
75
+ "time window must be a positive integer"
76
+ elsif !non_negative_numeric?(average)
77
+ "average should be non negative numbers"
78
+ elsif maximum < average
79
+ "maximum should not be less than the average"
80
+ end
81
+
82
+ raise ArgumentError.new(error) if error
83
+
84
+ true
85
+ end
86
+
87
+ # Reset the count of the resource identified by the key to 0.
88
+ #
89
+ # ====== Attributes
90
+ #
91
+ # * +key+ - the identifier for the resource in cache store
92
+ def reset(key, options)
93
+ adapter.write(key, zero_counts)
94
+ end
95
+
96
+ def identifier #:nodoc:
97
+ :leaky_bucket
98
+ end
99
+
100
+ # calculates the loss given an average, window and a time interval
101
+ def loss(now, last_accessed, average, window)
102
+ loss = ((now - last_accessed) * average).to_f/window
103
+ loss > 0 ? loss : 0
104
+ end
105
+
106
+ private
107
+ def zero_counts #:nodoc:
108
+ {count: 0, timestamp: Time.now.to_i}
109
+ end
110
+
111
+ def window(options) #:nodoc:
112
+ options[:window] || self.class.default_window
113
+ end
114
+
115
+ def average(options) #:nodoc:
116
+ options[:average] || self.class.default_average
117
+ end
118
+
119
+ def maximum(options) #:nodoc:
120
+ options[:maximum] || options[:limit] || self.class.default_maximum
121
+ end
122
+
123
+ def positive_integer?(e) #:nodoc:
124
+ e.is_a?(Integer) && e > 0
125
+ end
126
+
127
+ def non_negative_numeric?(e) #:nodoc:
128
+ e.is_a?(Numeric) && e >= 0
129
+ end
4
130
  end
5
131
  end
6
132
  end
@@ -1,3 +1,3 @@
1
1
  module FineTune
2
- VERSION = "0.1.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/fine_tune.rb CHANGED
@@ -1,3 +1,8 @@
1
+ #
2
+ # Author:: Laknath Semage (blaknath at gmail dot com)
3
+ # Copyright:: Copyright (c) 2016 Vesess Inc.
4
+ # License:: MIT License
5
+
1
6
  require "fine_tune/version"
2
7
  require 'singleton'
3
8
  require "forwardable"
@@ -8,11 +13,18 @@ end
8
13
  require "fine_tune/base"
9
14
  require "fine_tune/max_rate_error"
10
15
 
16
+ ##
17
+ # FineTune helps throttle any kind of event sequence. It also supports
18
+ # custom throttling strategies using a common API. By default
19
+ # it supports LeakyBucket[https://en.wikipedia.org/wiki/Leaky_bucket] algorithm.
20
+
11
21
  module FineTune
12
22
  class << self
13
23
  extend Forwardable
14
- def_delegators :"FineTune::Base.instance", :adapter, :adapter=, :count,
15
- :reset, :throttle, :throttle!, :add_limit, :remove_limit, :rate_exceeded?
24
+ def_delegators :"FineTune::Base.instance", :count, :reset, :throttle,
25
+ :throttle!, :add_limit, :remove_limit, :rate_exceeded?
26
+ def_delegators :"FineTune::Base", :adapter, :adapter=, :default_strategy,
27
+ :default_strategy=
16
28
  end
17
29
  end
18
30
 
metadata CHANGED
@@ -1,85 +1,112 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fine_tune
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Laknath Semage
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-06-27 00:00:00.000000000 Z
12
+ date: 2016-07-04 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - "~>"
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
- version: '1.12'
21
+ version: '0'
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - "~>"
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
- version: '1.12'
29
+ version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rake
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - "~>"
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
- version: '10.0'
37
+ version: '0'
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - "~>"
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
- version: '10.0'
45
+ version: '0'
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: minitest
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - "~>"
51
+ - - ~>
46
52
  - !ruby/object:Gem::Version
47
53
  version: '5.0'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - "~>"
59
+ - - ~>
53
60
  - !ruby/object:Gem::Version
54
61
  version: '5.0'
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: minitest-reporters
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - "~>"
67
+ - - ~>
60
68
  - !ruby/object:Gem::Version
61
- version: 1.1.9
69
+ version: '1.1'
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - "~>"
75
+ - - ~>
67
76
  - !ruby/object:Gem::Version
68
- version: 1.1.9
77
+ version: '1.1'
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: mocha
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
- - - "~>"
83
+ - - ~>
74
84
  - !ruby/object:Gem::Version
75
- version: 0.14.0
85
+ version: '0.14'
76
86
  type: :development
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
- - - "~>"
91
+ - - ~>
81
92
  - !ruby/object:Gem::Version
82
- version: 0.14.0
93
+ version: '0.14'
94
+ - !ruby/object:Gem::Dependency
95
+ name: activesupport
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '4.2'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '4.2'
83
110
  description: A rate limiter without the worst case throttling of two times the defined
84
111
  threshold.
85
112
  email:
@@ -88,8 +115,9 @@ executables: []
88
115
  extensions: []
89
116
  extra_rdoc_files: []
90
117
  files:
91
- - ".gitignore"
92
- - ".travis.yml"
118
+ - .gitignore
119
+ - .ruby-version
120
+ - .travis.yml
93
121
  - Gemfile
94
122
  - LICENSE.txt
95
123
  - README.md
@@ -105,25 +133,26 @@ files:
105
133
  homepage: https://github.com/vesess/fine_tune
106
134
  licenses:
107
135
  - MIT
108
- metadata: {}
109
136
  post_install_message:
110
137
  rdoc_options: []
111
138
  require_paths:
112
139
  - lib
113
140
  required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
114
142
  requirements:
115
- - - ">="
143
+ - - ! '>='
116
144
  - !ruby/object:Gem::Version
117
145
  version: '0'
118
146
  required_rubygems_version: !ruby/object:Gem::Requirement
147
+ none: false
119
148
  requirements:
120
- - - ">="
149
+ - - ! '>='
121
150
  - !ruby/object:Gem::Version
122
151
  version: '0'
123
152
  requirements: []
124
153
  rubyforge_project:
125
- rubygems_version: 2.2.5
154
+ rubygems_version: 1.8.23
126
155
  signing_key:
127
- specification_version: 4
156
+ specification_version: 3
128
157
  summary: Limits rate of a given event sequence with defined strategies.
129
158
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 084b2f0a33fb235fae26629c06c4d3ea49832456
4
- data.tar.gz: 36428f60b499e91fca15c2208edbb93b2ae21ec2
5
- SHA512:
6
- metadata.gz: ef657f44b8ccc3516998568101b3192103f0591a81171875bf626718137d88ae2a79c804ac47893fa0d42abad4f34cebf3ee0dcad12db9ebfc52c2ed9d57d130
7
- data.tar.gz: e41b1821a9e08b4d3323e7fc52a66ce353a3669946444c8316997a2988e5bca99dc0f93ef807f9a3c5e1131e7a98d4367f1555a6d2d2f6fb21829f304c9f3367