rsruby 0.4.0 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -253,6 +253,8 @@ VALUE to_ruby_with_mode(SEXP robj, int mode)
253
253
  VALUE obj;
254
254
  int i;
255
255
 
256
+ int old_mode = mode;
257
+
256
258
  switch (mode)
257
259
  {
258
260
  case PROC_CONVERSION:
@@ -275,6 +277,7 @@ VALUE to_ruby_with_mode(SEXP robj, int mode)
275
277
  obj = Data_Wrap_Struct(rb_const_get(rb_cObject,
276
278
  rb_intern("RObj")), 0, 0, robj);
277
279
  rb_iv_set(obj,"@conversion",INT2FIX(TOP_MODE));
280
+ rb_iv_set(obj,"@wrap",Qfalse);
278
281
  }
279
282
 
280
283
  return obj;
@@ -424,7 +427,8 @@ int
424
427
  from_proc_table(SEXP robj, VALUE *fun)
425
428
  {
426
429
  VALUE proc_table, procs, proc, funs, res, obj, mode;
427
- int i, l, error;
430
+ VALUE args[2];
431
+ int i, l, error, exception;
428
432
 
429
433
  proc_table = rb_cvar_get(rb_const_get(rb_cObject,
430
434
  rb_intern("RSRuby")),
@@ -444,13 +448,12 @@ from_proc_table(SEXP robj, VALUE *fun)
444
448
  obj = Data_Wrap_Struct(rb_const_get(rb_cObject,
445
449
  rb_intern("RObj")), 0, 0, robj);
446
450
  rb_iv_set(obj,"@conversion",INT2FIX(TOP_MODE));
451
+ rb_iv_set(obj,"@wrap",Qfalse);
447
452
 
448
453
  error = 0;
449
454
  for (i=0; i<l; i++) {
450
455
  proc = rb_ary_entry(procs, i);
451
456
 
452
- //TODO - something strange here in RPy isn't there infinite
453
- //recursion?? We set to basic mode in function to avoid.
454
457
  mode = rb_cvar_get(rb_const_get(rb_cObject,
455
458
  rb_intern("RSRuby")),
456
459
  rb_intern("@@default_mode"));
@@ -459,19 +462,11 @@ from_proc_table(SEXP robj, VALUE *fun)
459
462
  rb_intern("@@default_mode"),
460
463
  INT2FIX(BASIC_CONVERSION),Qtrue);
461
464
 
462
- //Call function
463
- res = rb_funcall(proc, rb_intern("call"), 1, obj);
464
-
465
- //Reset mode
466
- rb_cvar_set(rb_const_get(rb_cObject,
467
- rb_intern("RSRuby")),
468
- rb_intern("@@default_mode"),
469
- mode,Qtrue);
465
+ //New safe code
466
+ args[0] = proc;
467
+ args[1] = obj;
468
+ res = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
470
469
 
471
- if (!res) {
472
- error = -1;
473
- break;
474
- }
475
470
  if (RTEST(res)) {
476
471
  *fun = rb_ary_entry(funs, i);
477
472
  break;
@@ -481,10 +476,27 @@ from_proc_table(SEXP robj, VALUE *fun)
481
476
  return error;
482
477
  }
483
478
 
479
+ VALUE call_proc(VALUE data){
480
+ VALUE *args = (VALUE *) data;
481
+ return rb_funcall(args[0], rb_intern("call"), 1, args[1]);
482
+ }
483
+
484
+ VALUE reset_mode(VALUE mode){
485
+
486
+ rb_cvar_set(rb_const_get(rb_cObject,
487
+ rb_intern("RSRuby")),
488
+ rb_intern("@@default_mode"),
489
+ mode,Qtrue);
490
+
491
+ return Qnil;
492
+
493
+ }
494
+
484
495
  int
485
496
  to_ruby_proc(SEXP robj, VALUE *obj)
486
497
  {
487
498
  VALUE fun=Qnil, tmp, mode;
499
+ VALUE args[2];
488
500
  int i;
489
501
 
490
502
  //Find function from proc table. integer is returned
@@ -503,6 +515,7 @@ to_ruby_proc(SEXP robj, VALUE *obj)
503
515
  tmp = Data_Wrap_Struct(rb_const_get(rb_cObject,
504
516
  rb_intern("RObj")), 0, 0, robj);
505
517
  rb_iv_set(tmp,"@conversion",INT2FIX(TOP_MODE));
518
+ rb_iv_set(tmp,"@wrap",Qfalse);
506
519
 
507
520
  //Again set conversion mode to basic to prevent recursion
508
521
  mode = rb_cvar_get(rb_const_get(rb_cObject,
@@ -513,14 +526,11 @@ to_ruby_proc(SEXP robj, VALUE *obj)
513
526
  rb_intern("@@default_mode"),
514
527
  INT2FIX(BASIC_CONVERSION),Qtrue);
515
528
 
516
- *obj = rb_funcall(fun, rb_intern("call"), 1, tmp);
517
-
518
- //And reset mode
519
- rb_cvar_set(rb_const_get(rb_cObject,
520
- rb_intern("RSRuby")),
521
- rb_intern("@@default_mode"),
522
- mode,Qtrue);
523
-
529
+ //New safe code
530
+ args[0] = fun;
531
+ args[1] = tmp;
532
+ *obj = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
533
+
524
534
  return 1; /* conversion succeed */
525
535
  }
526
536
 
@@ -567,7 +577,8 @@ VALUE from_class_table(SEXP robj)
567
577
  int
568
578
  to_ruby_class(SEXP robj, VALUE *obj)
569
579
  {
570
- VALUE fun, tmp;
580
+ VALUE fun, tmp, mode;
581
+ VALUE args[2];
571
582
 
572
583
  fun = from_class_table(robj);
573
584
 
@@ -577,8 +588,22 @@ to_ruby_class(SEXP robj, VALUE *obj)
577
588
  tmp = Data_Wrap_Struct(rb_const_get(rb_cObject,
578
589
  rb_intern("RObj")), 0, 0, robj);
579
590
  rb_iv_set(tmp,"@conversion",INT2FIX(TOP_MODE));
591
+ rb_iv_set(tmp,"@wrap",Qfalse);
592
+
593
+ //Again set conversion mode to basic to prevent recursion
594
+ mode = rb_cvar_get(rb_const_get(rb_cObject,
595
+ rb_intern("RSRuby")),
596
+ rb_intern("@@default_mode"));
597
+ rb_cvar_set(rb_const_get(rb_cObject,
598
+ rb_intern("RSRuby")),
599
+ rb_intern("@@default_mode"),
600
+ INT2FIX(BASIC_CONVERSION),Qtrue);
580
601
 
581
- *obj = rb_funcall(fun, rb_intern("call"), 1, tmp);
602
+ //New safe code
603
+ args[0] = fun;
604
+ args[1] = tmp;
605
+ *obj = rb_ensure(call_proc,(VALUE) &args[0],reset_mode,mode);
606
+ //*obj = rb_funcall(fun, rb_intern("call"), 1, tmp);
582
607
 
583
608
  return 1; /* conversion succeed */
584
609
  }
@@ -51,6 +51,9 @@ int to_ruby_class(SEXP robj, VALUE *obj);
51
51
  int from_proc_table(SEXP robj, VALUE *fun);
52
52
  VALUE from_class_table(SEXP robj);
53
53
 
54
+ VALUE call_proc(VALUE data);
55
+ VALUE reset_mode(VALUE mode);
56
+
54
57
  static VALUE to_ruby_hash(VALUE obj, SEXP names);
55
58
  static VALUE to_ruby_array(VALUE obj, int *dims, int l);
56
59
 
File without changes
File without changes
@@ -1,5 +1,4 @@
1
1
  require 'mkmf'
2
- require 'rbconfig'
3
2
 
4
3
  dir_config('R')
5
4
  unless have_library("R")
@@ -12,9 +11,3 @@ unless have_header("R.h")
12
11
  end
13
12
 
14
13
  create_makefile("rsruby")
15
- #create_makefile("robj")
16
-
17
- File.open("Makevars","w") do |file|
18
- file.puts "PKG_CPPFLAGS = -I#{Config::CONFIG["archdir"]} -D_R_=1 -DUSE_R=1 -DUSE_TOPLEVEL_EXEC=1"
19
- file.puts "PKG_LIBS = #{Config::CONFIG["LIBRUBYARG_SHARED"]}"
20
- end
File without changes
@@ -31,15 +31,6 @@
31
31
 
32
32
  #include "rsruby.h"
33
33
 
34
- //TODO - Cleanup and shutdown functions need implementing
35
- //static PyObject *
36
- //r_cleanup(void)
37
- //{
38
- // r_cleanup();
39
- // Py_INCREF(Py_None);
40
- // return Py_None;
41
- //}
42
-
43
34
  /* Global list to protect R objects from garbage collection */
44
35
  /* This is inspired in $R_SRC/src/main/memory.c */
45
36
  static SEXP R_References;
@@ -71,21 +62,6 @@ Robj_dealloc(VALUE self)
71
62
  return;
72
63
  }
73
64
 
74
- /*
75
- * Initialises the R interpreter.
76
- */
77
- void init_R(int argc, char **argv){
78
-
79
- int defaultArgc = 2;
80
- char *defaultArgv[] = {"Rtest","--silent"};
81
-
82
- if(argc == 0 || argv == NULL) {
83
- argc = defaultArgc;
84
- argv = defaultArgv;
85
- }
86
- Rf_initEmbeddedR(argc, argv);
87
- }
88
-
89
65
 
90
66
  /* Obtain an R object via its name.
91
67
  * This is only used to get the 'get' function.
@@ -112,6 +88,7 @@ VALUE get_fun(VALUE self, VALUE name){
112
88
  rubyobj = Data_Wrap_Struct(rb_const_get(rb_cObject,
113
89
  rb_intern("RObj")), 0, 0, robj);
114
90
  rb_iv_set(rubyobj,"@conversion",INT2FIX(conversion));
91
+ rb_iv_set(rubyobj,"@wrap",Qfalse);
115
92
 
116
93
  return rubyobj;
117
94
 
@@ -140,8 +117,6 @@ void r_finalize(void)
140
117
  VALUE cShutdown(VALUE self){
141
118
 
142
119
  r_finalize();
143
-
144
- self = Qnil;
145
120
  return Qtrue;
146
121
 
147
122
  }
@@ -162,6 +137,17 @@ VALUE rr_init(VALUE self){
162
137
 
163
138
  }
164
139
 
140
+ /*
141
+ * Initialises the R interpreter.
142
+ */
143
+ void init_R(int argc, char **argv){
144
+
145
+ int defaultArgc = 2;
146
+ char *defaultArgv[] = {"rsruby","-q","--vanilla"};
147
+
148
+ Rf_initEmbeddedR(defaultArgc, defaultArgv);
149
+ }
150
+
165
151
  /* Ruby code */
166
152
 
167
153
  VALUE cRRuby;
File without changes
data/lib/rsruby.rb CHANGED
@@ -1,116 +1,29 @@
1
+ require 'rsruby/robj'
2
+ require 'rsruby.so'
3
+ require 'singleton'
4
+
5
+ require 'complex'
6
+
1
7
  #== Synopsis
2
8
  #
3
- #This class provides the ability to embed a full R
4
- #interpreter inside a running Ruby script. R methods can
5
- #then be called from the Ruby script and data passed between the
6
- #R interpreter and the Ruby script. The code is based on a conversion
7
- #of the RSPerl[http://www.omegahat.org/RSPerl/] and RPy[http://rpy.sourceforge.net/]
8
- #modules which provide similar (and more) functionality for Perl and Python
9
- #respectively.
10
- #
11
- #The main RSRuby class has Singleton module mixed in. This ensures that only
12
- #one R interpreter is running in a script at any one time and that the
13
- #interpreter can always be found. The embedded R interpreter is started by
14
- #calling RSRuby.instance (See the RSRuby class for details). The returned
15
- #RSRuby object represents the R interpreter and R functions are called by
16
- #calling methods on this object.
17
- #
18
- #== Usage
19
- #
20
- # require 'rsruby'
21
- #
22
- # r = RSRuby.instance
23
- # puts r.sum(1,2,3)
24
- #
25
- #Converting between R and Ruby data types is handled in a similar way to
26
- #RPy and is explained in more detail in the manual (see Converters.c for the
27
- #gory details).
28
- #
29
- #The default conversion system mapping between R types and Ruby classes is
30
- #summarised here:
31
- #
32
- # - R Logicals (true/false) <=> Ruby true/false
33
- # - R Integers <=> Ruby Fixnum/Bignum
34
- # - R Real <=> Ruby Float
35
- # - R Complex <=> Ruby Complex
36
- # - R String <=> Ruby String
37
- # - R Vector <=> Ruby Array or Hash
38
- # - R List <=> Ruby Array or Hash
39
- # - R Array <=> Ruby Array or Hash
40
- # - R 'other' <=> Ruby RObj
41
- #
42
- #While this generally works fine for simple data structures, more complicated
43
- #structures can loose information when converted to Ruby. Clever use of the
44
- #more complicated custom conversion modes can usually avoid this.
45
- #
46
- #As shown above, calling R methods can be done by calling the same method
47
- #on the RSRuby object. Some R methods contain '.' and other characters
48
- #forbidden in Ruby method names. To call these methods substitute '_' for '.':
49
- #
50
- #Sample usage (to call R method 'as.list'):
51
- #
52
- # require 'rsruby'
53
- #
54
- # r = RSRuby.instance
55
- # puts r.as_list([1,2,3])
56
- #
57
- #If a Hash is the last argument to an RSRuby method call then the hash is
58
- #interpreted as a list of named arguments to the corresponding R function.
59
- #Argument names can be given as Strings or Symbols. Argument order is not
60
- #maintained in this case (because order is not maintained in Hashes). If
61
- #named arguments and order are required then there is the lcall syntax where
62
- #arguments are given as an array of two member arrays (where each two member
63
- #array represents a name/argument pair). lcall is a method defined in the
64
- #RObj class which represents functions and other non-convertible R objects.
65
- #
66
- #Calling an R method with no arguments returns the method object itself - it
67
- #does not call the method. This may be changed in the future as it is somewhat
68
- #confusing. However, the returned object can then be called or 'lcall'ed as
69
- #required. It is also possible to return R variables in this way:
70
- #
71
- #E.g.
72
- #
73
- # require 'rsruby'
74
- #
75
- # r = RSRuby.instance
76
- # norm = r.rnorm
77
- # norm_dist = norm.call(100)
78
- #
79
- # r.plot(norm_dist,
80
- # {:ylab => "TestY"})
81
- # sleep(2)
82
- #
9
+ #This class represents the embedded R interpreter. The Singleton module is
10
+ #mixed in to ensure that only one R interpreter is running in a script at
11
+ #any one time and that the interpreter can always be easily accessed without
12
+ #using a global variable.
83
13
  #
84
- #The final way to execute R code is to just evaluate a complete R expression
85
- #The eval_R method provides this functionality. Pass a String to the method to
86
- #see it evaluated by R:
14
+ #The R interpreter is started by calling RSRuby.instance. The returned
15
+ #object represents the R interpreter and R functions are called by
16
+ #calling methods on this object:
87
17
  #
88
- # require 'rsruby'
89
- #
90
- # r = RSRuby.instance
91
- # r.eval_R("a=43")
92
- # puts r.a
93
- #
94
- #As an alternative to the method syntax, R objects and functions can be
95
- #returned using []. This is required for weird R methods such as '$' or '[[':
96
- #
97
- # require 'rsruby'
98
- #
99
- # r = RSRuby.instance
100
- # r.eval_R("a=43")
101
- # puts r['a']
102
- #
103
- #R libraries can be loaded using the library method. Just provide the library
104
- #name as a String:
105
- #
106
- # require 'rsruby'
107
- #
108
- # r = RSRuby.instance
109
- # r.library("library_name")
110
- #
111
- #== Author
112
- #Alex Gutteridge
18
+ # r = RSRuby.instance
19
+ # r.sum(1,2,3)
20
+ # puts r.t_test(1,2,3)['p-value']
113
21
  #
22
+ #See the manual[http://web.kuicr.kyoto-u.ac.jp/~alexg/rsruby/manual.pdf] for
23
+ #more details on calling functions and the conversion system for passing data
24
+ #between Ruby and R. If no suitable conversion from R to Ruby is found, an RObj
25
+ #is returned (all R functions are returned as instances of RObj).
26
+ #--
114
27
  #== Copyright
115
28
  #Copyright (C) 2006 Alex Gutteridge
116
29
  #
@@ -136,18 +49,12 @@
136
49
  #You should have received a copy of the GNU Lesser General Public
137
50
  #License along with this library; if not, write to the Free Software
138
51
  #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
139
-
140
- require 'rsruby/robj'
141
- require 'rsruby.so'
142
- require 'singleton'
143
-
144
- require 'complex'
145
-
146
- class RException < RuntimeError
147
- end
52
+ #++
148
53
 
149
54
  class RSRuby
150
55
 
56
+ VERSION = '0.4.2'
57
+
151
58
  include Singleton
152
59
 
153
60
  #Constants for conversion modes
@@ -223,7 +130,7 @@ class RSRuby
223
130
 
224
131
  end
225
132
 
226
- #As method_missing, but only returns the R function/object
133
+ #The same as method_missing, but only returns the R function/object,
227
134
  #does not call it.
228
135
  def [](r_id)
229
136
 
@@ -245,7 +152,8 @@ class RSRuby
245
152
  return func
246
153
  end
247
154
 
248
- #Converts method names from Ruby compatible style into R style.
155
+ #Converts a String representing a 'Ruby-style' R function name into a
156
+ #String with the real R name according to the rules given in the manual.
249
157
  def RSRuby.convert_method_name(name)
250
158
  if name.length > 1 and name[-1].chr == '_' and name[-2].chr != '_'
251
159
  name = name[0..-2]
@@ -255,10 +163,16 @@ class RSRuby
255
163
  return name
256
164
  end
257
165
 
258
- #Converts an array of arguments into lcall format. If the last element
259
- #of the array is a Hash then the contents are interpreted as named
260
- #arguments. lcall format is an Array of two member Arrays. Each two
261
- #member array corresponds to a name/argument pair.
166
+ #Converts an Array of function arguments into lcall format. If the last
167
+ #element of the array is a Hash then the contents of the Hash are
168
+ #interpreted as named arguments.
169
+ #
170
+ #The returned value is an Array of tuples (Arrays of length two). Each
171
+ #tupple corresponds to a name/argument pair.
172
+ #
173
+ #For example:
174
+ # convert_args_to_lcall([1,2,3,{:a=>4,:b=>5})
175
+ # => [['',1],['',2],['',3],['a',4],['b',5]]
262
176
  def RSRuby.convert_args_to_lcall(args)
263
177
 
264
178
  lcall_args = []
@@ -290,24 +204,32 @@ class RSRuby
290
204
  @@default_mode
291
205
  end
292
206
 
293
- #TODO - input/output setting methods don't work atm
207
+ #TODO - not implemented
294
208
  def RSRuby.set_rsruby_input(m)
295
209
  @@rsruby_input = m
296
210
  end
211
+
212
+ #TODO - not implemented
297
213
  def RSRuby.get_rsruby_input
298
214
  @@rsruby_input
299
215
  end
300
216
 
217
+ #TODO - not implemented
301
218
  def RSRuby.set_rsruby_output(m)
302
219
  @@rsruby_output = m
303
220
  end
221
+
222
+ #TODO - not implemented
304
223
  def RSRuby.get_rsruby_output
305
224
  @@rsruby_output
306
225
  end
307
226
 
227
+ #TODO - not implemented
308
228
  def RSRuby.set_rsruby_showfiles(m)
309
229
  @@rsruby_showfiles = m
310
230
  end
231
+
232
+ #TODO - not implemented
311
233
  def RSRuby.get_rsruby_showfiles
312
234
  @@rsruby_showfiles
313
235
  end
@@ -343,7 +265,6 @@ class RSRuby
343
265
  self.print(helpobj)
344
266
  end
345
267
 
346
- :private
347
268
  def __getitem__(name)
348
269
 
349
270
  #Find the identifier and cache (unless already cached)
@@ -359,3 +280,6 @@ class RSRuby
359
280
  end
360
281
 
361
282
  end
283
+
284
+ class RException < RuntimeError
285
+ end