The Modest Rubyist

A blog about Ruby & Rails from beginner to advanced.

Redis + CompSci 101 (Redis::Stack)

ShareThis March 27th 2010

Recently I got introduced to Redis, a super-cool, im-memory (but less-volitale), key-value store. As usual, I was late to the party.

Redis, is several things, including a sort of data structures server. So to flash back to CompSci 101, in this article I build a stack on top of the Redis Ruby client, which is one of the first things I did with it.

Redis Resources

Before we get started here are some Redis resources I used to get up and running:

Redis Homepage

Redis Wiki

Engine Yard Article

Redis Ruby client

Redis::Stack

Our Redis::Stack class will implement 4 operations: push, pop, peek, to_a, and size. Redis provides us with a list data structure, implemented as a Linked List, which we will use to store our stack. The operations that act on lists we will concern ourself with are below. The commands used (passed to the Redis client object) are not specific to the Redis Ruby client but as this is a Ruby blog, I express them in Ruby code.

redis_client = Redis.new
redis_client.lpush 'stack', 'member' # push element onto top of stack
redis_client.lpop 'stack'            # pop an element off the stack
redis_client.lrange, 'stack', 0, 0   # peek at the top element of 
                                     # the stack. lrange takes a
                                     # key, a starting index in the
                                     # list, and an ending index

The Ruby Redis client allows commands to be called in two ways. The way you will probably want to use it is by calling the command as an instance method of the client. Redis-rb does a little method missing magic with that and calls the instance method #call_command, passing it an array representing the command and its arguments.

#the following will produce the same result
redis_client.call_command ['lpush', 'stack', 'member']
redis_client.lpush 'stack', 'member'

With that, lets implement our Stack. It will take a hash of options when initalized. The options should include a :key to store our stack in and a :redis instance. Each of the commands will only operate on the given :key using the given :redis client.

class Redis::Stack
  attr_reader :key

  def initialize(options)
    @redis = options[:redis]
    @key = options[:key]
  end 

  def push(member)
    @redis.lpush key, member
  end 

  def pop
    @redis.lpop
  end

  def peek
    (@redis.lrange key, 0, 0).first # lrange returns an array
                                    # peek should return a member
  end 

  def to_a
    @redis.lrange key, 0, -1
  end 

  def size
    to_a.size
  end

end

stack = Stack.new(:redis => Redis.new, :key => 'my_stack')
stack.size # 0
stack.to_a # []
stack.peek # nil
stack.pop  # nil

stack.push 1
stack.push 2
stack.size # 2
stack.to_a # [2, 1]
stack.peek # 2
stack.pop  # 2
stack.peek # 1

There you have it. A dirt simple stack using Redis. Of course, there are some edge cases to handle before using the class but this is more about using Redis so I have ignored those factors here. You will also, of course, need an instance of redis-server running.

blog comments powered by Disqus