<div dir="ltr"><div><br></div><div>By the way, maybe you should look two files in `inst`.</div><div><br></div><div>The `gen_function.R` crawls <a href="http://redis.io/commands">http://redis.io/commands</a> and generates the command according to the official redis manual. You could modify `template.R` to generate the helper functions dynamically based on the exposed Rcpp function.</div>
<div><br></div><div>Hope it helps.</div><div><br></div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I may do something like that tomorrow evening.<br>
<br>
For now, I did something _much_ simpler still. We need single C++ source<br>
file. Some key features:<br>
<br>
-- no more Boost shared_ptr<br>
-- no more Rcpp::XPtr<br>
-- "empty" constructor and destructor, nothing to be done<br>
-- no member variables<br>
-- one worker function which takes string (with a redis command), runs it<br>
and returns the result string<br>
-- the worker function checks if the redis context pointer is non-NULL; in<br>
case it is NULL (eg first use) it creates a context<br>
<br>
-----------------------------------------------------------------------------<br>
<br>
#include <Rcpp.h><br>
#include <hiredis/hiredis.h> // on Ubuntu file /usr/include/hiredis/hiredis.h<br>
<br>
// We use a static pointer which makes the variable persistent across calls<br>
// A more formal C++ idiom would be a singleton class, but this is simpler<br>
static redisContext *prc = NULL;<br>
<br>
<br>
// A simple and lightweight class -- without member variables<br>
// We could add some member variables to cache the last call, status, ...<br>
//<br>
class Redis {<br>
<br>
private:<br>
void checkAndInit() {<br>
if (prc == NULL) {<br>
prc = redisConnect("127.0.0.1", 6379);<br>
// should test for error here, could even throw() under Rcpp, ...<br>
Rcpp::Rcout << "Context created\n";<br>
} else {<br>
Rcpp::Rcout << "Reusing context\n";<br>
}<br>
}<br>
<br>
public:<br>
Redis() { /* Rcpp::Rcout << "In ctor\n"; */ }<br>
~Redis() { /* Rcpp::Rcout << "In dtor\n"; */ }<br>
<br>
std::string execCommand(std::string cmd) {<br>
checkAndInit(); // important: ensure prc is set up, re-use if so<br>
redisReply *reply = static_cast<redisReply*>(redisCommand(prc, cmd.c_str()));<br>
std::string res(reply->str);<br>
freeReplyObject(reply);<br>
return(res);<br>
}<br>
<br>
void disconnect() {<br>
redisFree(prc);<br>
prc = NULL; // just to be on the safe side<br>
}<br>
<br>
// could create new functions to (re-)connect with given host and port etc pp<br>
};<br>
<br>
-----------------------------------------------------------------------------<br>
<br>
Couple this with a simple function (which is so simple that I wrote it<br>
"straight" without even Rcpp attributes. One string in, one string out:<br>
<br>
<br>
-----------------------------------------------------------------------------<br>
// for now, single worker function<br>
extern "C" SEXP execRedisCommand(SEXP p) {<br>
Redis redis;<br>
std::string txt = Rcpp::as<std::string>(p);<br>
std::string res = redis.execCommand(txt);<br>
return Rcpp::wrap(res);<br>
}<br>
-----------------------------------------------------------------------------<br>
<br>
<br>
(We could create a second function to close redis and call disconnect();<br>
and we could 'getter' function for the state variables inside the context.)<br>
<br>
This function is then used by a single R function:<br>
<br>
-----------------------------------------------------------------------------<br>
## minimal R interface to redis using the hiredis library<br>
redis <- function(cmd) {<br>
## some sanity checking on cmd would be nice too...<br>
.Call("execRedisCommand", cmd, package="Rhiredis")<br>
}<br>
-----------------------------------------------------------------------------<br>
<br>
And that is all. I added a simple tester:<br>
<br>
edd@don:~/git/Rhiredis$ Rscript tests/simpleRedisClient.R<br>
Context created<br>
[1] "PONG"<br>
Reusing context<br>
[1] "PONG"<br>
Reusing context<br>
[1] "PONG"<br>
Reusing context<br>
[1] "OK"<br>
Reusing context<br>
[1] "42"<br>
edd@don:~/git/Rhiredis$<br>
<br>
As you can see from the verbose text from checkAndInit(), we only need to<br>
create the redis instance once.<br>
<br>
I may still turn this into something based on Rcpp modules. Maybe tomorrow.<br>
<br>
The code is for now in a quick fork of your Rhiredis in my github account.<br>
<br>
Hope this helps, Dirk<br>
<span class="HOEnZb"><font color="#888888"><br>
<br>
--<br>
Dirk Eddelbuettel | <a href="mailto:edd@debian.org">edd@debian.org</a> | <a href="http://dirk.eddelbuettel.com" target="_blank">http://dirk.eddelbuettel.com</a><br>
</font></span></blockquote></div><br></div></div>