antirez/redis — pull request #848 by tricknotes (2012-12-25 09:34:12+00:00)
Title: scripting with mruby

We have created a command `REVAL` to use [mruby](https://github.com/mruby/mruby) for scripting of Redis.

mruby is the lightweight implementation of the Ruby language complying to (part of) the ISO standard.
Ruby is good at processing strings, arrays, hashes, etc. with its pretty designed libraries.
With mruby, we can do complex data operations in Redis with simple scripts.

How do you think about this idea?
As this patch is still rough cutting, some works will be needed to fit with Redis.
(For example `REVALSHA` is not implemented. Not implemented features will be listed later.)

If your feel positive about implementing scripting languages in Redis other than Lua, we would like to consider supporting JavaScript with [v8](http://code.google.com/p/v8/).
JavaScript runs on both client-side and server-side.
If Redis supports JavaScript, we can write everything in JavaScript.

The usage of `REVAL` is as follows:

----

```
REVAL script numkeys key [key ...] arg [arg …]
```

## Features

Run mruby in the context of Redis server.
```
> reval "[KEYS[0],KEYS[1],ARGV[0],ARGV[1]]" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
```

Call Redis commands from a mruby script. (same as `EVAL` command)

```
> reval "REDIS.call('set','foo','bar')" 0
OK
```

## Conversion between mruby and Redis data types

**Redis to mruby** conversion table.
* Redis integer reply -> mruby Integer
* Redis bulk reply -> mruby String
* Redis multi bulk reply -> mruby Array
* Redis error reply -> mruby Exception
* Redis Nil bulk reply and Nil multi bulk reply -> mruby nil

**mruby to Redis** conversion table.
* mruby Integer -> Redis integer reply (the number is converted into an integer)
* mruby String -> Redis bulk reply
* mruby Array -> Redis multi bulk reply (truncated to the first nil inside the mruby array if any)
* mruby Hash with a single ok key -> Redis status reply
* mruby Hash with a single err key -> Redis error reply
* mruby Error -> Redis error reply
* mruby boolean false -> Redis Nil bulk reply
* mruby boolean true -> Redis integer reply with value of 1.

(examples)

```
> reval "10" 0
(integer) 10

> reval "[1, 2, [3, 'Hello World!']]" 0
1) (integer) 1
2) (integer) 2
3) 1) (integer) 3
2) "Hello World!"

> reval "REDIS.call('get', 'foo')" 0
"bar"
```

## Not implemented yet

- `REVALSHA`
- `REDIS.pcall`
- `REDIS.log`
- script timeout