glutton_ratelimit 0.2.0 → 1.0.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/Rakefile CHANGED
@@ -1,52 +1,50 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "glutton_ratelimit"
8
- gem.summary = %Q{Simple Ruby library for self-imposed rater-limiting.}
9
- gem.description = %Q{A Ruby library for limiting the number of times a method can be invoked within a specified time period.}
10
- gem.email = "stungeye@gmail.com"
11
- gem.homepage = "http://github.com/stungeye/glutton_ratelimit"
12
- gem.authors = ["Wally Glutton"]
13
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
- end
15
- Jeweler::GemcutterTasks.new
16
- rescue LoadError
17
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
- end
19
-
20
- require 'rake/testtask'
21
- Rake::TestTask.new(:test) do |test|
22
- test.libs << 'lib' << 'test'
23
- test.pattern = 'test/**/test_*.rb'
24
- test.verbose = true
25
- end
26
-
27
- begin
28
- require 'rcov/rcovtask'
29
- Rcov::RcovTask.new do |test|
30
- test.libs << 'test'
31
- test.pattern = 'test/**/test_*.rb'
32
- test.verbose = true
33
- end
34
- rescue LoadError
35
- task :rcov do
36
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
- end
38
- end
39
-
40
- task :test => :check_dependencies
41
-
42
- task :default => :test
43
-
44
- require 'rake/rdoctask'
45
- Rake::RDocTask.new do |rdoc|
46
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
-
48
- rdoc.rdoc_dir = 'rdoc'
49
- rdoc.title = "glutton_ratelimit #{version}"
50
- rdoc.rdoc_files.include('README*')
51
- rdoc.rdoc_files.include('lib/**/*.rb')
52
- end
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "glutton_ratelimit"
8
+ gem.summary = %Q{Simple Ruby library for self-imposed rater-limiting.}
9
+ gem.description = %Q{A Ruby library for limiting the number of times a method can be invoked within a specified time period.}
10
+ gem.email = "stungeye@gmail.com"
11
+ gem.homepage = "http://github.com/stungeye/glutton_ratelimit"
12
+ gem.authors = ["Wally Glutton"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/test_*.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+ task :default => :test
41
+
42
+ require 'rdoc/task'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "glutton_ratelimit #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 1.0.0
@@ -1,34 +1,34 @@
1
- require 'rubygems'
2
- require 'glutton_ratelimit'
3
-
4
- class LimitInstanceMethods
5
- extend GluttonRatelimit
6
-
7
- def initialize
8
- @start = Time.now
9
- end
10
-
11
- def limit_me
12
- puts "#{Time.now - @start}"
13
- sleep 0.001
14
- end
15
-
16
- def cap_me
17
- puts "#{Time.now - @start}"
18
- sleep 0.001
19
- end
20
-
21
- rate_limit :limit_me, 6, 6
22
- rate_limit :cap_me, 6, 6, GluttonRatelimit::BurstyTokenBucket
23
- end
24
-
25
- t = LimitInstanceMethods.new
26
-
27
- puts "Six requests every 6 seconds (Averaged): "
28
- 13.times { t.limit_me }
29
- puts "Six requests every 6 seconds (Bursty): "
30
- 13.times { t.cap_me }
31
-
32
- # In both cases:
33
- # The 7th execution should occur after 6 seconds after the first.
1
+ require 'rubygems'
2
+ require 'glutton_ratelimit'
3
+
4
+ class LimitInstanceMethods
5
+ extend GluttonRatelimit
6
+
7
+ def initialize
8
+ @start = Time.now
9
+ end
10
+
11
+ def limit_me
12
+ puts "#{Time.now - @start}"
13
+ sleep 0.001
14
+ end
15
+
16
+ def cap_me
17
+ puts "#{Time.now - @start}"
18
+ sleep 0.001
19
+ end
20
+
21
+ rate_limit :limit_me, 6, 6
22
+ rate_limit :cap_me, 6, 6, GluttonRatelimit::BurstyTokenBucket
23
+ end
24
+
25
+ t = LimitInstanceMethods.new
26
+
27
+ puts "Six requests every 6 seconds (Averaged): "
28
+ 13.times { t.limit_me }
29
+ puts "Six requests every 6 seconds (Bursty): "
30
+ 13.times { t.cap_me }
31
+
32
+ # In both cases:
33
+ # The 7th execution should occur after 6 seconds after the first.
34
34
  # The 13th execution should occur after 12 seconds after the first.
@@ -1,32 +1,32 @@
1
- # $LOAD_PATH << File.dirname(__FILE__) +'/../lib'
2
- require 'rubygems'
3
- require 'glutton_ratelimit'
4
-
5
- puts "Maximum of 12 executions every 5 seconds (Bursty):"
6
- rl = GluttonRatelimit::BurstyTokenBucket.new 12, 5
7
-
8
- start = Time.now
9
- n = 0
10
-
11
- rl.times(25) do
12
- puts "#{n += 1} - #{Time.now - start}"
13
- # Simulating a constant-time task:
14
- sleep 0.1
15
- end
16
-
17
- # The 25th execution should occur after 10 seconds has elapsed.
18
-
19
- puts "Maximum of 3 executions every 3 seconds (Averaged):"
20
- rl = GluttonRatelimit::AveragedThrottle.new 3, 3
21
- # AverageThrottle will attempt to evenly space executions within the allowed period.
22
-
23
- start = Time.now
24
- n = 0
25
-
26
- rl.times(7) do
27
- puts "#{n += 1} - #{Time.now - start}"
28
- # Simulating a 0 to 1 second random-time task:
29
- sleep rand
30
- end
31
-
1
+ # $LOAD_PATH << File.dirname(__FILE__) +'/../lib'
2
+ require 'rubygems'
3
+ require 'glutton_ratelimit'
4
+
5
+ puts "Maximum of 12 executions every 5 seconds (Bursty):"
6
+ rl = GluttonRatelimit::BurstyTokenBucket.new 12, 5
7
+
8
+ start = Time.now
9
+ n = 0
10
+
11
+ rl.times(25) do
12
+ puts "#{n += 1} - #{Time.now - start}"
13
+ # Simulating a constant-time task:
14
+ sleep 0.1
15
+ end
16
+
17
+ # The 25th execution should occur after 10 seconds has elapsed.
18
+
19
+ puts "Maximum of 3 executions every 3 seconds (Averaged):"
20
+ rl = GluttonRatelimit::AveragedThrottle.new 3, 3
21
+ # AverageThrottle will attempt to evenly space executions within the allowed period.
22
+
23
+ start = Time.now
24
+ n = 0
25
+
26
+ rl.times(7) do
27
+ puts "#{n += 1} - #{Time.now - start}"
28
+ # Simulating a 0 to 1 second random-time task:
29
+ sleep rand
30
+ end
31
+
32
32
  # The 7th execution should occur after 6 seconds has elapsed.
@@ -1,64 +1,64 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = %q{glutton_ratelimit}
8
- s.version = "0.1.0"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Wally Glutton"]
12
- s.date = %q{2010-06-10}
13
- s.description = %q{A Ruby library for limiting the number of times a method can be invoked within a specified time period.}
14
- s.email = %q{stungeye@gmail.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "examples/limit_instance_methods.rb",
27
- "examples/simple_manual.rb",
28
- "glutton_ratelimit.gemspec",
29
- "lib/glutton_ratelimit.rb",
30
- "lib/glutton_ratelimit/averaged_throttle.rb",
31
- "lib/glutton_ratelimit/bursty_ring_buffer.rb",
32
- "lib/glutton_ratelimit/bursty_token_bucket.rb",
33
- "test/helper.rb",
34
- "test/test_glutton_ratelimit_averaged_throttle.rb",
35
- "test/test_glutton_ratelimit_bursty_ring_buffer.rb",
36
- "test/test_glutton_ratelimit_bursty_token_bucket.rb",
37
- "test/testing_module.rb"
38
- ]
39
- s.homepage = %q{http://github.com/stungeye/glutton_ratelimit}
40
- s.rdoc_options = ["--charset=UTF-8"]
41
- s.require_paths = ["lib"]
42
- s.rubygems_version = %q{1.3.6}
43
- s.summary = %q{Simple Ruby library for self-imposed rater-limiting.}
44
- s.test_files = [
45
- "test/test_glutton_ratelimit_averaged_throttle.rb",
46
- "test/helper.rb",
47
- "test/test_glutton_ratelimit_bursty_ring_buffer.rb",
48
- "test/testing_module.rb",
49
- "test/test_glutton_ratelimit_bursty_token_bucket.rb",
50
- "examples/limit_instance_methods.rb",
51
- "examples/simple_manual.rb"
52
- ]
53
-
54
- if s.respond_to? :specification_version then
55
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
- s.specification_version = 3
57
-
58
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
- else
60
- end
61
- else
62
- end
63
- end
64
-
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: glutton_ratelimit 1.0.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "glutton_ratelimit".freeze
9
+ s.version = "1.0.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Wally Glutton".freeze]
14
+ s.date = "2019-12-19"
15
+ s.description = "A Ruby library for limiting the number of times a method can be invoked within a specified time period.".freeze
16
+ s.email = "stungeye@gmail.com".freeze
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".github/workflows/ruby.yml",
24
+ ".ruby-version",
25
+ ".travis.yml",
26
+ "Gemfile",
27
+ "Gemfile.lock",
28
+ "LICENSE",
29
+ "README.rdoc",
30
+ "Rakefile",
31
+ "VERSION",
32
+ "examples/limit_instance_methods.rb",
33
+ "examples/simple_manual.rb",
34
+ "glutton_ratelimit.gemspec",
35
+ "lib/glutton_ratelimit.rb",
36
+ "lib/glutton_ratelimit/averaged_throttle.rb",
37
+ "lib/glutton_ratelimit/bursty_ring_buffer.rb",
38
+ "lib/glutton_ratelimit/bursty_token_bucket.rb",
39
+ "test/helper.rb",
40
+ "test/test_glutton_ratelimit_averaged_throttle.rb",
41
+ "test/test_glutton_ratelimit_bursty_ring_buffer.rb",
42
+ "test/test_glutton_ratelimit_bursty_token_bucket.rb",
43
+ "test/testing_module.rb"
44
+ ]
45
+ s.homepage = "http://github.com/stungeye/glutton_ratelimit".freeze
46
+ s.rubygems_version = "2.7.6.2".freeze
47
+ s.summary = "Simple Ruby library for self-imposed rater-limiting.".freeze
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 4
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<jeweler>.freeze, [">= 0"])
54
+ s.add_runtime_dependency(%q<test-unit>.freeze, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<jeweler>.freeze, [">= 0"])
57
+ s.add_dependency(%q<test-unit>.freeze, [">= 0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<jeweler>.freeze, [">= 0"])
61
+ s.add_dependency(%q<test-unit>.freeze, [">= 0"])
62
+ end
63
+ end
64
+
@@ -1,38 +1,39 @@
1
- module GluttonRatelimit
2
-
3
- def rate_limit symbol, executions, time_period, rl_class = AveragedThrottle
4
- rl = rl_class.new executions, time_period
5
- old_symbol = "#{symbol}_old".to_sym
6
- alias_method old_symbol, symbol
7
- define_method symbol do |*args|
8
- rl.wait
9
- self.send old_symbol, *args
10
- end
11
- end
12
-
13
- private
14
- # All the other classes extend this parent and are therefore
15
- # constructed in the same manner.
16
- class ParentLimiter
17
- attr_reader :executions
18
-
19
- def initialize executions, time_period
20
- @executions = executions
21
- @time_period = time_period
22
- end
23
-
24
- def times(num, &block)
25
- raise ArgumentError, "Code block expected" if not block
26
- raise ArgumentError, "Parameter expected to be Fixnum but found a #{num.class}." unless num.class.equal?(Fixnum)
27
- num.times do
28
- wait
29
- yield
30
- end
31
- end
32
- end
33
- end
34
-
35
- dir = File.expand_path(File.dirname(__FILE__))
36
- require File.join(dir, "glutton_ratelimit", "bursty_ring_buffer")
37
- require File.join(dir, "glutton_ratelimit", "bursty_token_bucket")
38
- require File.join(dir, "glutton_ratelimit", "averaged_throttle")
1
+ module GluttonRatelimit
2
+
3
+ def rate_limit symbol, executions, time_period, rl_class = AveragedThrottle
4
+ rl = rl_class.new executions, time_period
5
+ old_symbol = "#{symbol}_old".to_sym
6
+ alias_method old_symbol, symbol
7
+ define_method symbol do |*args|
8
+ rl.wait
9
+ self.send old_symbol, *args
10
+ end
11
+ end
12
+
13
+ private
14
+ # All the other classes extend this parent and are therefore
15
+ # constructed in the same manner.
16
+ class ParentLimiter
17
+ attr_reader :executions
18
+
19
+ def initialize executions, time_period
20
+ @executions = executions
21
+ @time_period = time_period
22
+ end
23
+
24
+ def times(num, &block)
25
+ raise ArgumentError, "Code block expected" if not block
26
+
27
+ raise ArgumentError, "Parameter expected to be #{Integer.to_s} but found a #{num.class}." unless num.kind_of?(Integer)
28
+ num.times do
29
+ wait
30
+ yield
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ dir = File.expand_path(File.dirname(__FILE__))
37
+ require File.join(dir, "glutton_ratelimit", "bursty_ring_buffer")
38
+ require File.join(dir, "glutton_ratelimit", "bursty_token_bucket")
39
+ require File.join(dir, "glutton_ratelimit", "averaged_throttle")
@@ -1,44 +1,45 @@
1
- module GluttonRatelimit
2
-
3
- class AveragedThrottle < ParentLimiter
4
-
5
- def reset_bucket
6
- @before_previous_execution = Time.now if @before_previous_execution.nil?
7
- @oldest_timestamp = Time.now
8
- @tokens = @executions
9
- @total_task_time = 0
10
- end
11
-
12
- def executed_this_period
13
- @executions - @tokens
14
- end
15
-
16
- def average_task_time
17
- @total_task_time.to_f / executed_this_period
18
- end
19
-
20
- def wait
21
- reset_bucket if @tokens.nil?
22
-
23
- now = Time.now
24
- delta_since_previous = now - @before_previous_execution
25
- @total_task_time += delta_since_previous
26
- remaining_time = @time_period - (now - @oldest_timestamp)
27
-
28
- if @tokens.zero?
29
- sleep(remaining_time) if remaining_time > 0
30
- reset_bucket
31
- elsif executed_this_period != 0
32
- throttle = (remaining_time.to_f + delta_since_previous) / (@tokens+1) - average_task_time
33
- sleep throttle if throttle > 0
34
- end
35
-
36
- @tokens -= 1
37
- @before_previous_execution = Time.now
38
- end
39
-
40
- end
41
-
42
- end
43
-
44
-
1
+ module GluttonRatelimit
2
+ class AveragedThrottle < ParentLimiter
3
+ def initialize executions, time_period
4
+ super(executions, time_period)
5
+ @tokens = nil
6
+ end
7
+
8
+ def reset_bucket
9
+ @before_previous_execution ||= Time.now
10
+ @oldest_timestamp = Time.now
11
+ @tokens = @executions
12
+ @total_task_time = 0
13
+ end
14
+
15
+ def executed_this_period
16
+ @executions - @tokens
17
+ end
18
+
19
+ def average_task_time
20
+ @total_task_time.to_f / executed_this_period
21
+ end
22
+
23
+ def wait
24
+ reset_bucket if @tokens.nil?
25
+
26
+ now = Time.now
27
+ delta_since_previous = now - @before_previous_execution
28
+ @total_task_time += delta_since_previous
29
+ remaining_time = @time_period - (now - @oldest_timestamp)
30
+
31
+ if @tokens.zero?
32
+ sleep(remaining_time) if remaining_time > 0
33
+ reset_bucket
34
+ elsif executed_this_period != 0
35
+ throttle = (remaining_time.to_f + delta_since_previous) / (@tokens+1) - average_task_time
36
+ sleep throttle if throttle > 0
37
+ end
38
+
39
+ @tokens -= 1
40
+ @before_previous_execution = Time.now
41
+ end
42
+ end
43
+ end
44
+
45
+