rolling-limit 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f170a253aa712039baf7c2b5e8ffe46d053debf3
4
+ data.tar.gz: 328cef9090ecb66f75a88a0c8df5906084fb3c19
5
+ SHA512:
6
+ metadata.gz: 7866c7cd9ab62f77ab78ea56040426f8c8402e10b4099dda72aa1cc21a50b2e6380cad82ccc5e18c42ffea62d4fecd35c55f370f32331f56fd2f1f485cf12f65
7
+ data.tar.gz: 339d23968de457e8a63b0713bf729355499a76b760f1aca71f19d85dd67315db3918e4fe468a9033f2f457b35d547c9faa14d726ab08b92c321b371197a06d02
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,63 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-08-11 22:14:45 +0100 using RuboCop version 0.39.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.1
11
+
12
+ # Offense count: 6
13
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
14
+ # URISchemes: http, https
15
+ Metrics/LineLength:
16
+ Max: 104
17
+
18
+ # Offense count: 1
19
+ # Cop supports --auto-correct.
20
+ Style/EmptyLines:
21
+ Exclude:
22
+ - 'spec/rolling/limit_spec.rb'
23
+
24
+ # Offense count: 1
25
+ # Cop supports --auto-correct.
26
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
27
+ # SupportedStyles: empty_lines, no_empty_lines
28
+ Style/EmptyLinesAroundBlockBody:
29
+ Exclude:
30
+ - 'spec/rolling/limit_spec.rb'
31
+
32
+ # Offense count: 1
33
+ # Cop supports --auto-correct.
34
+ # Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues.
35
+ # SupportedStyles: ruby19, ruby19_no_mixed_keys, hash_rockets
36
+ Style/HashSyntax:
37
+ Enabled: false
38
+
39
+ # Offense count: 1
40
+ # Cop supports --auto-correct.
41
+ Style/MutableConstant:
42
+ Exclude:
43
+ - 'lib/rolling/limit/version.rb'
44
+
45
+ # Offense count: 2
46
+ # Cop supports --auto-correct.
47
+ # Configuration parameters: PreferredDelimiters.
48
+ Style/PercentLiteralDelimiters:
49
+ Exclude:
50
+ - 'rolling-limit.gemspec'
51
+
52
+ # Offense count: 18
53
+ # Cop supports --auto-correct.
54
+ # Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
55
+ # SupportedStyles: single_quotes, double_quotes
56
+ Style/StringLiterals:
57
+ Enabled: false
58
+
59
+ # Offense count: 2
60
+ # Cop supports --auto-correct.
61
+ Style/UnneededPercentQ:
62
+ Exclude:
63
+ - 'rolling-limit.gemspec'
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rolling-limit.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Rolling::Limit
2
+
3
+ A redis-backed rate limiter, using redis sorted sets.
4
+
5
+ ````ruby
6
+ require 'rolling/limit'
7
+
8
+ rl = Rolling::Limit.new(redis: connection, key: "unique key",
9
+ max_operations: 5, timespan: 60)
10
+
11
+ rl.remaining # => 4
12
+ rl.remaining # => 3
13
+ rl.remaining # => 2
14
+ rl.remaining # => 1
15
+ rl.remaining # => 0
16
+ rl.remaining # => false
17
+ # ... 61s later
18
+ rl.remaining # => 4
19
+ ````
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'rolling-limit'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install rolling-limit
36
+
37
+ ## Usage
38
+
39
+ TODO: Write usage instructions here
40
+
41
+ ## Development
42
+
43
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
44
+
45
+ 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).
46
+
47
+ ## Contributing
48
+
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/livelink/rolling-limit.
50
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rolling/limit"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ module Rolling
2
+ class Limit
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,67 @@
1
+ require 'rolling/limit/version'
2
+ require 'redis'
3
+
4
+ module Rolling
5
+ # Rolling::Limit is a class that maintains a rolling limit of no more than
6
+ # <max_operations> operations for a given <key> within <timespan> seconds.
7
+ class Limit
8
+ def initialize(redis:, key:, max_operations:, timespan:)
9
+ @redis = redis
10
+ @key = "rlmt:#{key}"
11
+ @timespan = timespan
12
+ @max_operations = max_operations.to_i
13
+ end
14
+
15
+ # Increments the counter and returns truthy (with number of remaining
16
+ # operations)
17
+ def remaining
18
+ cleanup
19
+ return false if count >= max_operations
20
+ increment
21
+ max_operations - count
22
+ end
23
+
24
+ # Resets this counter
25
+ def reset!
26
+ redis.del(key)
27
+ end
28
+
29
+ # Shows numbers of remaining operations without incrementing
30
+ def remaining?
31
+ cleanup
32
+ return false if count >= max_operations
33
+ true
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :key, :timespan, :max_operations, :redis
39
+
40
+ # Ensure this key lives for at least <timespan>
41
+ def autoexpire
42
+ redis.expire(key, timespan)
43
+ end
44
+
45
+ # Delete operations that are older than time - timespan
46
+ def cleanup
47
+ redis.zremrangebyscore(key, '-inf', time - timespan)
48
+ end
49
+
50
+ def time
51
+ Time.now.to_i
52
+ end
53
+
54
+ def unique_key
55
+ "#{Time.now.to_f}.#{rand}"
56
+ end
57
+
58
+ def count
59
+ redis.zcard(key)
60
+ end
61
+
62
+ def increment
63
+ redis.zadd(key, time, unique_key)
64
+ autoexpire
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rolling/limit/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rolling-limit"
8
+ spec.version = Rolling::Limit::VERSION
9
+ spec.authors = ["Geoff Youngs"]
10
+ spec.email = ["git@intersect-uk.co.uk"]
11
+ spec.licenses = ['MIT']
12
+
13
+ spec.summary = %q{A redis-based rolling rate limiter}
14
+ spec.description = %q{Uses redis sorted sets to allow easy rate limiting}
15
+ spec.homepage = "https://github.com/livelink/rolling-limit"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org/"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "redis", "~> 1.12"
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rolling-limit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Geoff Youngs
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.12'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Uses redis sorted sets to allow easy rate limiting
70
+ email:
71
+ - git@intersect-uk.co.uk
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".rubocop.yml"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - lib/rolling/limit.rb
86
+ - lib/rolling/limit/version.rb
87
+ - rolling-limit.gemspec
88
+ homepage: https://github.com/livelink/rolling-limit
89
+ licenses:
90
+ - MIT
91
+ metadata:
92
+ allowed_push_host: https://rubygems.org/
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.5.1
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A redis-based rolling rate limiter
113
+ test_files: []