redis-prescription 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e4c70dac256ca079b9af76b03cefc189db30507860c0a6816ddd519da7bdd75a
4
+ data.tar.gz: a1c5e2fe3645bd592f26a00a16accf2be1d0340468c4f824e06c7da51f1d29eb
5
+ SHA512:
6
+ metadata.gz: a1f3988eb35db89865af75881b7bd0e33cb4a922fa468589f8f9de3396ac88118405b400ac8999995648ed92a224f768f2fc88a19d3a75d6c54145c9f01488b1
7
+ data.tar.gz: 19a72258d2adf1bef91b436965ebcea477a886cc4c9e269e81f5cffe489b406811f9fc7c46088bfc02071c720fecc016c819b48e297bd8b602e6ce11d21d31fd
@@ -0,0 +1,10 @@
1
+ /Gemfile.lock
2
+
3
+ /.autoenv.zsh
4
+ /.bundle
5
+ /.yardoc
6
+ /_yardoc
7
+ /coverage
8
+ /doc
9
+ /pkg
10
+ /tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1,40 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ DisplayCopNames: true
4
+
5
+
6
+ ## Layout ######################################################################
7
+
8
+ Layout/DotPosition:
9
+ EnforcedStyle: trailing
10
+
11
+ Layout/IndentArray:
12
+ EnforcedStyle: consistent
13
+
14
+
15
+ ## Metrics #####################################################################
16
+
17
+ Metrics/BlockLength:
18
+ Exclude:
19
+ - "spec/**/*"
20
+
21
+
22
+ ## Style #######################################################################
23
+
24
+ Style/HashSyntax:
25
+ EnforcedStyle: hash_rockets
26
+
27
+ Style/RegexpLiteral:
28
+ EnforcedStyle: percent_r
29
+
30
+ Style/RescueStandardError:
31
+ EnforcedStyle: implicit
32
+
33
+ Style/SafeNavigation:
34
+ Enabled: false
35
+
36
+ Style/StringLiterals:
37
+ EnforcedStyle: double_quotes
38
+
39
+ Style/YodaCondition:
40
+ Enabled: false
@@ -0,0 +1,28 @@
1
+ language: ruby
2
+ sudo: false
3
+
4
+ services:
5
+ - redis-server
6
+
7
+ cache: bundler
8
+
9
+ rvm:
10
+ - 2.3
11
+ - 2.4
12
+ - 2.5
13
+
14
+ matrix:
15
+ fast_finish: true
16
+ include:
17
+ - rvm: 2.4
18
+ env: TEST_SUITE="rubocop"
19
+
20
+ before_install:
21
+ - gem update --system
22
+ - gem --version
23
+ - gem install bundler --no-rdoc --no-ri
24
+ - bundle --version
25
+
26
+ install: bundle install --without development doc
27
+
28
+ script: bundle exec rake $TEST_SUITE
@@ -0,0 +1,2 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
data/Gemfile ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ ruby RUBY_VERSION
5
+
6
+ gem "rake"
7
+ gem "rspec"
8
+ gem "rubocop", "~> 0.52.0", :require => false
9
+
10
+ gem "redis"
11
+ gem "redis-namespace"
12
+
13
+ group :development do
14
+ gem "guard", :require => false
15
+ gem "guard-rspec", :require => false
16
+ gem "guard-rubocop", :require => false
17
+ gem "pry", :require => false
18
+ end
19
+
20
+ group :test do
21
+ gem "codecov", :require => false
22
+ gem "simplecov", :require => false
23
+ end
24
+
25
+ group :doc do
26
+ gem "redcarpet"
27
+ gem "yard"
28
+ end
29
+
30
+ # Specify your gem's dependencies in redis-prescription.gemspec
31
+ gemspec
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, :cmd => "bundle exec rspec" do
4
+ require "guard/rspec/dsl"
5
+ dsl = Guard::RSpec::Dsl.new(self)
6
+
7
+ # RSpec files
8
+ rspec = dsl.rspec
9
+ watch(rspec.spec_helper) { rspec.spec_dir }
10
+ watch(rspec.spec_support) { rspec.spec_dir }
11
+ watch(rspec.spec_files)
12
+
13
+ # Ruby files
14
+ ruby = dsl.ruby
15
+ dsl.watch_spec_files_for(ruby.lib_files)
16
+ end
17
+
18
+ guard :rubocop do
19
+ watch(%r{.+\.rb$})
20
+ watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
21
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Alexey Zapparov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,89 @@
1
+ # Redis::Prescription
2
+
3
+ Redis LUA stored procedure runner. Preloads (and reloads when needed, e.g. when
4
+ scripts were flushed away) script and then runs it with `EVALSHA`.
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "redis-prescription"
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install redis-prescription
22
+
23
+
24
+ ## Usage
25
+
26
+ ``` ruby
27
+ script = Redis::Prescription.new <<~LUA
28
+ return tonumber(redis.call('GET', KEYS[1]) or 42)
29
+ LUA
30
+
31
+ script.eval(Redis.current, :xxx) # => 42
32
+
33
+ Redis.current.set(:xxx, 123)
34
+ script.eval(Redis.current, :xxx) # => 123
35
+ ```
36
+
37
+
38
+ ## Supported Ruby Versions
39
+
40
+ This library aims to support and is [tested against][1] the following Ruby
41
+ versions:
42
+
43
+ * Ruby 2.3.x
44
+ * Ruby 2.4.x
45
+ * Ruby 2.5.x
46
+
47
+ If something doesn't work on one of these versions, it's a bug.
48
+
49
+ This library may inadvertently work (or seem to work) on other Ruby versions,
50
+ however support will only be provided for the versions listed above.
51
+
52
+ If you would like this library to support another Ruby version or
53
+ implementation, you may volunteer to be a maintainer. Being a maintainer
54
+ entails making sure all tests run and pass on that implementation. When
55
+ something breaks on your implementation, you will be responsible for providing
56
+ patches in a timely fashion. If critical issues for a particular implementation
57
+ exist at the time of a major release, support for that Ruby version may be
58
+ dropped.
59
+
60
+
61
+ ## Development
62
+
63
+ After checking out the repo, run `bundle install` to install dependencies.
64
+ Then, run `bundle exec rake spec` to run the tests with ruby-rb client.
65
+
66
+ To install this gem onto your local machine, run `bundle exec rake install`.
67
+ To release a new version, update the version number in `version.rb`, and then
68
+ run `bundle exec rake release`, which will create a git tag for the version,
69
+ push git commits and tags, and push the `.gem` file to [rubygems.org][2].
70
+
71
+
72
+ ## Contributing
73
+
74
+ * Fork sidekiq-throttled on GitHub
75
+ * Make your changes
76
+ * Ensure all tests pass (`bundle exec rake`)
77
+ * Send a pull request
78
+ * If we like them we'll merge them
79
+ * If we've accepted a patch, feel free to ask for commit access!
80
+
81
+
82
+ ## Copyright
83
+
84
+ Copyright (c) 2018 SensorTower Inc.
85
+ See LICENSE.md for further details.
86
+
87
+
88
+ [1]: http://travis-ci.org/sensortower/redis-prescription
89
+ [2]: https://rubygems.org
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rspec/core/rake_task"
6
+ RSpec::Core::RakeTask.new
7
+
8
+ require "rubocop/rake_task"
9
+ RuboCop::RakeTask.new
10
+
11
+ if ENV["CI"]
12
+ task :default => :spec
13
+ else
14
+ task :default => %i[rubocop spec]
15
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "prescription/version"
4
+
5
+ # @see https://github.com/redis/redis-rb
6
+ class Redis
7
+ # Lua script executor for redis.
8
+ #
9
+ # Instead of executing script with `EVAL` everytime - loads script once
10
+ # and then runs it with `EVALSHA`.
11
+ #
12
+ # @example Usage
13
+ #
14
+ # script = Redis::Prescription.new("return ARGV[1] + ARGV[2]")
15
+ # script.eval(Redis.current, :argv => [2, 2]) # => 2
16
+ class Prescription
17
+ # Script load command.
18
+ LOAD = "load"
19
+ private_constant :LOAD
20
+
21
+ # Redis error fired when script ID is unkown.
22
+ NOSCRIPT = "NOSCRIPT"
23
+ private_constant :NOSCRIPT
24
+
25
+ # LUA script source.
26
+ # @return [String]
27
+ attr_reader :source
28
+
29
+ # LUA script SHA1 digest.
30
+ # @return [String]
31
+ attr_reader :digest
32
+
33
+ # @param source [#to_s] Lua script.
34
+ def initialize(source)
35
+ @source = source.to_s.strip.freeze
36
+ @digest = Digest::SHA1.hexdigest(@source).freeze
37
+ end
38
+
39
+ # Loads script to redis.
40
+ # @param redis (see #namespaceless)
41
+ # @return [void]
42
+ def bootstrap!(redis)
43
+ digest = namespaceless(redis).script(LOAD, @source)
44
+ return if @digest == digest
45
+
46
+ # XXX: this may happen **ONLY** if script digesting will be
47
+ # changed in redis, which is not likely gonna happen.
48
+ warn "[#{self.class}] Unexpected digest: " \
49
+ "#{digest.inspect} (expected: #{@digest.inspect})"
50
+
51
+ @digest = digest.freeze
52
+ end
53
+
54
+ # Executes script and returns result of execution.
55
+ # @param redis (see #namespaceless)
56
+ # @param keys [Array] keys to pass to the script
57
+ # @param argv [Array] arguments to pass to the script
58
+ # @return depends on the script
59
+ def eval(redis, keys: [], argv: [])
60
+ redis.evalsha(@digest, keys, argv)
61
+ rescue => e
62
+ raise unless e.message.include? NOSCRIPT
63
+
64
+ bootstrap!(redis)
65
+ redis.evalsha(@digest, keys, argv)
66
+ end
67
+
68
+ # Reads given file and returns new {Prescription} with its contents.
69
+ # @param file [String]
70
+ # @return [Prescription]
71
+ def self.read(file)
72
+ new File.read file
73
+ end
74
+
75
+ private
76
+
77
+ # Yields real namespace-less redis client.
78
+ # @param redis [Redis, Redis::Namespace]
79
+ # @return [Redis]
80
+ def namespaceless(redis)
81
+ if redis.is_a?(Redis)
82
+ redis
83
+ elsif defined?(Redis::Namespace) && redis.is_a?(Redis::Namespace)
84
+ redis.redis
85
+ else
86
+ raise TypeError, "Unsupported redis client type: #{redis.class}"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Redis
4
+ class Prescription
5
+ # Gem version.
6
+ VERSION = "1.0.0"
7
+ end
8
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require "redis/prescription/version"
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "redis-prescription"
10
+ spec.version = Redis::Prescription::VERSION
11
+ spec.authors = ["Alexey Zapparov"]
12
+ spec.email = ["ixti@member.fsf.org"]
13
+
14
+ spec.summary = "Redis LUA stored procedure runner."
15
+ spec.description = <<~DESCRIPTION
16
+ Preloads (and reloads when needed, e.g. when scripts
17
+ were flushed away) script and then runs it with `EVALSHA`.
18
+ DESCRIPTION
19
+
20
+ spec.homepage = "https://github.com/ixti/redis-prescription"
21
+ spec.license = "MIT"
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
24
+ f.match(%r{^(test|spec|features)/})
25
+ end
26
+
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.16"
30
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-prescription
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Zapparov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ description: |
28
+ Preloads (and reloads when needed, e.g. when scripts
29
+ were flushed away) script and then runs it with `EVALSHA`.
30
+ email:
31
+ - ixti@member.fsf.org
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - ".gitignore"
37
+ - ".rspec"
38
+ - ".rubocop.yml"
39
+ - ".travis.yml"
40
+ - ".yardopts"
41
+ - Gemfile
42
+ - Guardfile
43
+ - LICENSE.txt
44
+ - README.md
45
+ - Rakefile
46
+ - lib/redis/prescription.rb
47
+ - lib/redis/prescription/version.rb
48
+ - redis-prescription.gemspec
49
+ homepage: https://github.com/ixti/redis-prescription
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.7.3
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Redis LUA stored procedure runner.
73
+ test_files: []