alexgutteridge-rsruby 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/License.txt +504 -0
- data/Manifest.txt +39 -0
- data/README.txt +96 -0
- data/Rakefile.rb +153 -0
- data/examples/arrayfields.rb +52 -0
- data/examples/bioc.rb +35 -0
- data/examples/dataframe.rb +35 -0
- data/examples/erobj.rb +30 -0
- data/ext/Converters.c +667 -0
- data/ext/Converters.h +77 -0
- data/ext/R_eval.c +144 -0
- data/ext/R_eval.h +40 -0
- data/ext/extconf.rb +13 -0
- data/ext/robj.c +205 -0
- data/ext/rsruby.c +182 -0
- data/ext/rsruby.h +87 -0
- data/lib/rsruby.rb +302 -0
- data/lib/rsruby/dataframe.rb +107 -0
- data/lib/rsruby/erobj.rb +105 -0
- data/lib/rsruby/robj.rb +67 -0
- data/test/table.txt +4 -0
- data/test/tc_array.rb +59 -0
- data/test/tc_boolean.rb +30 -0
- data/test/tc_cleanup.rb +22 -0
- data/test/tc_eval.rb +21 -0
- data/test/tc_extensions.rb +43 -0
- data/test/tc_init.rb +11 -0
- data/test/tc_io.rb +57 -0
- data/test/tc_library.rb +20 -0
- data/test/tc_matrix.rb +23 -0
- data/test/tc_modes.rb +264 -0
- data/test/tc_robj.rb +84 -0
- data/test/tc_sigint.rb +10 -0
- data/test/tc_to_r.rb +145 -0
- data/test/tc_to_ruby.rb +153 -0
- data/test/tc_util.rb +19 -0
- data/test/tc_vars.rb +28 -0
- data/test/test_all.rb +22 -0
- metadata +103 -0
data/ext/Converters.h
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
/*
|
2
|
+
* == Author
|
3
|
+
* Alex Gutteridge
|
4
|
+
*
|
5
|
+
* == Copyright
|
6
|
+
*Copyright (C) 2006 Alex Gutteridge
|
7
|
+
*
|
8
|
+
* The Original Code is the RPy python module.
|
9
|
+
*
|
10
|
+
* The Initial Developer of the Original Code is Walter Moreira.
|
11
|
+
* Portions created by the Initial Developer are Copyright (C) 2002
|
12
|
+
* the Initial Developer. All Rights Reserved.
|
13
|
+
*
|
14
|
+
* Contributor(s):
|
15
|
+
* Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
16
|
+
*
|
17
|
+
*This library is free software; you can redistribute it and/or
|
18
|
+
*modify it under the terms of the GNU Lesser General Public
|
19
|
+
*License as published by the Free Software Foundation; either
|
20
|
+
*version 2.1 of the License, or (at your option) any later version.
|
21
|
+
*
|
22
|
+
*This library is distributed in the hope that it will be useful,
|
23
|
+
*but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24
|
+
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
25
|
+
*Lesser General Public License for more details.
|
26
|
+
*
|
27
|
+
*You should have received a copy of the GNU Lesser General Public
|
28
|
+
*License along with this library; if not, write to the Free Software
|
29
|
+
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
30
|
+
*/
|
31
|
+
|
32
|
+
#ifndef R_RUBY_CONVERTERS_H
|
33
|
+
#define R_RUBY_CONVERTERS_H
|
34
|
+
|
35
|
+
#include "rsruby.h"
|
36
|
+
|
37
|
+
//Converters for Ruby to R
|
38
|
+
SEXP ruby_to_R(VALUE val);
|
39
|
+
|
40
|
+
SEXP array_to_R(VALUE obj);
|
41
|
+
SEXP hash_to_R(VALUE obj);
|
42
|
+
int type_to_int(VALUE obj);
|
43
|
+
|
44
|
+
//Converters for R to Ruby
|
45
|
+
VALUE to_ruby_with_mode(SEXP robj, int mode);
|
46
|
+
|
47
|
+
int to_ruby_basic(SEXP robj, VALUE *obj);
|
48
|
+
int to_ruby_vector(SEXP robj, VALUE *obj, int mode);
|
49
|
+
int to_ruby_proc(SEXP robj, VALUE *obj);
|
50
|
+
int to_ruby_class(SEXP robj, VALUE *obj);
|
51
|
+
int from_proc_table(SEXP robj, VALUE *fun);
|
52
|
+
VALUE from_class_table(SEXP robj);
|
53
|
+
|
54
|
+
VALUE call_proc(VALUE data);
|
55
|
+
VALUE reset_mode(VALUE mode);
|
56
|
+
|
57
|
+
VALUE to_ruby_hash(VALUE obj, SEXP names);
|
58
|
+
VALUE to_ruby_array(VALUE obj, int *dims, int l);
|
59
|
+
|
60
|
+
VALUE ltranspose(VALUE list, int *dims, int *strides,
|
61
|
+
int pos, int shift, int len);
|
62
|
+
|
63
|
+
//Macros for quick checks
|
64
|
+
#define Robj_Check(v) (rb_obj_is_instance_of(v,rb_const_get(rb_cObject,rb_intern("RObj"))))
|
65
|
+
#define RubyComplex_Check(v) (rb_obj_is_instance_of(v,rb_const_get(rb_cObject,rb_intern("Complex"))))
|
66
|
+
|
67
|
+
/* These are auxiliaries for a state machine for converting Python
|
68
|
+
list to the coarsest R vector type */
|
69
|
+
#define ANY_T 0
|
70
|
+
#define BOOL_T 1
|
71
|
+
#define INT_T 2
|
72
|
+
#define FLOAT_T 3
|
73
|
+
#define COMPLEX_T 4
|
74
|
+
#define STRING_T 5
|
75
|
+
#define ROBJ_T 6
|
76
|
+
|
77
|
+
#endif
|
data/ext/R_eval.c
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
/*
|
2
|
+
* == Author
|
3
|
+
* Alex Gutteridge
|
4
|
+
*
|
5
|
+
* == Copyright
|
6
|
+
*Copyright (C) 2006 Alex Gutteridge
|
7
|
+
*
|
8
|
+
* The Original Code is the RPy python module.
|
9
|
+
*
|
10
|
+
* The Initial Developer of the Original Code is Walter Moreira.
|
11
|
+
* Portions created by the Initial Developer are Copyright (C) 2002
|
12
|
+
* the Initial Developer. All Rights Reserved.
|
13
|
+
*
|
14
|
+
* Contributor(s):
|
15
|
+
* Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
16
|
+
*
|
17
|
+
*This library is free software; you can redistribute it and/or
|
18
|
+
*modify it under the terms of the GNU Lesser General Public
|
19
|
+
*License as published by the Free Software Foundation; either
|
20
|
+
*version 2.1 of the License, or (at your option) any later version.
|
21
|
+
*
|
22
|
+
*This library is distributed in the hope that it will be useful,
|
23
|
+
*but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24
|
+
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
25
|
+
*Lesser General Public License for more details.
|
26
|
+
*
|
27
|
+
*You should have received a copy of the GNU Lesser General Public
|
28
|
+
*License along with this library; if not, write to the Free Software
|
29
|
+
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
30
|
+
*/
|
31
|
+
|
32
|
+
#include <rsruby.h>
|
33
|
+
#include <R_eval.h>
|
34
|
+
|
35
|
+
int interrupted = 0;
|
36
|
+
|
37
|
+
/* Abort the current R computation due to a SIGINT */
|
38
|
+
void interrupt_R(int signum)
|
39
|
+
{
|
40
|
+
interrupted = 1;
|
41
|
+
error("Interrupted");
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
/* Evaluate a SEXP. It must be constructed by hand. It raises a Ruby
|
46
|
+
exception if an error ocurred in the evaluation */
|
47
|
+
SEXP do_eval_expr(SEXP e) {
|
48
|
+
SEXP res;
|
49
|
+
VALUE rb_eRException;
|
50
|
+
int error = 0;
|
51
|
+
|
52
|
+
signal(SIGINT, interrupt_R);
|
53
|
+
interrupted = 0;
|
54
|
+
|
55
|
+
res = R_tryEval(e, R_GlobalEnv, &error);
|
56
|
+
|
57
|
+
if (error) {
|
58
|
+
if (interrupted) {
|
59
|
+
rb_raise(rb_eInterrupt,"RSRuby interrupted");
|
60
|
+
}
|
61
|
+
else {
|
62
|
+
rb_eRException = rb_const_get(rb_cObject,
|
63
|
+
rb_intern("RException"));
|
64
|
+
rb_raise(rb_eRException, get_last_error_msg());
|
65
|
+
return NULL;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
return res;
|
70
|
+
|
71
|
+
}
|
72
|
+
|
73
|
+
/* Evaluate a function given by a name (without arguments) */
|
74
|
+
SEXP do_eval_fun(char *name) {
|
75
|
+
SEXP exp, fun, res;
|
76
|
+
|
77
|
+
fun = get_fun_from_name(name);
|
78
|
+
if (!fun)
|
79
|
+
return NULL;
|
80
|
+
|
81
|
+
PROTECT(fun);
|
82
|
+
PROTECT(exp = allocVector(LANGSXP, 1));
|
83
|
+
SETCAR(exp, fun);
|
84
|
+
|
85
|
+
PROTECT(res = do_eval_expr(exp));
|
86
|
+
UNPROTECT(3);
|
87
|
+
return res;
|
88
|
+
}
|
89
|
+
|
90
|
+
/*
|
91
|
+
* Get an R **function** object by its name. When not found, an exception is
|
92
|
+
* raised. The checking of the length of the identifier is needed to
|
93
|
+
* avoid R raising an error.
|
94
|
+
*/
|
95
|
+
SEXP get_fun_from_name(char *ident) {
|
96
|
+
SEXP obj;
|
97
|
+
|
98
|
+
/* For R not to throw an error, we must check the identifier is
|
99
|
+
neither null nor greater than MAXIDSIZE */
|
100
|
+
if (!*ident) {
|
101
|
+
rb_raise(rb_eRuntimeError, "Attempt to use zero-length variable name");
|
102
|
+
return NULL;
|
103
|
+
}
|
104
|
+
if (strlen(ident) > MAXIDSIZE) {
|
105
|
+
rb_raise(rb_eRuntimeError, "symbol print-name too long");
|
106
|
+
return NULL;
|
107
|
+
}
|
108
|
+
|
109
|
+
#if R_VERSION < 0x20000
|
110
|
+
obj = Rf_findVar(Rf_install(ident), R_GlobalEnv);
|
111
|
+
#else
|
112
|
+
/*
|
113
|
+
* For R-2.0.0 and later, it is necessary to use findFun to get
|
114
|
+
* functions. Unfortunately, calling findFun on an undefined name
|
115
|
+
* causes a segfault!
|
116
|
+
*
|
117
|
+
* Solution:
|
118
|
+
*
|
119
|
+
* 1) Call findVar on the name
|
120
|
+
*
|
121
|
+
* 2) If something has the name, call findFun
|
122
|
+
*
|
123
|
+
* 3) Raise an error if either step 1 or 2 fails.
|
124
|
+
*/
|
125
|
+
obj = Rf_findVar(Rf_install(ident), R_GlobalEnv);
|
126
|
+
|
127
|
+
if (obj != R_UnboundValue)
|
128
|
+
obj = Rf_findFun(Rf_install(ident), R_GlobalEnv);
|
129
|
+
#endif
|
130
|
+
|
131
|
+
if (obj == R_UnboundValue) {
|
132
|
+
rb_raise(rb_eNoMethodError, "R Function \"%s\" not found", ident);
|
133
|
+
return NULL;
|
134
|
+
}
|
135
|
+
return obj;
|
136
|
+
}
|
137
|
+
|
138
|
+
/* Obtain the text of the last R error message */
|
139
|
+
char *get_last_error_msg() {
|
140
|
+
SEXP msg;
|
141
|
+
|
142
|
+
msg = do_eval_fun("geterrmessage");
|
143
|
+
return CHARACTER_VALUE(msg);
|
144
|
+
}
|
data/ext/R_eval.h
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
/*
|
2
|
+
* == Author
|
3
|
+
* Alex Gutteridge
|
4
|
+
*
|
5
|
+
* == Copyright
|
6
|
+
*Copyright (C) 2006 Alex Gutteridge
|
7
|
+
*
|
8
|
+
* The Original Code is the RPy python module.
|
9
|
+
*
|
10
|
+
* The Initial Developer of the Original Code is Walter Moreira.
|
11
|
+
* Portions created by the Initial Developer are Copyright (C) 2002
|
12
|
+
* the Initial Developer. All Rights Reserved.
|
13
|
+
*
|
14
|
+
* Contributor(s):
|
15
|
+
* Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
16
|
+
*
|
17
|
+
*This library is free software; you can redistribute it and/or
|
18
|
+
*modify it under the terms of the GNU Lesser General Public
|
19
|
+
*License as published by the Free Software Foundation; either
|
20
|
+
*version 2.1 of the License, or (at your option) any later version.
|
21
|
+
*
|
22
|
+
*This library is distributed in the hope that it will be useful,
|
23
|
+
*but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24
|
+
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
25
|
+
*Lesser General Public License for more details.
|
26
|
+
*
|
27
|
+
*You should have received a copy of the GNU Lesser General Public
|
28
|
+
*License along with this library; if not, write to the Free Software
|
29
|
+
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
30
|
+
*/
|
31
|
+
|
32
|
+
/* R Evaluation */
|
33
|
+
SEXP do_eval_expr(SEXP e);
|
34
|
+
SEXP do_eval_fun(char *);
|
35
|
+
SEXP get_fun_from_name(char *);
|
36
|
+
|
37
|
+
/* Interrupt the R interpreter */
|
38
|
+
void interrupt_R(int);
|
39
|
+
|
40
|
+
char *get_last_error_msg(void);
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
dir_config('R')
|
4
|
+
unless have_library("R")
|
5
|
+
$stderr.puts "\nERROR: Cannot find the R library, aborting."
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
unless have_header("R.h")
|
9
|
+
$stderr.puts "\nERROR: Cannot find the R header, aborting."
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
create_makefile("rsruby_c")
|
data/ext/robj.c
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
/*
|
2
|
+
* == Author
|
3
|
+
* Alex Gutteridge
|
4
|
+
*
|
5
|
+
* == Copyright
|
6
|
+
*Copyright (C) 2006 Alex Gutteridge
|
7
|
+
*
|
8
|
+
* The Original Code is the RPy python module.
|
9
|
+
*
|
10
|
+
* The Initial Developer of the Original Code is Walter Moreira.
|
11
|
+
* Portions created by the Initial Developer are Copyright (C) 2002
|
12
|
+
* the Initial Developer. All Rights Reserved.
|
13
|
+
*
|
14
|
+
* Contributor(s):
|
15
|
+
* Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
16
|
+
*
|
17
|
+
*This library is free software; you can redistribute it and/or
|
18
|
+
*modify it under the terms of the GNU Lesser General Public
|
19
|
+
*License as published by the Free Software Foundation; either
|
20
|
+
*version 2.1 of the License, or (at your option) any later version.
|
21
|
+
*
|
22
|
+
*This library is distributed in the hope that it will be useful,
|
23
|
+
*but WITHOUT ANY WARRANTY; without even the implied warranty of
|
24
|
+
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
25
|
+
*Lesser General Public License for more details.
|
26
|
+
*
|
27
|
+
*You should have received a copy of the GNU Lesser General Public
|
28
|
+
*License along with this library; if not, write to the Free Software
|
29
|
+
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
30
|
+
*/
|
31
|
+
|
32
|
+
#include "rsruby.h"
|
33
|
+
|
34
|
+
/* Methods for the 'Robj' type */
|
35
|
+
|
36
|
+
/* Explicitly call an R object with a list containing (name, value) *
|
37
|
+
* argument pairs. 'name' can be None or '' to provide unnamed
|
38
|
+
* arguments. This function is necessary when the *order* of named
|
39
|
+
* arguments needs to be preserved.
|
40
|
+
*/
|
41
|
+
|
42
|
+
VALUE RObj_lcall(VALUE self, VALUE args){
|
43
|
+
SEXP exp, e, res;
|
44
|
+
SEXP r_obj;
|
45
|
+
int conv, default_mode;
|
46
|
+
VALUE obj;
|
47
|
+
|
48
|
+
//Ensure we have an array
|
49
|
+
args = rb_check_array_type(args);
|
50
|
+
|
51
|
+
// A SEXP with the function to call and the arguments
|
52
|
+
PROTECT(exp = allocVector(LANGSXP, (RARRAY(args)->len)+1));
|
53
|
+
e = exp;
|
54
|
+
|
55
|
+
Data_Get_Struct(self, struct SEXPREC, r_obj);
|
56
|
+
|
57
|
+
SETCAR(e, r_obj);
|
58
|
+
e = CDR(e);
|
59
|
+
|
60
|
+
// Add the arguments to the SEXP
|
61
|
+
if (!make_argl(args, &e)) {
|
62
|
+
UNPROTECT(1);
|
63
|
+
return Qnil;
|
64
|
+
}
|
65
|
+
|
66
|
+
// Evaluate
|
67
|
+
PROTECT(res = do_eval_expr(exp));
|
68
|
+
if (!res) {
|
69
|
+
UNPROTECT(2);
|
70
|
+
return Qnil;
|
71
|
+
}
|
72
|
+
|
73
|
+
default_mode = NUM2INT(rb_iv_get(RSRUBY,"@default_mode"));
|
74
|
+
|
75
|
+
// Convert
|
76
|
+
if (default_mode < 0){
|
77
|
+
conv = NUM2INT(rb_iv_get(self,"@conversion"));
|
78
|
+
} else {
|
79
|
+
conv = default_mode;
|
80
|
+
}
|
81
|
+
|
82
|
+
obj = to_ruby_with_mode(res, conv);
|
83
|
+
|
84
|
+
UNPROTECT(2);
|
85
|
+
|
86
|
+
return obj;
|
87
|
+
}
|
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
|
+
|
128
|
+
/* Convert a sequence of (name, value) pairs to arguments to an R
|
129
|
+
function call */
|
130
|
+
int
|
131
|
+
make_argl(VALUE args, SEXP *e)
|
132
|
+
{
|
133
|
+
SEXP rvalue;
|
134
|
+
int i;
|
135
|
+
VALUE pair, name, value;
|
136
|
+
|
137
|
+
//Ensure we have an array
|
138
|
+
args = rb_check_array_type(args);
|
139
|
+
|
140
|
+
for (i=0; i<RARRAY(args)->len; i++) {
|
141
|
+
pair = rb_ary_entry(args, i);
|
142
|
+
pair = rb_check_array_type(pair);
|
143
|
+
if(RARRAY(pair)->len != 2)
|
144
|
+
rb_raise(rb_eArgError,"Misformed argument in lcall\n");
|
145
|
+
|
146
|
+
/* Name must be a string. If it is empty string '' then no name*/
|
147
|
+
name = rb_ary_entry(pair, 0);
|
148
|
+
name = StringValue(name);
|
149
|
+
name = rb_funcall(rb_const_get(rb_cObject,
|
150
|
+
rb_intern("RSRuby")),
|
151
|
+
rb_intern("convert_method_name"),1,name);
|
152
|
+
|
153
|
+
/* Value can be anything. */
|
154
|
+
value = rb_ary_entry(pair, 1);
|
155
|
+
rvalue = ruby_to_R(value);
|
156
|
+
|
157
|
+
/* Add parameter value to call */
|
158
|
+
SETCAR(*e, rvalue);
|
159
|
+
|
160
|
+
/* Add name (if present) */
|
161
|
+
if (RSTRING(name)->len > 0)
|
162
|
+
{
|
163
|
+
SET_TAG(*e, Rf_install(RSTRING(name)->ptr));
|
164
|
+
}
|
165
|
+
|
166
|
+
/* Move index to new end of call */
|
167
|
+
*e = CDR(*e);
|
168
|
+
}
|
169
|
+
return 1;
|
170
|
+
}
|
171
|
+
|
172
|
+
VALUE RObj_to_ruby(VALUE self, VALUE args){
|
173
|
+
|
174
|
+
int conv;
|
175
|
+
VALUE obj;
|
176
|
+
SEXP robj;
|
177
|
+
|
178
|
+
args = rb_check_array_type(args);
|
179
|
+
|
180
|
+
if (RARRAY(args)->len > 1){
|
181
|
+
rb_raise(rb_eArgError,"Too many arguments in to_ruby\n");
|
182
|
+
}
|
183
|
+
|
184
|
+
if (RARRAY(args)->len == 0){
|
185
|
+
conv = NUM2INT(rb_iv_get(RSRUBY,"@default_mode"));
|
186
|
+
} else {
|
187
|
+
conv = NUM2INT(rb_ary_entry(args,0));
|
188
|
+
}
|
189
|
+
|
190
|
+
if (conv <= -2 || conv > TOP_MODE) {
|
191
|
+
rb_raise(rb_eArgError, "Wrong mode\n");
|
192
|
+
return Qnil;
|
193
|
+
}
|
194
|
+
|
195
|
+
if (conv < 0)
|
196
|
+
conv = TOP_MODE;
|
197
|
+
|
198
|
+
Data_Get_Struct(self, struct SEXPREC, robj);
|
199
|
+
|
200
|
+
obj = to_ruby_with_mode(robj, conv);
|
201
|
+
return obj;
|
202
|
+
|
203
|
+
}
|
204
|
+
|
205
|
+
|