rsruby 0.4.5 → 0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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