class Redis::Namespace

Constants

ALIASES

support previous versions of redis gem

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 217
def initialize(namespace, options = {})
  @namespace = namespace
  @redis = options[:redis] || Redis.current
  @warning = options[:warning] || false
end

Public Instance Methods

eval(*args) click to toggle source
# File lib/redis/namespace.rb, line 268
def eval(*args)
  method_missing(:eval, *args)
end
exec() click to toggle source
# File lib/redis/namespace.rb, line 264
def exec
  method_missing(:exec)
end
keys(query = nil) click to toggle source
Calls superclass method
# File lib/redis/namespace.rb, line 239
def keys(query = nil)
  query.nil? ? super("*") : super
end
method_missing(command, *args, &block) click to toggle source
# File lib/redis/namespace.rb, line 272
def method_missing(command, *args, &block)
  command_for_lookup = command.to_s.downcase
  handling = COMMANDS[command_for_lookup] ||
    COMMANDS[ALIASES[command_for_lookup]]

  # 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 handling.nil?
    warn("Passing '#{command}' command to redis as is.") if @warning
    return @redis.send(command, *args, &block)
  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
multi(&block) click to toggle source
# File lib/redis/namespace.rb, line 243
def multi(&block)
  if block_given?
    namespaced_block(:multi, &block)
  else
    method_missing(:multi)
  end
end
namespace(desired_namespace = nil) { |namespace(desired_namespace, :redis => redis)| ... } click to toggle source
# File lib/redis/namespace.rb, line 255
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 251
def pipelined(&block)
  namespaced_block(:pipelined, &block)
end
respond_to?(command, include_private=false) click to toggle source
# File lib/redis/namespace.rb, line 231
def respond_to?(command, include_private=false)
  if self_respond_to?(command, include_private)
    true
  else
    @redis.respond_to?(command, include_private)
  end
end
Also aliased as: self_respond_to?
self_respond_to?(command, include_private=false)
Alias for: respond_to?
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 225
def type(key)
  method_missing(:type, key)
end

Private Instance Methods

add_namespace(key) click to toggle source
# File lib/redis/namespace.rb, line 382
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 412
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 defined?(::Enumerable::Enumerator)
    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 372
def namespaced_block(command, &block)
  original = @redis
  result = redis.send(command) do |r|
    @redis = r
    yield self
  end
  @redis = original
  result
end
rem_namespace(key) click to toggle source
# File lib/redis/namespace.rb, line 395
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