class Redis::Namespace
Constants
- COMMANDS
The following table defines how input parameters and result values should be modified for the namespace.
COMMANDS is a hash. Each key is the name of a command and each value is a two element array.
The first element in the value array describes how to modify the arguments passed. It can be one of:
nil Do nothing. :first Add the namespace to the first argument passed, e.g. GET key => GET namespace:key :all Add the namespace to all arguments passed, e.g. MGET key1 key2 => MGET namespace:key1 namespace:key2 :exclude_first Add the namespace to all arguments but the first, e.g. :exclude_last Add the namespace to all arguments but the last, e.g. BLPOP key1 key2 timeout => BLPOP namespace:key1 namespace:key2 timeout :exclude_options Add the namespace to all arguments, except the last argument, if the last argument is a hash of options. ZUNIONSTORE key1 2 key2 key3 WEIGHTS 2 1 => ZUNIONSTORE namespace:key1 2 namespace:key2 namespace:key3 WEIGHTS 2 1 :alternate Add the namespace to every other argument, e.g. MSET key1 value1 key2 value2 => MSET namespace:key1 value1 namespace:key2 value2 :sort Add namespace to first argument if it is non-nil Add namespace to second arg's :by and :store if second arg is a Hash Add namespace to each element in second arg's :get if second arg is a Hash; forces second arg's :get to be an Array if present. :eval_style Add namespace to each element in keys argument (via options hash or multi-args) :scan_style Add namespace to :match option, or supplies "#{namespace}:*" if not present.
The second element in the value array describes how to modify the return value of the Redis call. It can be one of:
nil Do nothing. :all Add the namespace to all elements returned, e.g. key1 key2 => namespace:key1 namespace:key2
- Enumerator
Support 1.8.7 by providing a namespaced reference to Enumerable::Enumerator
- VERSION
Attributes
namespace[W]
redis[R]
warning[RW]
Public Class Methods
new(namespace, options = {})
click to toggle source
# File lib/redis/namespace.rb, line 216 def initialize(namespace, options = {}) @namespace = namespace @redis = options[:redis] || Redis.current @warning = !!options.fetch(:warning) do !ENV['REDIS_NAMESPACE_QUIET'] end @deprecations = !!options.fetch(:deprecations) do ENV['REDIS_NAMESPACE_DEPRECATIONS'] end end
Public Instance Methods
call_with_namespace(command, *args, &block)
click to toggle source
# File lib/redis/namespace.rb, line 318 def call_with_namespace(command, *args, &block) handling = COMMANDS[command.to_s.downcase] if handling.nil? fail("Redis::Namespace does not know how to handle '#{command}'.") end (before, after) = handling # Add the namespace to any parameters that are keys. case before when :first args[0] = add_namespace(args[0]) if args[0] when :all args = add_namespace(args) when :exclude_first first = args.shift args = add_namespace(args) args.unshift(first) if first when :exclude_last last = args.pop unless args.length == 1 args = add_namespace(args) args.push(last) if last when :exclude_options if args.last.is_a?(Hash) last = args.pop args = add_namespace(args) args.push(last) else args = add_namespace(args) end when :alternate args.each_with_index { |a, i| args[i] = add_namespace(a) if i.even? } when :sort args[0] = add_namespace(args[0]) if args[0] if args[1].is_a?(Hash) [:by, :store].each do |key| args[1][key] = add_namespace(args[1][key]) if args[1][key] end args[1][:get] = Array(args[1][:get]) args[1][:get].each_index do |i| args[1][:get][i] = add_namespace(args[1][:get][i]) unless args[1][:get][i] == "#" end end when :eval_style # redis.eval() and evalsha() can either take the form: # # redis.eval(script, [key1, key2], [argv1, argv2]) # # Or: # # redis.eval(script, :keys => ['k1', 'k2'], :argv => ['arg1', 'arg2']) # # This is a tricky + annoying special case, where we only want the `keys` # argument to be namespaced. if args.last.is_a?(Hash) args.last[:keys] = add_namespace(args.last[:keys]) else args[1] = add_namespace(args[1]) end when :scan_style options = (args.last.kind_of?(Hash) ? args.pop : {}) options[:match] = add_namespace(options.fetch(:match, '*')) args << options if block original_block = block block = proc { |key| original_block.call rem_namespace(key) } end end # Dispatch the command to Redis and store the result. result = @redis.send(command, *args, &block) # Don't try to remove namespace from a Redis::Future, you can't. return result if result.is_a?(Redis::Future) # Remove the namespace from results that are keys. case after when :all result = rem_namespace(result) when :first result[0] = rem_namespace(result[0]) if result when :second result[1] = rem_namespace(result[1]) if result end result end
client()
click to toggle source
# File lib/redis/namespace.rb, line 235 def client @redis.client end
deprecations?()
click to toggle source
# File lib/redis/namespace.rb, line 227 def deprecations? @deprecations end
eval(*args)
click to toggle source
# File lib/redis/namespace.rb, line 281 def eval(*args) call_with_namespace(:eval, *args) end
exec()
click to toggle source
# File lib/redis/namespace.rb, line 277 def exec call_with_namespace(:exec) end
keys(query = nil)
click to toggle source
# File lib/redis/namespace.rb, line 252 def keys(query = nil) call_with_namespace(:keys, query || '*') end
method_missing(command, *args, &block)
click to toggle source
Calls superclass method
# File lib/redis/namespace.rb, line 285 def method_missing(command, *args, &block) normalized_command = command.to_s.downcase if COMMANDS.include?(normalized_command) call_with_namespace(command, *args, &block) elsif @redis.respond_to?(normalized_command) && !deprecations? # blind passthrough is deprecated and will be removed in 2.0 # redis-namespace does not know how to handle this command. # Passing it to @redis as is, where redis-namespace shows # a warning message if @warning is set. if warning? call_site = caller.reject { |l| l.start_with?(__FILE__) }.first warn("Passing '#{command}' command to redis as is; blind " + "passthrough has been deprecated and will be removed in " + "redis-namespace 2.0 (at #{call_site})") end @redis.send(command, *args, &block) else super end end
multi(&block)
click to toggle source
# File lib/redis/namespace.rb, line 256 def multi(&block) if block_given? namespaced_block(:multi, &block) else call_with_namespace(:multi) end end
namespace(desired_namespace = nil) { |namespace(desired_namespace, :redis => redis)| ... }
click to toggle source
# File lib/redis/namespace.rb, line 268 def namespace(desired_namespace = nil) if desired_namespace yield Redis::Namespace.new(desired_namespace, :redis => @redis) end @namespace end
pipelined(&block)
click to toggle source
# File lib/redis/namespace.rb, line 264 def pipelined(&block) namespaced_block(:pipelined, &block) end
respond_to?(command, include_private=false)
click to toggle source
emulate Ruby 1.9+ and keep respond_to_missing? logic together.
Calls superclass method
# File lib/redis/namespace.rb, line 248 def respond_to?(command, include_private=false) super or respond_to_missing?(command, include_private) end
Also aliased as: self_respond_to?
respond_to_missing?(command, include_all=false)
click to toggle source
Calls superclass method
# File lib/redis/namespace.rb, line 307 def respond_to_missing?(command, include_all=false) return true if COMMANDS.include?(command.to_s.downcase) # blind passthrough is deprecated and will be removed in 2.0 if @redis.respond_to?(command, include_all) && !deprecations? return true end defined?(super) && super end
type(key)
click to toggle source
Ruby defines a now deprecated type method so we need to override it here since it will never hit #method_missing
# File lib/redis/namespace.rb, line 241 def type(key) call_with_namespace(:type, key) end
warning?()
click to toggle source
# File lib/redis/namespace.rb, line 231 def warning? @warning end
Private Instance Methods
add_namespace(key)
click to toggle source
# File lib/redis/namespace.rb, line 423 def add_namespace(key) return key unless key && @namespace case key when Array key.map {|k| add_namespace k} when Hash Hash[*key.map {|k, v| [ add_namespace(k), v ]}.flatten] else "#{@namespace}:#{key}" end end
create_enumerator(&block)
click to toggle source
# File lib/redis/namespace.rb, line 453 def create_enumerator(&block) # Enumerator in 1.8.7 *requires* a single argument, so we need to use # its Generator class, which matches the block syntax of 1.9.x's # Enumerator class. if RUBY_VERSION.start_with?('1.8') require 'generator' unless defined?(Generator) Generator.new(&block).to_enum else Enumerator.new(&block) end end
namespaced_block(command) { |self| ... }
click to toggle source
# File lib/redis/namespace.rb, line 412 def namespaced_block(command, &block) redis.send(command) do |r| begin original, @redis = @redis, r yield self ensure @redis = original end end end
rem_namespace(key)
click to toggle source
# File lib/redis/namespace.rb, line 436 def rem_namespace(key) return key unless key && @namespace case key when Array key.map {|k| rem_namespace k} when Hash Hash[*key.map {|k, v| [ rem_namespace(k), v ]}.flatten] when Enumerator create_enumerator do |yielder| key.each { |k| yielder.yield rem_namespace(k) } end else key.to_s.sub(/\A#{@namespace}:/, '') end end