rsruby 0.4.5 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ = 0.5 2008-04-18
2
+
3
+ * Added easy figure method RSRuby.img()
4
+ * Removed R interactive features.
5
+ * Extra test cases
6
+
1
7
  = 0.4.2 2007-01-09
2
8
 
3
9
  * Several bugs in the conversion system are fixed
data/Manifest.txt CHANGED
@@ -1,7 +1,8 @@
1
1
  History.txt
2
2
  License.txt
3
3
  Manifest.txt
4
- README.txt
4
+ README.txt
5
+ Rakefile.rb
5
6
  examples/arrayfields.rb
6
7
  examples/bioc.rb
7
8
  examples/dataframe.rb
@@ -27,6 +28,7 @@ test/tc_extensions.rb
27
28
  test/tc_init.rb
28
29
  test/tc_io.rb
29
30
  test/tc_library.rb
31
+ test/tc_matrix.rb
30
32
  test/tc_modes.rb
31
33
  test/tc_robj.rb
32
34
  test/tc_sigint.rb
data/Rakefile.rb ADDED
@@ -0,0 +1,153 @@
1
+ require 'hoe'
2
+
3
+ $LOAD_PATH.unshift("./lib")
4
+ $LOAD_PATH.unshift("./ext")
5
+
6
+ gem_name = RUBY_PLATFORM !~ /mswin32$/ ? "rsruby" : "rsrubywin"
7
+ hoe = Hoe.new(gem_name,'0.5') do |p|
8
+
9
+ p.author = "Alex Gutteridge"
10
+ p.email = "ag357@cam.ac.uk"
11
+ p.url = "http://web.kuicr.kyoto-u.ac.jp/~alexg/rsruby/"
12
+
13
+ p.description = p.paragraphs_of("README.txt",1..3)[0]
14
+ p.summary = p.paragraphs_of("README.txt",1)[0]
15
+ p.changes = p.paragraphs_of("History.txt",0..1).join("\n\n")
16
+
17
+ p.clean_globs = ["ext/*.o","ext/*.so","ext/Makefile","ext/mkmf.log","**/*~","email.txt","manual.{aux,log,out,toc,pdf}"]
18
+
19
+ p.rdoc_pattern = /(^lib\/.*\.rb$|^examples\/.*\.rb$|^README|^History|^License)/
20
+
21
+ p.spec_extras = {
22
+ :extensions => RUBY_PLATFORM !~ /mswin32$/ ? ['ext/extconf.rb'] : [],
23
+ :require_paths => ['lib','test','ext'],
24
+ :has_rdoc => true,
25
+ :extra_rdoc_files => ["README.txt","History.txt","License.txt"] + FileList["examples/*"],
26
+ :rdoc_options => ["--exclude", "test/*", "--main", "README.txt", "--inline-source"]
27
+ }
28
+
29
+ task :setup_rb_package => [:clean, :package] do
30
+
31
+ package_dir = "#{p.name}-#{p.version}"
32
+ cp("setup.rb","pkg/#{package_dir}")
33
+ #cp("manual.pdf","pkg/#{package_dir}")
34
+
35
+ Dir.chdir("pkg")
36
+ system("tar -czf #{p.name}-#{p.version}.tgz #{package_dir}")
37
+ Dir.chdir("..")
38
+
39
+ end
40
+
41
+ end
42
+
43
+ hoe.spec.dependencies.delete_if{|dep| dep.name == "hoe"}
44
+ if RUBY_PLATFORM =~ /mswin32$/
45
+ # add the precompiled rsruby_c.so into the gemspec
46
+ hoe.spec.files = hoe.spec.files + ["ext/rsruby_c.so"]
47
+
48
+ # add the :build_extension task to :gem so that the extension gets
49
+ # built BEFORE packaging (note the task needs to occur first)
50
+ Rake.application.lookup(:gem).prerequisites.unshift(:build_extension)
51
+ end
52
+
53
+ desc "Uses extconf.rb and make to build the extension"
54
+ task :build_extension => ['ext/rsruby_c.so']
55
+ SRC = FileList['ext/*.c'] + FileList['ext/*.h']
56
+ file 'ext/rsruby_c.so' => SRC do
57
+ Dir.chdir('ext')
58
+ if RUBY_PLATFORM !~ /mswin32$/
59
+ system("ruby extconf.rb -- --with-R-dir=$R_HOME --with-R-include=/usr/share/R/include/")
60
+ system("make")
61
+ else
62
+ # Windows-specific build that does not use extconf.rb or make
63
+ # This build was designed using the default One-Click Installer
64
+ # for Windows (1.8.6-25) and MinGW (5.1.3). Both are freely
65
+ # available. See the following websites for downloads and
66
+ # installation information:
67
+ #
68
+ # http://rubyforge.org/projects/rubyinstaller/
69
+ # http://www.mingw.org/
70
+ #
71
+
72
+ # TODO -
73
+ # * add checks for installation paths
74
+ # * rewrite this build in terms of rake rules? (or at least check
75
+ # so that up-to-date files are not rebuilt)
76
+ # * add configuration options a-la extconf.rb
77
+
78
+ # Note: here I use slashes '/' rather than backslashes '\' in the paths.
79
+ # If you enter the gcc command into the command prompt, you do NOT
80
+ # need to use the *nix-style paths. Here it's necessary so the backslashes
81
+ # aren't treated as character escapes in the ruby strings.
82
+ ruby_install_dir = ENV['RUBY_INSTALL_DIR'] || "C:/ruby"
83
+ ruby_headers_dir = "#{ruby_install_dir}/lib/ruby/1.8/i386-mswin32"
84
+ ruby_lib_dir = "#{ruby_install_dir}/lib"
85
+
86
+ r_install_dir = ENV['R_INSTALL_DIR'] || "C:/Program Files/R/R-2.6.0"
87
+ r_headers_dir = "#{r_install_dir}/include"
88
+ r_lib_dir = "#{r_install_dir}/bin"
89
+
90
+ # These defines are all added for a clean compile. I'm not sure if
91
+ # setting these flags is appropriate, but they do work.
92
+ # HAVE_R_H:: extconf.rb includes this flag
93
+ # HAVE_ISINF:: prevents "isinf" redefinition
94
+ # _MSC_VER:: prevents "MSC version unmatch" error -- it may not be smart to bypass this check
95
+ # STRICT_R_HEADERS:: prevents "ERROR" redefinition
96
+ defines = "-DHAVE_R_H -DHAVE_ISINF -D_MSC_VER=1200 -DSTRICT_R_HEADERS"
97
+
98
+ # check required files exist
99
+ [ruby_headers_dir, ruby_lib_dir].each do |dir|
100
+ next if File.exists?(dir)
101
+ raise %Q{
102
+ Build Error:
103
+ ruby directory does not exist (#{dir})
104
+ Try setting RUBY_INSTALL_DIR to the ruby installation directory.
105
+
106
+ }
107
+ end
108
+
109
+ [r_headers_dir, r_lib_dir].each do |dir|
110
+ next if File.exists?(dir)
111
+ raise %Q{
112
+ Build Error:
113
+ R directory does not exist (#{dir})
114
+ Try setting R_INSTALL_DIR to the R installation directory.
115
+
116
+ }
117
+ end
118
+
119
+ OBJ = SRC.collect do |src|
120
+ next unless File.extname(src) == ".c"
121
+
122
+ # at this point the src files are like 'ext/src.c'
123
+ src = File.basename(src)
124
+
125
+ # compile each source file, using the same flags as extconf.rb
126
+ # notice the quotes encapsulating the include paths, so that
127
+ # spaces are allowed (as in the R default install path)
128
+ sh( %Q{gcc -I. -I"#{ruby_headers_dir}" -I"#{r_headers_dir}" #{defines} -g -O2 -c #{src}} )
129
+
130
+ # double duty... collect the .o filenames
131
+ File.basename(src).chomp(".c") + ".o"
132
+ end.compact
133
+
134
+ # same notes as extconf.rb
135
+ sh( %Q{gcc -shared -s -L. -Wl,--enable-auto-image-base,--enable-auto-import,--export-all -L"#{ruby_lib_dir}" -L"#{r_lib_dir}" -o rsruby_c.so #{OBJ.join(" ")} -lmsvcrt-ruby18 -lR -lwsock32})
136
+ end
137
+ Dir.chdir('..')
138
+ end
139
+
140
+ task :test => [:build_extension]
141
+
142
+ desc "Build PDF manual"
143
+ task :build_manual => ["manual.pdf"]
144
+ file "manual.pdf" => ["manual.tex"] do
145
+ out = 'Rerun'
146
+ while out.match(/Rerun/)
147
+ out = `pdflatex manual.tex`
148
+ end
149
+ end
150
+
151
+ task :build_manual_clean => [:build_manual] do
152
+ system("rm manual.{aux,log,out,toc}")
153
+ end
data/ext/Converters.c CHANGED
@@ -38,6 +38,8 @@
38
38
  SEXP ruby_to_R(VALUE obj)
39
39
  {
40
40
  SEXP robj;
41
+ VALUE str;
42
+ char buf [100];
41
43
 
42
44
  //Return nil if object is nil
43
45
  if (obj == Qnil) {
@@ -99,7 +101,10 @@ SEXP ruby_to_R(VALUE obj)
99
101
  }
100
102
  else
101
103
  {
102
- rb_raise(rb_eArgError,"Unsupported object passed to R.\n");
104
+ str = rb_funcall(obj,rb_intern("inspect"),0);
105
+ str = rb_funcall(str,rb_intern("slice"),2,INT2NUM(0),INT2NUM(60));
106
+ sprintf(buf,"Unsupported object '%s' passed to R.\n",RSTRING(str)->ptr);
107
+ rb_raise(rb_eArgError,buf);
103
108
  PROTECT(robj = NULL); /* Protected to avoid stack inbalance */
104
109
  }
105
110
 
@@ -143,8 +148,8 @@ SEXP array_to_R(VALUE obj)
143
148
 
144
149
  state = -1;
145
150
  for (i=0; i<RARRAY(obj)->len; i++) {
146
- if (!(it = rb_ary_entry(obj, i)))
147
- goto exception;
151
+
152
+ it = rb_ary_entry(obj, i);
148
153
 
149
154
  if (state < 0)
150
155
  state = type_to_int(it);
@@ -183,6 +188,7 @@ SEXP array_to_R(VALUE obj)
183
188
 
184
189
  exception:
185
190
  UNPROTECT(1);
191
+ rb_raise(rb_eArgError,"Error converting Array to R\n");
186
192
  return NULL;
187
193
  }
188
194
 
@@ -193,6 +199,12 @@ hash_to_R(VALUE obj)
193
199
  VALUE keys, values;
194
200
  SEXP robj, names;
195
201
 
202
+ //TODO - Baffling. Not sure what's wrong with these functions?
203
+ //rb_hash_keys(proc_table);
204
+ //rb_hash_values(proc_table);
205
+ //rb_hash_size(proc_table);
206
+ //compiles, but complains they are undefined symbols when run...
207
+
196
208
  if (FIX2INT(rb_funcall(obj,rb_intern("size"),0)) == 0)
197
209
  return R_NilValue;
198
210
 
@@ -421,12 +433,15 @@ from_proc_table(SEXP robj, VALUE *fun)
421
433
  VALUE args[2];
422
434
  int i, l, error;
423
435
 
424
- proc_table = rb_cvar_get(rb_const_get(rb_cObject,
425
- rb_intern("RSRuby")),
426
- rb_intern("@@proc_table"));
436
+ proc_table = rb_iv_get(RSRUBY,"@proc_table");
427
437
 
428
438
  proc = Qnil;
429
439
 
440
+ //TODO - Baffling. Not sure what's wrong with these functions?
441
+ //procs = rb_hash_keys(proc_table);
442
+ //funs = rb_hash_values(proc_table);
443
+ //l = FIX2INT(rb_hash_size(proc_table));
444
+
430
445
  procs = rb_funcall(proc_table,rb_intern("keys"),0);
431
446
  funs = rb_funcall(proc_table,rb_intern("values"),0);
432
447
  l = FIX2INT(rb_funcall(proc_table,rb_intern("size"),0));
@@ -440,13 +455,10 @@ from_proc_table(SEXP robj, VALUE *fun)
440
455
  for (i=0; i<l; i++) {
441
456
  proc = rb_ary_entry(procs, i);
442
457
 
443
- mode = rb_cvar_get(rb_const_get(rb_cObject,
444
- rb_intern("RSRuby")),
445
- rb_intern("@@default_mode"));
446
- rb_cvar_set(rb_const_get(rb_cObject,
447
- rb_intern("RSRuby")),
448
- rb_intern("@@default_mode"),
449
- INT2FIX(BASIC_CONVERSION),Qtrue);
458
+ mode = rb_iv_get(RSRUBY,"@default_mode");
459
+ rb_iv_set(RSRUBY,
460
+ "@default_mode",
461
+ INT2FIX(BASIC_CONVERSION));
450
462
 
451
463
  //New safe code
452
464
  args[0] = proc;
@@ -469,10 +481,9 @@ VALUE call_proc(VALUE data){
469
481
 
470
482
  VALUE reset_mode(VALUE mode){
471
483
 
472
- rb_cvar_set(rb_const_get(rb_cObject,
473
- rb_intern("RSRuby")),
474
- rb_intern("@@default_mode"),
475
- mode,Qtrue);
484
+ rb_iv_set(RSRUBY,
485
+ "@default_mode",
486
+ mode);
476
487
 
477
488
  return Qnil;
478
489
 
@@ -504,13 +515,8 @@ to_ruby_proc(SEXP robj, VALUE *obj)
504
515
  rb_iv_set(tmp,"@wrap",Qfalse);
505
516
 
506
517
  //Again set conversion mode to basic to prevent recursion
507
- mode = rb_cvar_get(rb_const_get(rb_cObject,
508
- rb_intern("RSRuby")),
509
- rb_intern("@@default_mode"));
510
- rb_cvar_set(rb_const_get(rb_cObject,
511
- rb_intern("RSRuby")),
512
- rb_intern("@@default_mode"),
513
- INT2FIX(BASIC_CONVERSION),Qtrue);
518
+ mode = rb_iv_get(RSRUBY,"@default_mode");
519
+ rb_iv_set(RSRUBY, "@default_mode", INT2FIX(BASIC_CONVERSION));
514
520
 
515
521
  //New safe code
516
522
  args[0] = fun;
@@ -527,9 +533,7 @@ VALUE from_class_table(SEXP robj)
527
533
  VALUE key, fun, class_table;
528
534
  int i;
529
535
 
530
- class_table = rb_cvar_get(rb_const_get(rb_cObject,
531
- rb_intern("RSRuby")),
532
- rb_intern("@@class_table"));
536
+ class_table = rb_iv_get(RSRUBY, "@class_table");
533
537
 
534
538
  PROTECT(rclass = GET_CLASS(robj));
535
539
 
@@ -577,13 +581,8 @@ to_ruby_class(SEXP robj, VALUE *obj)
577
581
  rb_iv_set(tmp,"@wrap",Qfalse);
578
582
 
579
583
  //Again set conversion mode to basic to prevent recursion
580
- mode = rb_cvar_get(rb_const_get(rb_cObject,
581
- rb_intern("RSRuby")),
582
- rb_intern("@@default_mode"));
583
- rb_cvar_set(rb_const_get(rb_cObject,
584
- rb_intern("RSRuby")),
585
- rb_intern("@@default_mode"),
586
- INT2FIX(BASIC_CONVERSION),Qtrue);
584
+ mode = rb_iv_get(RSRUBY, "@default_mode");
585
+ rb_iv_set(RSRUBY, "@default_mode", INT2FIX(BASIC_CONVERSION));
587
586
 
588
587
  //New safe code
589
588
  args[0] = fun;
data/ext/Converters.h CHANGED
@@ -58,7 +58,7 @@ VALUE to_ruby_hash(VALUE obj, SEXP names);
58
58
  VALUE to_ruby_array(VALUE obj, int *dims, int l);
59
59
 
60
60
  VALUE ltranspose(VALUE list, int *dims, int *strides,
61
- int pos, int shift, int len);
61
+ int pos, int shift, int len);
62
62
 
63
63
  //Macros for quick checks
64
64
  #define Robj_Check(v) (rb_obj_is_instance_of(v,rb_const_get(rb_cObject,rb_intern("RObj"))))
data/ext/extconf.rb CHANGED
@@ -10,4 +10,4 @@ unless have_header("R.h")
10
10
  exit 1
11
11
  end
12
12
 
13
- create_makefile("rsruby")
13
+ create_makefile("rsruby_c")
data/ext/robj.c CHANGED
@@ -70,9 +70,7 @@ VALUE RObj_lcall(VALUE self, VALUE args){
70
70
  return Qnil;
71
71
  }
72
72
 
73
- default_mode = NUM2INT(rb_cvar_get(rb_const_get(rb_cObject,
74
- rb_intern("RSRuby")),
75
- rb_intern("@@default_mode")));
73
+ default_mode = NUM2INT(rb_iv_get(RSRUBY,"@default_mode"));
76
74
 
77
75
  // Convert
78
76
  if (default_mode < 0){
@@ -88,6 +86,45 @@ VALUE RObj_lcall(VALUE self, VALUE args){
88
86
  return obj;
89
87
  }
90
88
 
89
+
90
+ //lcall method that is safe to call during RSRuby initialisation
91
+ VALUE RObj_init_lcall(VALUE self, VALUE args){
92
+ SEXP exp, e, res;
93
+ SEXP r_obj;
94
+ VALUE obj;
95
+
96
+ //Ensure we have an array
97
+ args = rb_check_array_type(args);
98
+
99
+ // A SEXP with the function to call and the arguments
100
+ PROTECT(exp = allocVector(LANGSXP, (RARRAY(args)->len)+1));
101
+ e = exp;
102
+
103
+ Data_Get_Struct(self, struct SEXPREC, r_obj);
104
+
105
+ SETCAR(e, r_obj);
106
+ e = CDR(e);
107
+
108
+ // Add the arguments to the SEXP
109
+ if (!make_argl(args, &e)) {
110
+ UNPROTECT(1);
111
+ return Qnil;
112
+ }
113
+
114
+ // Evaluate
115
+ PROTECT(res = do_eval_expr(exp));
116
+ if (!res) {
117
+ UNPROTECT(2);
118
+ return Qnil;
119
+ }
120
+
121
+ obj = to_ruby_with_mode(res, BASIC_CONVERSION);
122
+
123
+ UNPROTECT(2);
124
+
125
+ return obj;
126
+ }
127
+
91
128
  /* Convert a sequence of (name, value) pairs to arguments to an R
92
129
  function call */
93
130
  int
@@ -145,9 +182,7 @@ VALUE RObj_to_ruby(VALUE self, VALUE args){
145
182
  }
146
183
 
147
184
  if (RARRAY(args)->len == 0){
148
- conv = NUM2INT(rb_cvar_get(rb_const_get(rb_cObject,
149
- rb_intern("RSRuby")),
150
- rb_intern("@@default_mode")));
185
+ conv = NUM2INT(rb_iv_get(RSRUBY,"@default_mode"));
151
186
  } else {
152
187
  conv = NUM2INT(rb_ary_entry(args,0));
153
188
  }
data/ext/rsruby.c CHANGED
@@ -33,7 +33,7 @@
33
33
 
34
34
  /* Global list to protect R objects from garbage collection */
35
35
  /* This is inspired in $R_SRC/src/main/memory.c */
36
- static SEXP R_References;
36
+ //static SEXP R_References;
37
37
 
38
38
  SEXP
39
39
  RecursiveRelease(SEXP obj, SEXP list)
@@ -48,19 +48,18 @@ RecursiveRelease(SEXP obj, SEXP list)
48
48
  }
49
49
 
50
50
  /* TODO: This needs implementing as a Ruby destructor for each RObj */
51
- void
52
- Robj_dealloc(VALUE self)
53
- {
54
- /* Remove the object from the list of protected objects */
51
+ /*static void
52
+ Robj_dealloc(VALUE self)
53
+ {
55
54
  SEXP robj;
56
-
55
+
57
56
  Data_Get_Struct(self, struct SEXPREC, robj);
58
-
57
+
59
58
  R_References = RecursiveRelease(robj, R_References);
60
59
  SET_SYMVALUE(install("R.References"), R_References);
61
-
60
+
62
61
  return;
63
- }
62
+ }*/
64
63
 
65
64
 
66
65
  /* Obtain an R object via its name.
@@ -73,7 +72,6 @@ VALUE get_fun(VALUE self, VALUE name){
73
72
  int conversion=TOP_MODE;
74
73
  SEXP robj;
75
74
  VALUE rubyobj;
76
- //VALUE params[2];
77
75
  char* cstr_name;
78
76
 
79
77
  str = StringValue(name);
@@ -104,6 +102,7 @@ void r_finalize(void)
104
102
  R_RunExitFinalizers();
105
103
  CleanEd();
106
104
  KillAllDevices();
105
+
107
106
  if((tmpdir = getenv("R_SESSION_TMPDIR"))) {
108
107
  snprintf((char *)buf, 1024, "rm -rf %s", tmpdir);
109
108
  R_system((char *)buf);
@@ -116,9 +115,10 @@ void r_finalize(void)
116
115
  /*
117
116
  * Shutdown the R interpreter
118
117
  */
119
- VALUE cShutdown(VALUE self){
118
+ VALUE rs_shutdown(VALUE self){
120
119
 
121
120
  r_finalize();
121
+ Rf_endEmbeddedR(0);
122
122
  return Qtrue;
123
123
 
124
124
  }
@@ -147,24 +147,36 @@ void init_R(int argc, char **argv){
147
147
  char *defaultArgv[] = {"rsruby","-q","--vanilla"};
148
148
 
149
149
  Rf_initEmbeddedR(sizeof(defaultArgv) / sizeof(defaultArgv[0]), defaultArgv);
150
+ R_Interactive = FALSE; //Remove crash menu (and other interactive R features)
150
151
  }
152
+
153
+ /* This method is for testing catching of segfaults */
154
+ VALUE crash(){
155
+ int* ptr = (int*)0;
156
+ *ptr = 1;
157
+ return Qtrue;
158
+ }
159
+
151
160
 
152
161
  /* Ruby code */
153
162
 
154
163
  VALUE cRRuby;
155
164
  VALUE cRObj;
156
165
 
157
- void Init_rsruby(){
166
+ void Init_rsruby_c(){
158
167
 
159
168
  cRRuby = rb_define_class("RSRuby",rb_cObject);
160
- cRObj = rb_const_get(rb_cObject,rb_intern("RObj"));
161
169
 
162
- rb_define_method(cRRuby, "initialize", rr_init, 0);
170
+ rb_define_method(cRRuby, "r_init", rr_init, 0);
163
171
  rb_define_method(cRRuby, "get_fun", get_fun, 1);
164
- rb_define_method(cRRuby, "shutdown", cShutdown, 0);
172
+ rb_define_method(cRRuby, "shutdown", rs_shutdown, 0);
173
+
174
+ rb_define_method(cRRuby, "crash", crash, 0);
165
175
 
166
176
  //Add the lcall method to RObj
177
+ cRObj = rb_const_get(rb_cObject,rb_intern("RObj"));
167
178
  rb_define_method(cRObj, "lcall", RObj_lcall, 1);
179
+ rb_define_method(cRObj, "__init_lcall__", RObj_init_lcall, 1);
168
180
  rb_define_method(cRObj, "to_ruby", RObj_to_ruby, -2);
169
181
 
170
182
  }
data/ext/rsruby.h CHANGED
@@ -55,13 +55,16 @@
55
55
 
56
56
  #define TOP_MODE 4
57
57
 
58
+ #define RSRUBY rb_funcall(rb_const_get(rb_cObject,rb_intern("RSRuby")),rb_intern("instance"),0)
59
+
58
60
  /* Missing definitions from Rinterface.h or RStartup.h */
59
61
  # define CleanEd Rf_CleanEd
62
+ extern int Rf_initEmbeddedR(int argc, char **argv);
63
+ extern int R_Interactive;
60
64
  extern void CleanEd(void);
61
65
  extern int R_CollectWarnings;
62
66
  # define PrintWarnings Rf_PrintWarnings
63
67
  extern void PrintWarnings(void);
64
- extern void Rf_initEmbeddedR(int argc, char **argv);
65
68
 
66
69
  void Init_rsruby();
67
70
 
@@ -69,14 +72,16 @@ void init_R(int argc, char *argv[0]);
69
72
  void r_finalize(void);
70
73
 
71
74
  SEXP RecursiveRelease(SEXP obj, SEXP list);
72
- void Robj_dealloc(VALUE self);
75
+ //static void Robj_dealloc(VALUE self);
73
76
 
74
- VALUE shutdown(VALUE self);
77
+ VALUE rs_shutdown(VALUE self);
75
78
  VALUE get_fun(VALUE self, VALUE name);
76
- VALUE rr_init(VALUE self);
79
+ VALUE rr_init(VALUE self);
80
+
81
+ VALUE crash(void);
77
82
 
78
83
  VALUE RObj_lcall(VALUE self, VALUE args);
84
+ VALUE RObj_init_lcall(VALUE self, VALUE args);
79
85
  VALUE RObj_to_ruby(VALUE self, VALUE args);
80
86
  int make_argl(VALUE args, SEXP *e);
81
-
82
87
  #endif
data/lib/rsruby.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'rsruby/robj'
2
- require 'rsruby.so'
2
+ require 'rsruby_c'
3
3
  require 'singleton'
4
4
 
5
5
  require 'complex'
@@ -53,7 +53,7 @@ require 'complex'
53
53
 
54
54
  class RSRuby
55
55
 
56
- VERSION = '0.4.3'
56
+ VERSION = '0.5'
57
57
 
58
58
  include Singleton
59
59
 
@@ -66,40 +66,63 @@ class RSRuby
66
66
  NO_CONVERSION = 0
67
67
  NO_DEFAULT = -1
68
68
 
69
- alias c_initialize initialize
69
+ attr_accessor :proc_table, :class_table, :default_mode, :caching
70
70
 
71
71
  #Create a new RSRuby interpreter instance. The Singleton design pattern
72
72
  #ensures that only one instance can be running in a script. Further
73
73
  #calls to RSRuby.instance will return the original instance.
74
74
  def initialize()
75
75
 
76
- #Initialize in C
77
- c_initialize
76
+ #Initialize R
77
+ r_init
78
78
 
79
- @@default_mode = NO_DEFAULT
79
+ @default_mode = NO_DEFAULT
80
80
 
81
- @@class_table = {}
82
- @@proc_table = {}
81
+ @class_table = {}
82
+ @proc_table = {}
83
+
84
+ @caching = true
85
+ reset_cache
86
+
87
+ #Catch errors
88
+ self.__init_eval_R__("options(error=expression(NULL))")
89
+ #disable errors
90
+ self.__init_eval_R__("options(show.error.messages=F)")
83
91
 
92
+ end
93
+
94
+ def reset_cache
84
95
  #Setup R object cache
85
- @@cache = {}
86
- @@cache['get'] = self.get_fun('get')
96
+ @cache = {}
97
+ @cache['get'] = self.get_fun('get')
87
98
 
88
99
  #Get constants
89
- @@cache['TRUE'] = self.__getitem__('T')
90
- @@cache['FALSE'] = self.__getitem__('F')
91
- @@cache['NA'] = self.eval_R('NA')
92
- # @@cache['NAN'] = self.eval_R('as.double(NA)')
93
- @@cache['NaN'] = self.eval_R('NaN')
100
+ @cache['TRUE'] = self.__getitem__('T',true)
101
+ @cache['FALSE'] = self.__getitem__('F',true)
102
+
103
+ @cache['parse'] = self.__getitem__('parse',true)
104
+ @cache['eval'] = self.__getitem__('eval',true)
105
+
106
+ @cache['NA'] = self.__init_eval_R__('NA')
107
+ @cache['NaN'] = self.__init_eval_R__('NaN')
108
+ # @cache['NAN'] = self.eval_R('as.double(NA)')
94
109
 
95
110
  #help!
96
- @@cache['helpfun'] = self.with_mode(NO_CONVERSION, self.__getitem__('help'))
97
-
98
- #Catch errors
99
- self.eval_R("options(error=expression(NULL))")
100
- #disable errors
101
- self.options('show.error.messages' => false)
111
+ @cache['helpfun'] = self.with_mode(NO_CONVERSION, self.__getitem__('help',true))
112
+ end
113
+
114
+ #Delete an R object from the cache. Use R-style function naming, not ruby style.
115
+ def delete_from_cache(x)
116
+ @cache.delete(x)
117
+ end
102
118
 
119
+ def self.img(filename,args={})
120
+ format = File.extname(filename).gsub(".","").to_sym
121
+ r = RSRuby.instance
122
+ raise ArgumentError, "Format #{format.to_s} is not supported" unless [:pdf].include? format
123
+ r.pdf(filename,args)
124
+ yield(r)
125
+ r.dev_off.call
103
126
  end
104
127
 
105
128
  #Handles method name conversion and calling of R functions
@@ -193,15 +216,17 @@ class RSRuby
193
216
 
194
217
  #Sets the default conversion mode for RSRuby. The constants defined
195
218
  #in #RSRuby should be used
219
+ #DEPRECATED: Use the accessor instead
196
220
  def RSRuby.set_default_mode(m)
197
221
  if m < -1 or m > TOP_CONVERSION
198
222
  raise ArgumentError, "Invalid mode requested"
199
223
  end
200
- @@default_mode = m
224
+ RSRuby.instance.default_mode = m
201
225
  end
202
226
  #Returns the current default conversion mode as an Integer.
227
+ #DEPRECATED: Use the accessor on the RSRuby instance isntead
203
228
  def RSRuby.get_default_mode
204
- @@default_mode
229
+ RSRuby.instance.default_mode
205
230
  end
206
231
 
207
232
  #TODO - not implemented
@@ -234,46 +259,38 @@ class RSRuby
234
259
  @@rsruby_showfiles
235
260
  end
236
261
 
237
- #Returns the current class table Hash for RSRuby.
238
- def class_table
239
- @@class_table
240
- end
241
-
242
- #Sets the RSRuby class table Hash.
243
- def class_table=(h)
244
- @@class_table = h
245
- end
246
-
247
- #Returns the current proc table Hash for RSRuby.
248
- def proc_table
249
- @@proc_table
250
- end
251
-
252
- #Sets the RSRuby proc table Hash.
253
- def proc_table=(h)
254
- @@proc_table = h
255
- end
256
-
257
262
  #Evaluates the given string in R. Returns the result of the evaluation.
258
263
  def eval_R(s)
259
264
  self.eval(self.parse(:text => s))
260
265
  end
261
266
 
267
+
262
268
  #Wraps the R help function.
263
269
  def help(*args)
264
- helpobj = @@cache['helpfun'].call(args)
270
+ helpobj = @cache['helpfun'].call(args)
265
271
  self.print(helpobj)
266
272
  end
267
273
 
268
- def __getitem__(name)
274
+
275
+ def __init_eval_R__(s)
276
+ parsed = self.parse.__init_lcall__([['text',s]])
277
+ self.eval.__init_lcall__([['',parsed]])
278
+ end
279
+
280
+ def __getitem__(name,init=false)
269
281
 
270
282
  #Find the identifier and cache (unless already cached)
271
- unless @@cache.has_key?(name)
272
- @@cache[name] = @@cache['get'].lcall([['',name]])
283
+ unless @cache.has_key?(name) && @caching
284
+ if init
285
+ robj = @cache['get'].__init_lcall__([['',name]])
286
+ else
287
+ robj = @cache['get'].lcall([['',name]])
288
+ end
289
+ @cache[name] = robj if @caching
273
290
  end
274
291
 
275
292
  #Retrieve object from cache
276
- robj = @@cache[name]
293
+ robj ||= @cache[name]
277
294
 
278
295
  return robj
279
296
 
@@ -55,12 +55,37 @@ class DataFrame < ERObj
55
55
  #Returns an array of the column names used in the R data frame.
56
56
  def columns
57
57
  cols = @r.colnames(@robj)
58
- cols = [cols] unless cols.class == 'Array'
58
+ cols = [cols] unless cols.kind_of?(Array)
59
59
  return cols
60
60
  end
61
61
 
62
- def[](col)
63
- return @r['$'].call(@robj,col.to_s)
62
+ #def[](col)
63
+ # return @r['$'].call(@robj,col.to_s)
64
+ #end
65
+
66
+ #Needs to work for named and numbered columns
67
+ def[](row,col)
68
+ if col.kind_of?(Integer) and !(columns.include?(col))
69
+ col = columns[col]
70
+ end
71
+ return @r['$'].call(@robj,col.to_s)[row]
72
+ end
73
+
74
+ def[]=(row,col,val)
75
+ #How to set a value in this dataframe?
76
+ @r.assign("rsrubytemp",@robj)
77
+
78
+ ### VERY HACKY - This relies on val having the same
79
+ #string representation in R and Ruby. An assign based
80
+ #solution with proper conversion of val would be much
81
+ #better
82
+ @r.eval_R("rsrubytemp[#{row+1},#{col+1}] <- #{val}")
83
+ #
84
+ #@r.assign("rsrubytemp[#{row+1},#{col+1}]",val)
85
+
86
+ @robj = @r.eval_R('get("rsrubytemp")')
87
+
88
+ return @r['$'].call(@robj,columns[col].to_s)[row]
64
89
  end
65
90
 
66
91
  def method_missing(attr)
data/test/tc_array.rb CHANGED
@@ -4,8 +4,8 @@ require 'rsruby'
4
4
  class TestArray < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
-
8
7
  @r = RSRuby.instance
8
+ #@r.gctorture(:on => false)
9
9
  @ruby_AoA = [[[0,6,12,18],[2,8,14,20],[4,10,16,22]],
10
10
  [[1,7,13,19],[3,9,15,21],[5,11,17,23]]]
11
11
 
@@ -16,6 +16,10 @@ class TestArray < Test::Unit::TestCase
16
16
  @r.array.autoconvert(RSRuby::BASIC_CONVERSION)
17
17
  end
18
18
 
19
+ def test_boolean
20
+ assert_equal [true,false], @r.c(true,false)
21
+ end
22
+
19
23
  def test_convert_to_ruby
20
24
  assert_equal(@ruby_AoA,@r_array.to_ruby)
21
25
  end
data/test/tc_boolean.rb CHANGED
@@ -6,6 +6,7 @@ class TestBoolean < Test::Unit::TestCase
6
6
  def setup
7
7
  @r = RSRuby.instance
8
8
  RSRuby.set_default_mode(RSRuby::NO_DEFAULT)
9
+ @r.c.autoconvert(RSRuby::BASIC_CONVERSION)
9
10
  end
10
11
 
11
12
  def test_true
@@ -21,4 +22,9 @@ class TestBoolean < Test::Unit::TestCase
21
22
  @r.as_logical(@r.FALSE))
22
23
  end
23
24
  end
25
+
26
+ def test_boolean_array
27
+ assert_equal([true,false,true,false],@r.c(true,false,true,false))
28
+ end
29
+
24
30
  end
data/test/tc_cleanup.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'test/unit'
2
2
  require 'rsruby'
3
-
3
+
4
4
  class TestCleanup < Test::Unit::TestCase
5
5
 
6
6
  def setup
@@ -8,13 +8,15 @@ class TestCleanup < Test::Unit::TestCase
8
8
  end
9
9
 
10
10
  def test_shutdown
11
- tempdir = @r.tempdir.call
12
- @r.postscript(tempdir+"/foo.ps")
13
- @r.plot(1,1)
14
- @r.dev_off.call
15
- assert(File.exists?(tempdir))
16
- @r.shutdown
17
- assert(!File.exists?(tempdir))
11
+ #@r.eval_R("shutdown_test=10")
12
+ #@r.shutdown
13
+ #assert_raise(RException){ @r.eval_R("shutdown_test") }
14
+ end
15
+
16
+ def test_crash
17
+ #Signal.trap('BUS','EXIT')
18
+ #Signal.trap('BUS',proc{ puts 'hi there'; exit!})
19
+ #@r.crash
18
20
  end
19
21
 
20
22
  end
data/test/tc_eval.rb CHANGED
@@ -5,6 +5,8 @@ class TestEval < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
7
  @r = RSRuby.instance
8
+ @r.proc_table = {}
9
+ @r.class_table = {}
8
10
  end
9
11
 
10
12
  def test_eval_R
@@ -2,7 +2,8 @@ require 'test/unit'
2
2
  require 'rsruby'
3
3
 
4
4
  class TestNewCases < Test::Unit::TestCase
5
-
5
+ @@test_dir = File.expand_path File.dirname(__FILE__)
6
+
6
7
  def test_erobj
7
8
 
8
9
  require 'rsruby/erobj'
@@ -19,8 +20,23 @@ class TestNewCases < Test::Unit::TestCase
19
20
 
20
21
  def test_dataframe
21
22
 
23
+ require 'rsruby/dataframe'
22
24
  r = RSRuby.instance
23
- r.as_data_frame({'x' => [1,2,3], 'row.names' => ['a','b','c']})
25
+ r.class_table['data.frame'] = lambda{|x| DataFrame.new(x)}
26
+ RSRuby.set_default_mode(RSRuby::CLASS_CONVERSION)
27
+ table = r.read_table(@@test_dir+"/table.txt",:header=>true)
28
+ assert_instance_of(DataFrame,table)
29
+
30
+ assert_equal(['A','B','C','D'],table.columns)
31
+ assert_equal([1,2,3],table.rows)
32
+
33
+ #assert_equal(['X1','X2','X3'],table['A'])
34
+ assert_equal('X2',table[1,'A'])
35
+ assert_equal('X2',table[1,0])
36
+
37
+ assert_equal(7,table[1,1])
38
+ table[1,1] = 5
39
+ assert_equal(5,table[1,1])
24
40
 
25
41
  end
26
42
 
data/test/tc_init.rb CHANGED
@@ -0,0 +1,11 @@
1
+ require 'test/unit'
2
+ require 'rsruby'
3
+
4
+ class TestInit < Test::Unit::TestCase
5
+
6
+ def test_init
7
+ assert_nothing_raised(){RSRuby.instance}
8
+ assert_instance_of(RSRuby, RSRuby.instance)
9
+ assert_equal(RSRuby.instance, RSRuby.instance)
10
+ end
11
+ end
data/test/tc_matrix.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'rsruby'
3
+
4
+ class Matrix
5
+ def as_r
6
+ "wibble"
7
+ end
8
+ end
9
+
10
+ class TestMatrix < Test::Unit::TestCase
11
+
12
+ def setup
13
+ @r = RSRuby.instance
14
+ end
15
+
16
+ def test_matrix_no_convert
17
+ r = RSRuby.instance
18
+ r.matrix.autoconvert(RSRuby::NO_CONVERSION)
19
+ m = r.matrix([1,2,3,4], :ncol => 2, :nrow => 2)
20
+ assert r.is_matrix(m)
21
+
22
+ end
23
+ end
data/test/tc_to_r.rb CHANGED
@@ -17,6 +17,7 @@ class TestToR < Test::Unit::TestCase
17
17
 
18
18
  def setup
19
19
  @r = RSRuby.instance
20
+ #@r.gctorture(:on => true)
20
21
  RSRuby.set_default_mode(RSRuby::NO_DEFAULT)
21
22
  end
22
23
 
@@ -88,6 +89,7 @@ class TestToR < Test::Unit::TestCase
88
89
  def test_hash_to_named_vector
89
90
  @r.c.autoconvert(RSRuby::NO_CONVERSION)
90
91
  assert_equal(@r.typeof(@r.c(:foo => 5, :bar => 7)),'integer')
92
+
91
93
  assert(@r.attributes(@r.c(:foo => 5, :bar => 7))['names'].include?('foo'))
92
94
  assert(@r.attributes(@r.c(:foo => 5, :bar => 7))['names'].include?('bar'))
93
95
  #TODO - these fail because of the different calling semantics in
@@ -113,7 +115,7 @@ class TestToR < Test::Unit::TestCase
113
115
  def test_instances_not_convertible
114
116
  foo = Foo.new
115
117
  assert_raises(ArgumentError){@r.c(foo)}
116
- end
118
+ end
117
119
 
118
120
  def test_as_r_method
119
121
  @r.c.autoconvert(RSRuby::BASIC_CONVERSION)
data/test/tc_to_ruby.rb CHANGED
@@ -2,7 +2,8 @@ require 'test/unit'
2
2
  require 'rsruby'
3
3
 
4
4
  class TestToRuby < Test::Unit::TestCase
5
-
5
+ @@test_dir = File.expand_path File.dirname(__FILE__)
6
+
6
7
  def setup
7
8
  @r = RSRuby.instance
8
9
  RSRuby.set_default_mode(RSRuby::NO_DEFAULT)
@@ -70,7 +71,7 @@ class TestToRuby < Test::Unit::TestCase
70
71
  #TODO - table.txt?????????
71
72
  def test_dataframe_to_list
72
73
  @r.read_table.autoconvert(RSRuby::BASIC_CONVERSION)
73
- assert_equal(@r.read_table("test/table.txt", {:header => 1}),
74
+ assert_equal(@r.read_table(@@test_dir+"/table.txt", {:header => 1}),
74
75
  {
75
76
  'A' => ['X1','X2','X3'],
76
77
  'C' => [5,8,2],
data/test/test_all.rb CHANGED
@@ -10,6 +10,7 @@ require 'tc_extensions'
10
10
  require 'tc_init'
11
11
  #require 'tc_io'
12
12
  require 'tc_library'
13
+ require 'tc_matrix'
13
14
  require 'tc_modes'
14
15
  require 'tc_robj'
15
16
  #require 'tc_sigint'
metadata CHANGED
@@ -1,39 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.2
3
- specification_version: 1
4
2
  name: rsruby
5
3
  version: !ruby/object:Gem::Version
6
- version: 0.4.5
7
- date: 2007-08-10 00:00:00 +09:00
8
- summary: RSRuby is a bridge library for Ruby giving Ruby developers access to the full R statistical programming environment. RSRuby embeds a full R interpreter inside the running Ruby script, allowing R methods to be called and data passed between the Ruby script and the R interpreter. Most data conversion is handled automatically, but user-definable conversion routines can also be written to handle any R or Ruby class.
9
- require_paths:
10
- - lib
11
- - test
12
- email: alexg@kuicr.kyoto-u.ac.jp
13
- homepage: http://web.kuicr.kyoto-u.ac.jp/~alexg/rsruby/
14
- rubyforge_project: rsruby
15
- description: RSRuby is a bridge library for Ruby giving Ruby developers access to the full R statistical programming environment. RSRuby embeds a full R interpreter inside the running Ruby script, allowing R methods to be called and data passed between the Ruby script and the R interpreter. Most data conversion is handled automatically, but user-definable conversion routines can also be written to handle any R or Ruby class.
16
- autorequire:
17
- default_executable:
18
- bindir: bin
19
- has_rdoc: true
20
- required_ruby_version: !ruby/object:Gem::Version::Requirement
21
- requirements:
22
- - - ">"
23
- - !ruby/object:Gem::Version
24
- version: 0.0.0
25
- version:
4
+ version: "0.5"
26
5
  platform: ruby
27
- signing_key:
28
- cert_chain:
29
- post_install_message:
30
6
  authors:
31
7
  - Alex Gutteridge
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-04-18 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: RSRuby is a bridge library for Ruby giving Ruby developers access to the full R statistical programming environment. RSRuby embeds a full R interpreter inside the running Ruby script, allowing R methods to be called and data passed between the Ruby script and the R interpreter. Most data conversion is handled automatically, but user-definable conversion routines can also be written to handle any R or Ruby class.
17
+ email: ag357@cam.ac.uk
18
+ executables: []
19
+
20
+ extensions:
21
+ - ext/extconf.rb
22
+ extra_rdoc_files:
23
+ - README.txt
24
+ - History.txt
25
+ - License.txt
26
+ - examples/arrayfields.rb
27
+ - examples/bioc.rb
28
+ - examples/dataframe.rb
29
+ - examples/erobj.rb
32
30
  files:
33
31
  - History.txt
34
32
  - License.txt
35
33
  - Manifest.txt
36
34
  - README.txt
35
+ - Rakefile.rb
37
36
  - examples/arrayfields.rb
38
37
  - examples/bioc.rb
39
38
  - examples/dataframe.rb
@@ -59,6 +58,7 @@ files:
59
58
  - test/tc_init.rb
60
59
  - test/tc_io.rb
61
60
  - test/tc_library.rb
61
+ - test/tc_matrix.rb
62
62
  - test/tc_modes.rb
63
63
  - test/tc_robj.rb
64
64
  - test/tc_sigint.rb
@@ -67,27 +67,37 @@ files:
67
67
  - test/tc_util.rb
68
68
  - test/tc_vars.rb
69
69
  - test/test_all.rb
70
- test_files:
71
- - test/test_all.rb
70
+ has_rdoc: true
71
+ homepage: http://web.kuicr.kyoto-u.ac.jp/~alexg/rsruby/
72
+ post_install_message:
72
73
  rdoc_options:
73
74
  - --exclude
74
75
  - test/*
75
76
  - --main
76
77
  - README.txt
77
78
  - --inline-source
78
- extra_rdoc_files:
79
- - README.txt
80
- - History.txt
81
- - License.txt
82
- - examples/arrayfields.rb
83
- - examples/bioc.rb
84
- - examples/dataframe.rb
85
- - examples/erobj.rb
86
- executables: []
87
-
88
- extensions:
89
- - ext/extconf.rb
79
+ require_paths:
80
+ - lib
81
+ - test
82
+ - ext
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
90
95
  requirements: []
91
96
 
92
- dependencies: []
93
-
97
+ rubyforge_project: rsruby
98
+ rubygems_version: 1.1.0
99
+ signing_key:
100
+ specification_version: 2
101
+ summary: RSRuby is a bridge library for Ruby giving Ruby developers access to the full R statistical programming environment. RSRuby embeds a full R interpreter inside the running Ruby script, allowing R methods to be called and data passed between the Ruby script and the R interpreter. Most data conversion is handled automatically, but user-definable conversion routines can also be written to handle any R or Ruby class.
102
+ test_files:
103
+ - test/test_all.rb