fine_tune 0.1.0 → 0.3.0

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