Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 40 additions & 19 deletions ext/Converters.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,18 @@
// ************** Converters from Ruby to R *********//


VALUE ruby_to_Robj(VALUE self, VALUE args){

SEXP robj;
VALUE val;
robj = ruby_to_R(args);
val = to_ruby_with_mode(robj,NO_CONVERSION);
return val;
}
SEXP ruby_to_R(VALUE obj)
{
SEXP robj;
VALUE str;
char buf [100];

//Return nil if object is nil
if (obj == Qnil) {
Expand Down Expand Up @@ -104,8 +111,7 @@ SEXP ruby_to_R(VALUE obj)
{
str = rb_funcall(obj,rb_intern("inspect"),0);
str = rb_funcall(str,rb_intern("slice"),2,INT2NUM(0),INT2NUM(60));
sprintf(buf,"Unsupported object '%s' passed to R.\n",RSTRING_PTR(str));
rb_raise(rb_eArgError,"%s",buf);
rb_raise(rb_eArgError, "Unsupported object '%s' passed to R.\n", RSTRING_PTR(str));
PROTECT(robj = NULL); /* Protected to avoid stack inbalance */
}

Expand Down Expand Up @@ -309,10 +315,9 @@ int
to_ruby_vector(SEXP robj, VALUE *obj, int mode)
{
VALUE it, tmp;
VALUE params[2];
SEXP names, dim;
int len, *integers, i, type;
char *strings, *thislevel;
const char *strings, *thislevel;
double *reals;
Rcomplex *complexes;

Expand Down Expand Up @@ -352,11 +357,11 @@ to_ruby_vector(SEXP robj, VALUE *obj, int mode)
if(isFactor(robj)) {
/* Watch for NA's! */
if(integers[i]==NA_INTEGER)
it = rb_str_new2(CHAR(NA_STRING));
it = rb_external_str_new_cstr(CHAR(NA_STRING));
else
{
thislevel = CHAR(STRING_ELT(GET_LEVELS(robj), integers[i]-1));
if (!(it = rb_str_new2(thislevel)))
if (!(it = rb_external_str_new_cstr(thislevel)))
return -1;
}
}
Expand All @@ -380,11 +385,11 @@ to_ruby_vector(SEXP robj, VALUE *obj, int mode)
break;
case STRSXP:
if(STRING_ELT(robj, i)==R_NaString)
it = rb_str_new2(CHAR(NA_STRING));
it = rb_external_str_new_cstr(CHAR(NA_STRING));
else
{
strings = CHAR(STRING_ELT(robj, i));
if (!(it = rb_str_new2(strings)))
if (!(it = rb_external_str_new_cstr(strings)))
return -1;
}
break;
Expand All @@ -404,8 +409,7 @@ to_ruby_vector(SEXP robj, VALUE *obj, int mode)

dim = GET_DIM(robj);
if (dim != R_NilValue) {
len = GET_LENGTH(dim);
*obj = to_ruby_array(tmp, INTEGER(dim), len);
*obj = to_ruby_array(tmp, robj);
return 1;
}

Expand Down Expand Up @@ -545,7 +549,7 @@ VALUE from_class_table(SEXP robj)

for (i=0; i<GET_LENGTH(rclass); i++){
fun = rb_hash_aref(class_table,
rb_str_new2(CHAR(STRING_ELT(rclass, i))));
rb_external_str_new_cstr(CHAR(STRING_ELT(rclass, i))));
if (fun != Qnil){
break;
}
Expand Down Expand Up @@ -592,7 +596,7 @@ VALUE to_ruby_hash(VALUE obj, SEXP names)
{
int len, i;
VALUE it, hash;
char *name;
const char *name;

if ((len = RARRAY_LEN(obj)) < 0)
return Qnil;
Expand All @@ -601,7 +605,7 @@ VALUE to_ruby_hash(VALUE obj, SEXP names)
for (i=0; i<len; i++) {
it = rb_ary_entry(obj, i);
name = CHAR(STRING_ELT(names, i));
rb_hash_aset(hash, rb_str_new2(name), it);
rb_hash_aset(hash, rb_external_str_new_cstr(name), it);
}

return hash;
Expand Down Expand Up @@ -639,10 +643,24 @@ VALUE ltranspose(VALUE list, int *dims, int *strides,

/* Convert a R Array to a Ruby Array (in the form of
* array of arrays of ...) */
VALUE to_ruby_array(VALUE obj, int *dims, int l)
VALUE to_ruby_array(VALUE obj, SEXP robj)
{
VALUE list;
int i, c, *strides;
VALUE rarrayComponents[3]; //values, dimnames, dimnamesnames
VALUE cRArray;
VALUE rarray;
SEXP dim;
int i, c, *strides,l;
int *dims;
int status;
dim = GET_DIM(robj);
dims = INTEGER(dim);
l = GET_LENGTH(dim);
status = to_ruby_vector(GET_DIMNAMES(robj),&rarrayComponents[1],VECTOR_CONVERSION);
if (!status)
rb_raise(rb_eRuntimeError,"Could not convert dimnames\n");
status = to_ruby_vector(GET_NAMES(GET_DIMNAMES(robj)),&rarrayComponents[2],VECTOR_CONVERSION);
if (!status)
rb_raise(rb_eRuntimeError,"Could not convert dimnames names\n");

strides = (int *)ALLOC_N(int,l);
if (!strides)
Expand All @@ -654,8 +672,11 @@ VALUE to_ruby_array(VALUE obj, int *dims, int l)
c *= dims[i];
}

list = ltranspose(obj, dims, strides, 0, 0, l);
rarrayComponents[0] = ltranspose(obj, dims, strides, 0, 0, l);
free(strides);

return list;
cRArray = rb_const_get(rb_cObject,rb_intern("RArray"));
rarray = rb_class_new_instance(3,rarrayComponents,cRArray);

return rarray;
}
5 changes: 3 additions & 2 deletions ext/Converters.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

//Converters for Ruby to R
SEXP ruby_to_R(VALUE val);
VALUE ruby_to_Robj(VALUE self,VALUE args);

SEXP array_to_R(VALUE obj);
SEXP hash_to_R(VALUE obj);
Expand All @@ -55,10 +56,10 @@ VALUE call_proc(VALUE data);
VALUE reset_mode(VALUE mode);

VALUE to_ruby_hash(VALUE obj, SEXP names);
VALUE to_ruby_array(VALUE obj, int *dims, int l);
VALUE to_ruby_array(VALUE obj, SEXP robj);

VALUE ltranspose(VALUE list, int *dims, int *strides,
int pos, int shift, int len);
int pos, int shift, int len);

//Macros for quick checks
#define Robj_Check(v) (rb_obj_is_instance_of(v,rb_const_get(rb_cObject,rb_intern("RObj"))))
Expand Down
2 changes: 1 addition & 1 deletion ext/R_eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ SEXP get_fun_from_name(char *ident) {
}

/* Obtain the text of the last R error message */
char *get_last_error_msg() {
const char *get_last_error_msg() {
SEXP msg;

msg = do_eval_fun("geterrmessage");
Expand Down
2 changes: 1 addition & 1 deletion ext/R_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ SEXP get_fun_from_name(char *);
/* Interrupt the R interpreter */
void interrupt_R(int);

char *get_last_error_msg(void);
const char *get_last_error_msg(void);
11 changes: 8 additions & 3 deletions ext/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,24 @@
exit 1
end

some_include_paths = some_paths.map{|dir| File.join(dir, 'include') } + %w[/usr/include/R]
some_include_paths = some_paths.map{|dir| File.join(dir, 'include') } + %w[/usr/include/R] + %w[/usr/share/R/include]
find_header('R.h', nil, *some_include_paths)

unless have_header("R.h")
$stderr.puts "\nERROR: Cannot find the R header, aborting."
exit 1
end

def r_home
@r_home ||=
$configure_args['--with-R-dir'] ||
%x(R RHOME 2>/dev/null).gsub(/[\r\n]/,"")
end

File.open("config.h", "w") do |f|
f.puts("#ifndef R_CONFIG_H")
f.puts("#define R_CONFIG_H")
r_home = $configure_args.has_key?('--with-R-dir') ? $configure_args['--with-R-dir'].inspect : 'NULL'
f.puts("#define RSRUBY_R_HOME #{r_home}")
f.puts("#define RSRUBY_R_HOME \"#{r_home}\"") if Dir.exist?(r_home)
f.puts("#endif")
end
$extconf_h = 'config.h'
Expand Down
36 changes: 16 additions & 20 deletions ext/rsruby.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
/* This is inspired in $R_SRC/src/main/memory.c */
static SEXP R_References;
void protect_robj(SEXP robj){
R_References = CONS(robj, R_References);
SET_SYMVALUE(install("R.References"), R_References);
R_PreserveObject(robj);
}

SEXP
Expand All @@ -55,16 +54,10 @@ RecursiveRelease(SEXP obj, SEXP list)

/* TODO: This needs implementing as a Ruby destructor for each RObj */
void
Robj_dealloc(VALUE self)
Robj_dealloc(SEXP robj)
{
SEXP robj;

Data_Get_Struct(self, struct SEXPREC, robj);

R_References = RecursiveRelease(robj, R_References);
SET_SYMVALUE(install("R.References"), R_References);

return;
R_ReleaseObject(robj);

}


Expand Down Expand Up @@ -101,9 +94,6 @@ VALUE get_fun(VALUE self, VALUE name){
//TODO - This function does not appear to be working correctly
void r_finalize(void)
{
unsigned char buf[1024];
char * tmpdir;

R_dot_Last();
R_gc(); /* Remove any remaining R objects from memory */
}
Expand All @@ -124,7 +114,7 @@ VALUE rs_shutdown(VALUE self){
*/
VALUE rr_init(VALUE self){


init_R(0,NULL);
// Initialize the list of protected objects
R_References = R_NilValue;
Expand All @@ -141,10 +131,15 @@ void init_R(int argc, char **argv){

char *defaultArgv[] = {"rsruby","-q","--vanilla"};

if (RSRUBY_R_HOME) {
setenv("R_HOME", RSRUBY_R_HOME, 0);
}
Rf_initEmbeddedR(sizeof(defaultArgv) / sizeof(defaultArgv[0]), defaultArgv);
#ifdef RSRUBY_R_HOME
setenv("R_HOME", RSRUBY_R_HOME, 0);
#endif

// Rf_initEmbeddedR(sizeof(defaultArgv) / sizeof(defaultArgv[0]), defaultArgv);
Rf_initialize_R(sizeof(defaultArgv) / sizeof(defaultArgv[0]), defaultArgv);
R_Interactive = TRUE;
R_CStackLimit = (uintptr_t)-1; //disable stack limit checking
setup_Rmainloop();
R_Interactive = FALSE; //Remove crash menu (and other interactive R features)
}

Expand All @@ -170,13 +165,14 @@ void Init_rsruby_c(){
rb_define_method(cRRuby, "shutdown", rs_shutdown, 0);

rb_define_method(cRRuby, "crash", crash, 0);
rb_define_method(cRRuby, "to_R", ruby_to_Robj, 1);

//Add the lcall method to RObj
cRObj = rb_const_get(rb_cObject,rb_intern("RObj"));
rb_define_method(cRObj, "lcall", RObj_lcall, 1);
rb_define_method(cRObj, "__init_lcall__", RObj_init_lcall, 1);
rb_define_method(cRObj, "to_ruby", RObj_to_ruby, -2);
rb_define_method(cRObj, "to_R", ruby_to_R, 1);


}

10 changes: 4 additions & 6 deletions ext/rsruby.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@

#ifndef R_RUBY_MAIN
#define R_RUBY_MAIN

#define CSTACK_DEFNS
#include "ruby.h"

#include "R.h"
#include "Rdefines.h"
#include "Rinternals.h"
#include "Rdefines.h"

#include "Rinterface.h"
#include "Rembedded.h"
#include "signal.h"

#include "R_eval.h"
Expand All @@ -58,8 +58,6 @@

/* Missing definitions from Rinterface.h or RStartup.h */
# define CleanEd Rf_CleanEd
extern int Rf_initEmbeddedR(int argc, char **argv);
extern int R_Interactive;
extern void CleanEd(void);
extern int R_CollectWarnings;
# define PrintWarnings Rf_PrintWarnings
Expand All @@ -84,6 +82,6 @@ VALUE RObj_init_lcall(VALUE self, VALUE args);
VALUE RObj_to_ruby(VALUE self, VALUE args);
int make_argl(VALUE args, SEXP *e);
void protect_robj(SEXP robj);
void Robj_dealloc(VALUE self);
void Robj_dealloc(SEXP robj);
#endif

28 changes: 23 additions & 5 deletions lib/rsruby.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'rsruby/robj'
require 'rsruby/rarray'
require 'rsruby_c'
require 'singleton'

Expand Down Expand Up @@ -133,8 +134,7 @@ def method_missing(r_id,*args)
#Translate Ruby method call to R
robj_name = RSRuby.convert_method_name(r_id.to_s)

#Retrieve it
robj = self.__getitem__(robj_name)
robj = robj_name =~ /(.+)::(.+)/ ? self.send('::',$1,$2) : self.__getitem__(robj_name)

#TODO perhaps this is not neccessary - always call these methods
#use the [] syntax for variables etc...
Expand Down Expand Up @@ -181,9 +181,9 @@ def RSRuby.convert_method_name(name)
if name.length > 1 and name[-1].chr == '_' and name[-2].chr != '_'
name = name[0..-2]
end
name.gsub!(/__/,'<-')
name.gsub!(/_/, '.')
return name
newname = name.gsub(/__/,'<-')
newname = name.gsub(/_/, '.')
return newname
end

#Converts an Array of function arguments into lcall format. If the last
Expand Down Expand Up @@ -299,4 +299,22 @@ def __getitem__(name,init=false)
end

class RException < RuntimeError
def initialize(_msg)
e = RSRuby.get_default_mode
RSRuby.set_default_mode(RSRuby::VECTOR_CONVERSION )
if RSRuby.instance.exists('traceback.character')[0]
@r_traceback = RSRuby.instance.traceback_character('max.lines'=>10)
else
r_full_traceback = RSRuby.instance.get(".Traceback")
r_shortened_traceback = r_full_traceback.map{|x| x.first(10)}
@r_traceback = r_shortened_traceback.flatten
end
RSRuby.set_default_mode(e)
super
end
def backtrace
x = super
return x if x.nil?
@r_traceback +x
end
end
Loading