diff --git a/.rspec b/.rspec deleted file mode 100644 index 8c18f1a..0000000 --- a/.rspec +++ /dev/null @@ -1,2 +0,0 @@ ---format documentation ---color diff --git a/.travis.yml b/.travis.yml index 1a37fcd..16cc8dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: ruby rvm: - - 2.1.7 - - 2.2.3 -before_install: gem install bundler -v 1.10.6 + - 2.3.3 + - 2.4.1 +before_install: gem install bundler -v 1.14.6 services: - redis-server diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index ce9bee7..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,13 +0,0 @@ -# Contributor Code of Conduct - -As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. - -We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. - -Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) diff --git a/Gemfile b/Gemfile index e266793..7ab296b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source 'https://rubygems.org' +source "https://rubygems.org" # Specify your gem's dependencies in redis_eval.gemspec gemspec diff --git a/README.md b/README.md index a801e6f..5e2d691 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,7 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/i2bskn/redis_eval. 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. - +Bug reports and pull requests are welcome on GitHub at https://github.com/i2bskn/redis_eval. ## License diff --git a/Rakefile b/Rakefile index b7e9ed5..d6c5113 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,10 @@ require "bundler/gem_tasks" -require "rspec/core/rake_task" +require "rake/testtask" -RSpec::Core::RakeTask.new(:spec) +Rake::TestTask.new(:test) do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList['test/**/*_test.rb'] +end -task :default => :spec +task :default => :test diff --git a/bin/setup b/bin/setup index b65ed50..c92300c 100755 --- a/bin/setup +++ b/bin/setup @@ -1,6 +1,7 @@ #!/bin/bash set -euo pipefail IFS=$'\n\t' +set -vx bundle install diff --git a/lib/redis_eval.rb b/lib/redis_eval.rb index b06abfe..16e89c4 100644 --- a/lib/redis_eval.rb +++ b/lib/redis_eval.rb @@ -3,6 +3,5 @@ require "redis" require "redis_eval/version" -require "redis_eval/configuration" -require "redis_eval/generator_methods" require "redis_eval/script" +require "redis_eval/script_set" diff --git a/lib/redis_eval/configuration.rb b/lib/redis_eval/configuration.rb deleted file mode 100644 index a5ff6b8..0000000 --- a/lib/redis_eval/configuration.rb +++ /dev/null @@ -1,58 +0,0 @@ -module RedisEval - class Configuration - module Accessible - def configure(options = {}, &block) - config.merge!(options) unless options.empty? - config.configure(&block) if block_given? - end - - def config - @_config ||= Configuration.new - end - end - - VALID_OPTIONS = [ - :redis_options, - :script_paths, - ].freeze - - attr_accessor *VALID_OPTIONS - - def initialize - reset - end - - def redis(cache_disable: false) - if cache_disable - @_redis = generate_redis_connection! - else - @_redis ||= generate_redis_connection! - end - end - - def configure - yield self - end - - def merge(params) - self.dup.merge!(params) - end - - def merge!(params) - params.keys.each {|key| self.send("#{key}=", params[key]) } - self - end - - def reset - self.redis_options = nil - self.script_paths = [] - end - - private - def generate_redis_connection! - redis_options ? Redis.new(**redis_options) : Redis.current - end - end - - extend Configuration::Accessible -end diff --git a/lib/redis_eval/generator_methods.rb b/lib/redis_eval/generator_methods.rb deleted file mode 100644 index 72e7169..0000000 --- a/lib/redis_eval/generator_methods.rb +++ /dev/null @@ -1,50 +0,0 @@ -module RedisEval - module GeneratorMethods - def build(name) - path = case name - when Pathname - name - when String, Symbol - name =~ /\.lua$/ ? pathname(name.to_s) : script_path(name) - else - raise ArgumentError - end - - RedisEval::Script.build_from_path(path) - end - - private - def pathname(path) - path.is_a?(String) ? Pathname.new(path) : path - end - - def script_cache - @script_cache ||= {} - end - - def script_path(name) - RedisEval.config.script_paths.each {|path| - if (script = pathname(path).join("#{name}.lua")).exist? - return script - end - } - nil - end - - def method_missing(name, *args, &block) - super unless respond_to?(name) - - define_singleton_method(name) do |*a, &b| - script_cache[name.to_s] ||= build(name) - end - - send(name, *args, &block) - end - - def respond_to_missing?(name, include_private = false) - !!script_path(name) - end - end - - extend GeneratorMethods -end diff --git a/lib/redis_eval/script.rb b/lib/redis_eval/script.rb index e507c59..950b7df 100644 --- a/lib/redis_eval/script.rb +++ b/lib/redis_eval/script.rb @@ -1,33 +1,20 @@ module RedisEval class Script - attr_reader :name, :script, :sha + attr_accessor :script_set + attr_reader :script, :sha - class << self - # @param path [Pathname] - # @return [RedisEval::Script] - def build_from_path(path) - name = path.basename(".*").to_s - script = File.read(path) - new(name, script) - end - - def load(script) - redis.script(:load, script) - end - - def flush - redis.script(:flush) - end + def initialize(script, script_set: nil, with_load: true) + @script = script + @sha = Digest::SHA1.hexdigest(script) + self.load if with_load + end - def redis - RedisEval.config.redis - end + def load + redis.script(:load, script) end - def initialize(name, script) - @name = name - @script = script - @sha = Digest::SHA1.hexdigest(script) + def exist? + redis.script(:exists, sha) end def execute(keys = [], argv = []) @@ -40,12 +27,19 @@ def execute(keys = [], argv = []) end end - def exist? - redis.script(:exists, sha) + def redis + case + when instance_variable_defined?(:@redis) + @redis + when !script_set.nil? + script_set.redis + else + Redis.current + end end - def redis - self.class.redis + def redis=(conn) + @redis = conn end end end diff --git a/lib/redis_eval/script_set.rb b/lib/redis_eval/script_set.rb new file mode 100644 index 0000000..07686f5 --- /dev/null +++ b/lib/redis_eval/script_set.rb @@ -0,0 +1,59 @@ +module RedisEval + class ScriptSet + attr_reader :src_path + + SCRIPT_SUFFIX = ".lua" + + def initialize(path) + @src_path = pathname(path) + end + + def load(name) + script = script_path(name).read + loaded_scripts[name.to_s] ||= RedisEval::Script.new(script, script_set: self) + end + + def load_all_script + src_path.children(false).each do |path| + name = path.basename(SCRIPT_SUFFIX).to_s + script = script_path(name).read + loaded_scripts[name] ||= RedisEval::Script.new(script, script_set: self) + end + true + end + + def redis + instance_variable_defined?(:@redis) ? @redis : Redis.current + end + + def redis=(conn) + @redis = conn + end + + private + + def pathname(path) + path.is_a?(Pathname) ? path : Pathname.new(path) + end + + def loaded_scripts + @loaded_scripts ||= {} + end + + def script_path(name) + src_path.join(name.to_s).sub_ext(SCRIPT_SUFFIX) + end + + def method_missing(name, *args, &block) + super unless respond_to?(name) + + self.load(name) + define_singleton_method(name) { |*a, &b| loaded_scripts[name.to_s] } + send(name, *args, &block) + end + + def respond_to_missing?(name, include_private = false) + loaded_scripts.has_key?(name.to_s) || script_path(name).exist? || super + end + end +end diff --git a/redis_eval.gemspec b/redis_eval.gemspec index f8f1b68..b8318cc 100644 --- a/redis_eval.gemspec +++ b/redis_eval.gemspec @@ -1,7 +1,7 @@ # coding: utf-8 -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'redis_eval/version' +require "redis_eval/version" Gem::Specification.new do |spec| spec.name = "redis_eval" @@ -14,16 +14,18 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/i2bskn/redis_eval" spec.license = "MIT" - spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + spec.files = `git ls-files -z`.split("\x0").reject do |f| + f.match(%r{^(test|spec|features)/}) + end spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] spec.add_dependency "redis" - spec.add_development_dependency "bundler", "~> 1.10" + spec.add_development_dependency "bundler", "~> 1.14" spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "rspec" + spec.add_development_dependency "minitest", "~> 5.0" spec.add_development_dependency "pry" spec.add_development_dependency "coveralls" spec.add_development_dependency "simplecov" diff --git a/spec/lua_scripts/hello.lua b/spec/lua_scripts/hello.lua deleted file mode 100644 index 85e4fe3..0000000 --- a/spec/lua_scripts/hello.lua +++ /dev/null @@ -1 +0,0 @@ -return "Hello world!" diff --git a/spec/redis_eval/configuration_spec.rb b/spec/redis_eval/configuration_spec.rb deleted file mode 100644 index b6ce5a5..0000000 --- a/spec/redis_eval/configuration_spec.rb +++ /dev/null @@ -1,125 +0,0 @@ -require "spec_helper" - -describe RedisEval::Configuration do - include_context "ConfigurationExample" - - describe "Accessible" do - context "extended" do - subject { Module.new { extend RedisEval::Configuration::Accessible } } - - it { is_expected.to respond_to(:configure) } - it { is_expected.to respond_to(:config) } - end - - describe "#configure" do - before do - RedisEval.configure do |config| - config.redis_options = options - config.script_paths = paths - end - end - - subject { config } - - it { is_expected.to have_attributes(redis_options: options) } - it { is_expected.to have_attributes(script_paths: paths) } - - it { - expect { - RedisEval.configure {|config| config.unknown = :value } - }.to raise_error(NoMethodError) - } - end - - describe "#config" do - it { expect(RedisEval.config.is_a?(RedisEval::Configuration)).to be_truthy } - end - end - - describe "#initialize" do - subject { RedisEval.config } - - RedisEval::Configuration::VALID_OPTIONS.each do |key| - it { is_expected.to respond_to(key) } - end - - it { is_expected.to have_attributes(redis_options: nil) } - it { is_expected.to have_attributes(script_paths: []) } - end - - describe "#redis" do - before(:each) { - if config.instance_variable_defined?(:@_redis) - config.remove_instance_variable(:@_redis) - end - } - - context "with cache" do - it { expect(config.redis).to be_kind_of(Redis) } - - it { - expect(config).to receive(:generate_redis_connection!) - config.redis - } - - it { - config.redis - expect(config).not_to receive(:generate_redis_connection!) - config.redis - } - end - - context "without cache" do - it { expect(config.redis(cache_disable: true)).to be_kind_of(Redis) } - - it { - expect(config).to receive(:generate_redis_connection!) - config.redis(cache_disable: true) - } - - it { - config.redis(cache_disable: true) - expect(config).to receive(:generate_redis_connection!) - config.redis(cache_disable: true) - } - end - end - - describe "#merge" do - subject { config.merge(script_paths: paths) } - - it { is_expected.to have_attributes(script_paths: paths) } - it { is_expected.to be_kind_of(RedisEval::Configuration) } - end - - describe "#merge!" do - subject { config.merge!(script_paths: paths) } - - it { is_expected.to have_attributes(script_paths: paths) } - it { is_expected.to be_kind_of(RedisEval::Configuration) } - end - - describe "#generate_redis_connection!" do - context "when redis_options is nil" do - it { expect(config.send(:generate_redis_connection!)).to be_kind_of(Redis) } - - it { - expect(Redis).not_to receive(:new) - expect(Redis).to receive(:current) - config.send(:generate_redis_connection!) - } - end - - context "when redis_options is not nil" do - before { config.redis_options = options } - - it { expect(config.send(:generate_redis_connection!)).to be_kind_of(Redis) } - - it { - expect(Redis).to receive(:new) - expect(Redis).not_to receive(:current) - config.send(:generate_redis_connection!) - } - end - end -end diff --git a/spec/redis_eval/generator_methods_spec.rb b/spec/redis_eval/generator_methods_spec.rb deleted file mode 100644 index b01a165..0000000 --- a/spec/redis_eval/generator_methods_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "spec_helper" - -describe RedisEval::GeneratorMethods do - include_context "LuaScriptExample" - - describe "#build" do - context "Pathname" do - it { - expect(RedisEval::Script).to receive(:build_from_path).with(pathname) - RedisEval.build(pathname) - } - end - - context "String" do - let(:path) { Pathname.new(string_path) } - - before(:each) { - expect(RedisEval::Script).to receive(:build_from_path).with(path) - } - - it { - expect(RedisEval).to receive(:pathname).with(string_path).and_return(path) - RedisEval.build(string_path) - } - - it { - expect(RedisEval).to receive(:script_path).with(string_name).and_return(path) - RedisEval.build(string_name) - } - end - - context "ArgumentError" do - it { - expect { - RedisEval.build(1) - }.to raise_error(ArgumentError) - } - end - end - - describe "#pathname" do - it { expect(RedisEval.send(:pathname, pathname)).to be_kind_of(Pathname) } - it { expect(RedisEval.send(:pathname, string_path)).to be_kind_of(Pathname) } - end - - describe "#script_cache" do - it { expect(RedisEval.send(:script_cache)).to be_kind_of(Hash) } - it { expect(RedisEval.send(:script_cache)).to be_empty } - end - - describe "#script_path" do - it { - RedisEval.config.reset - expect(RedisEval.send(:script_path, :hello)).to be_nil - } - - it { - RedisEval.config.script_paths = LUA_SCRIPT_PATH - expect(RedisEval.send(:script_path, :hello)).to eq(pathname) - } - end - - describe "#method_missing" do - before(:each) { RedisEval.config.script_paths = LUA_SCRIPT_PATH } - - it { expect(RedisEval.respond_to?(:hello)).to be_truthy } - it { expect(RedisEval.respond_to?(:unknown)).to be_falsey } - - it { - expect(RedisEval).to receive(:build).with(:hello) - RedisEval.hello - } - end -end diff --git a/spec/redis_eval/script_spec.rb b/spec/redis_eval/script_spec.rb deleted file mode 100644 index bef0d39..0000000 --- a/spec/redis_eval/script_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -require "spec_helper" - -describe RedisEval::Script do - include_context "LuaScriptExample" - let(:script) { RedisEval::Script.build_from_path(pathname) } - before(:each) { RedisEval::Script.flush } - - describe ".build_from_path" do - it { - expect(RedisEval::Script).to receive(:new).with(string_name, File.read(pathname)) - script - } - - it { - expect(script).to be_kind_of(RedisEval::Script) - } - end - - describe ".load" do - it { - expect { - RedisEval::Script.load(script.script) - }.to change { script.exist? } - } - - it { - expect(RedisEval::Script.load(script.script)).to eq(Digest::SHA1.hexdigest(script.script)) - } - end - - describe ".flush" do - before(:each) { RedisEval::Script.load(script.script) } - - it { - expect { - RedisEval::Script.flush - }.to change { script.exist? } - } - end - - describe ".redis" do - it { - expect(RedisEval.config).to receive(:redis) - RedisEval::Script.redis - } - end - - describe "#initialize" do - it { expect(script).to have_attributes(name: string_name) } - it { expect(script).to have_attributes(script: File.read(pathname)) } - it { expect(script).to have_attributes(sha: Digest::SHA1.hexdigest(File.read(pathname))) } - end - - describe "#execute" do - it { expect(script.execute).to eq("Hello world!") } - it { - expect(RedisEval.config.redis).to receive(:evalsha).and_raise(Redis::CommandError, "raise example") - expect { script.execute }.to raise_error(Redis::CommandError) - } - end - - describe "#exist?" do - it { expect(script.exist?).to be_falsey } - - it { - RedisEval::Script.load(script.script) - expect(script.exist?).to be_truthy - } - end - - describe "#redis" do - it { - expect(RedisEval::Script).to receive(:redis) - script.redis - } - end -end diff --git a/spec/redis_eval/version_spec.rb b/spec/redis_eval/version_spec.rb deleted file mode 100644 index ef8302f..0000000 --- a/spec/redis_eval/version_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "spec_helper" - -describe RedisEval do - it "has a version number" do - expect(RedisEval::VERSION).not_to be_nil - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index e21c03b..0000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,29 +0,0 @@ -require "simplecov" -require "coveralls" -Coveralls.wear! - -SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ - SimpleCov::Formatter::HTMLFormatter, - Coveralls::SimpleCov::Formatter -] - -SimpleCov.start do - add_filter "spec" - add_filter ".bundle" -end - -require "bundler/setup" -require "redis_eval" - -Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} - -LUA_SCRIPT_PATH = [File.expand_path("../lua_scripts", __FILE__)] -TEST_DB = "redis://localhost:6379/10" - -RSpec.configure do |config| - config.order = :random - config.after(:each) { - RedisEval.config.reset - RedisEval.send(:script_cache).clear - } -end diff --git a/spec/support/shared_contexts.rb b/spec/support/shared_contexts.rb deleted file mode 100644 index ede7671..0000000 --- a/spec/support/shared_contexts.rb +++ /dev/null @@ -1,11 +0,0 @@ -shared_context "ConfigurationExample" do - let(:paths) { ["/path/to/script_dir"] } - let(:options) { {url: TEST_DB} } - let(:config) { RedisEval.config } -end - -shared_context "LuaScriptExample" do - let(:string_path) { File.join(LUA_SCRIPT_PATH, "hello.lua") } - let(:pathname) { Pathname.new(string_path) } - let(:string_name) { "hello" } -end diff --git a/test/redis_eval_test.rb b/test/redis_eval_test.rb new file mode 100644 index 0000000..8bfce62 --- /dev/null +++ b/test/redis_eval_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class RedisEvalTest < Minitest::Test + def test_that_it_has_a_version_number + refute_nil ::RedisEval::VERSION + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..335ee39 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,19 @@ +require "bundler/setup" +require "simplecov" +require "coveralls" + +Coveralls.wear! + +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter::new([ + SimpleCov::Formatter::HTMLFormatter, + Coveralls::SimpleCov::Formatter +]) + +SimpleCov.start do + add_filter "spec" + add_filter ".bundle" +end + +require "redis_eval" + +require "minitest/autorun"