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
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rsruby'
|
2
|
+
require 'rsruby/erobj'
|
3
|
+
|
4
|
+
#== Synopsis
|
5
|
+
#
|
6
|
+
#This is an extended ERObj class inspired by the example given in the RPy
|
7
|
+
#manual used for R data frames.
|
8
|
+
#As with ERObj, methods caught by method_missing are converted into attribute
|
9
|
+
#calls on the R dataframe it represents. The rows and columns methods give
|
10
|
+
#access to the column and row names.
|
11
|
+
#
|
12
|
+
#== Usage
|
13
|
+
#
|
14
|
+
#See examples/dataframe.rb[link:files/examples/dataframe_rb.html] for
|
15
|
+
#examples of usage.
|
16
|
+
#
|
17
|
+
#--
|
18
|
+
#== Author
|
19
|
+
#Alex Gutteridge
|
20
|
+
#
|
21
|
+
#== Copyright
|
22
|
+
#Copyright (C) 2006 Alex Gutteridge
|
23
|
+
#
|
24
|
+
# The Original Code is the RPy python module.
|
25
|
+
#
|
26
|
+
# The Initial Developer of the Original Code is Walter Moreira.
|
27
|
+
# Portions created by the Initial Developer are Copyright (C) 2002
|
28
|
+
# the Initial Developer. All Rights Reserved.
|
29
|
+
#
|
30
|
+
# Contributor(s):
|
31
|
+
# Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
32
|
+
#
|
33
|
+
#This library is free software; you can redistribute it and/or
|
34
|
+
#modify it under the terms of the GNU Lesser General Public
|
35
|
+
#License as published by the Free Software Foundation; either
|
36
|
+
#version 2.1 of the License, or (at your option) any later version.
|
37
|
+
#
|
38
|
+
#This library is distributed in the hope that it will be useful,
|
39
|
+
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
40
|
+
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
41
|
+
#Lesser General Public License for more details.
|
42
|
+
#
|
43
|
+
#You should have received a copy of the GNU Lesser General Public
|
44
|
+
#License along with this library; if not, write to the Free Software
|
45
|
+
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
46
|
+
#++
|
47
|
+
|
48
|
+
class DataFrame < ERObj
|
49
|
+
|
50
|
+
#Returns an array of the row names used in the R data frame.
|
51
|
+
def rows
|
52
|
+
return @r.attr(@robj, 'row.names')
|
53
|
+
end
|
54
|
+
|
55
|
+
#Returns an array of the column names used in the R data frame.
|
56
|
+
def columns
|
57
|
+
cols = @r.colnames(@robj)
|
58
|
+
cols = [cols] unless cols.kind_of?(Array)
|
59
|
+
return cols
|
60
|
+
end
|
61
|
+
|
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]
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(attr)
|
92
|
+
attr = attr.to_s
|
93
|
+
mode = RSRuby.get_default_mode
|
94
|
+
RSRuby.set_default_mode(RSRuby::BASIC_CONVERSION)
|
95
|
+
column_names = @r.colnames(@robj)
|
96
|
+
if attr == column_names or column_names.include?(attr)
|
97
|
+
RSRuby.set_default_mode(mode)
|
98
|
+
return @r['$'].call(@robj,attr.to_s)
|
99
|
+
end
|
100
|
+
|
101
|
+
#? Not sure what here...
|
102
|
+
RSRuby.set_default_mode(mode)
|
103
|
+
return super(attr)
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
data/lib/rsruby/erobj.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'rsruby'
|
2
|
+
|
3
|
+
#== Synopsis
|
4
|
+
#
|
5
|
+
#This is an extended RObj class inspired by the example given in the RPy
|
6
|
+
#manual. Methods caught by method_missing are converted into attribute calls
|
7
|
+
#on the R object it represents. Also to_s is redefined to print exactly the
|
8
|
+
#representation used in R.
|
9
|
+
#
|
10
|
+
#== Usage
|
11
|
+
#
|
12
|
+
#See examples/erobj.rb[link:files/examples/erobj_rb.html] for examples of
|
13
|
+
#usage.
|
14
|
+
#
|
15
|
+
#--
|
16
|
+
# == Author
|
17
|
+
# Alex Gutteridge
|
18
|
+
#
|
19
|
+
# == Copyright
|
20
|
+
#Copyright (C) 2006 Alex Gutteridge
|
21
|
+
#
|
22
|
+
# The Original Code is the RPy python module.
|
23
|
+
#
|
24
|
+
# The Initial Developer of the Original Code is Walter Moreira.
|
25
|
+
# Portions created by the Initial Developer are Copyright (C) 2002
|
26
|
+
# the Initial Developer. All Rights Reserved.
|
27
|
+
#
|
28
|
+
# Contributor(s):
|
29
|
+
# Gregory R. Warnes <greg@warnes.net> (RPy Maintainer)
|
30
|
+
#
|
31
|
+
#This library is free software; you can redistribute it and/or
|
32
|
+
#modify it under the terms of the GNU Lesser General Public
|
33
|
+
#License as published by the Free Software Foundation; either
|
34
|
+
#version 2.1 of the License, or (at your option) any later version.
|
35
|
+
#
|
36
|
+
#This library is distributed in the hope that it will be useful,
|
37
|
+
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
38
|
+
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
39
|
+
#Lesser General Public License for more details.
|
40
|
+
#
|
41
|
+
#You should have received a copy of the GNU Lesser General Public
|
42
|
+
#License along with this library; if not, write to the Free Software
|
43
|
+
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
44
|
+
#++
|
45
|
+
|
46
|
+
class ERObj
|
47
|
+
|
48
|
+
@@x = 1
|
49
|
+
|
50
|
+
#The ERObj is intialised by passing it an RObj instance which it then stores
|
51
|
+
def initialize(robj)
|
52
|
+
@robj = robj
|
53
|
+
@r = RSRuby.instance
|
54
|
+
end
|
55
|
+
|
56
|
+
#Returns the storred RObj.
|
57
|
+
def as_r
|
58
|
+
@robj.as_r
|
59
|
+
end
|
60
|
+
|
61
|
+
#Returns the Ruby representation of the object according to the basic
|
62
|
+
#conversion mode.
|
63
|
+
def to_ruby
|
64
|
+
@robj.to_ruby(RSRuby::BASIC_CONVERSION)
|
65
|
+
end
|
66
|
+
|
67
|
+
#Calls the storred RObj.
|
68
|
+
def lcall(args)
|
69
|
+
@robj.lcall(args)
|
70
|
+
end
|
71
|
+
|
72
|
+
#Outputs the string representation provided by R.
|
73
|
+
def to_s
|
74
|
+
|
75
|
+
@@x += 1
|
76
|
+
|
77
|
+
mode = RSRuby.get_default_mode
|
78
|
+
RSRuby.set_default_mode(RSRuby::NO_CONVERSION)
|
79
|
+
a = @r.textConnection("tmpobj#{@@x}",'w')
|
80
|
+
|
81
|
+
RSRuby.set_default_mode(RSRuby::VECTOR_CONVERSION)
|
82
|
+
@r.sink(:file => a, :type => 'output')
|
83
|
+
@r.print_(@robj)
|
84
|
+
@r.sink.call()
|
85
|
+
@r.close_connection(a)
|
86
|
+
|
87
|
+
str = @r["tmpobj#{@@x}"].join("\n")
|
88
|
+
|
89
|
+
RSRuby.set_default_mode(mode)
|
90
|
+
|
91
|
+
return str
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
#Methods caught by method_missing are converted into attribute calls on
|
96
|
+
#the R object it represents.
|
97
|
+
def method_missing(attr)
|
98
|
+
mode = RSRuby.get_default_mode
|
99
|
+
RSRuby.set_default_mode(RSRuby::BASIC_CONVERSION)
|
100
|
+
e = @r['$'].call(@robj,attr.to_s)
|
101
|
+
RSRuby.set_default_mode(mode)
|
102
|
+
return e
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
data/lib/rsruby/robj.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#== Synopsis
|
2
|
+
#
|
3
|
+
#This class represents a reference to an object in the R interpreter. It
|
4
|
+
#also holds a conversion mode used if the RObj represents a callable function.
|
5
|
+
#RObj objects can be passed to R functions called from Ruby and are the
|
6
|
+
#default return type if RSRuby cannot convert the returned results of an R
|
7
|
+
#function.
|
8
|
+
#
|
9
|
+
#--
|
10
|
+
# == Author
|
11
|
+
# Alex Gutteridge
|
12
|
+
#
|
13
|
+
# == Copyright
|
14
|
+
#Copyright (C) 2006 Alex Gutteridge
|
15
|
+
#
|
16
|
+
#This library is free software; you can redistribute it and/or
|
17
|
+
#modify it under the terms of the GNU Lesser General Public
|
18
|
+
#License as published by the Free Software Foundation; either
|
19
|
+
#version 2.1 of the License, or (at your option) any later version.
|
20
|
+
#
|
21
|
+
#This library is distributed in the hope that it will be useful,
|
22
|
+
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
23
|
+
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
24
|
+
#Lesser General Public License for more details.
|
25
|
+
#
|
26
|
+
#You should have received a copy of the GNU Lesser General Public
|
27
|
+
#License along with this library; if not, write to the Free Software
|
28
|
+
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
29
|
+
#++
|
30
|
+
|
31
|
+
class RObj
|
32
|
+
|
33
|
+
attr_accessor :conversion, :wrap
|
34
|
+
|
35
|
+
def as_r
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
#Attempts to call the RObj with the arguments given. Returns the result
|
40
|
+
#of calling the R object. Only use this method if the RObj represents an
|
41
|
+
#R function.
|
42
|
+
def call(*args)
|
43
|
+
if @wrap
|
44
|
+
e = RSRuby.get_default_mode
|
45
|
+
RSRuby.set_default_mode(@wrap)
|
46
|
+
ret = self.lcall(RSRuby.convert_args_to_lcall(args))
|
47
|
+
RSRuby.set_default_mode(e)
|
48
|
+
else
|
49
|
+
ret = self.lcall(RSRuby.convert_args_to_lcall(args))
|
50
|
+
end
|
51
|
+
return ret
|
52
|
+
end
|
53
|
+
|
54
|
+
#Sets the conversion mode for this RObj (only relevant if the RObj
|
55
|
+
#represents a function). See the constants in RSRuby for valid modes.
|
56
|
+
#Returns the current conversion mode if called with no argument.
|
57
|
+
def autoconvert(m=false)
|
58
|
+
if m
|
59
|
+
raise ArgumentError if m < -1 or m > RSRuby::TOP_CONVERSION
|
60
|
+
@conversion = m
|
61
|
+
end
|
62
|
+
@conversion
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
data/test/table.txt
ADDED
data/test/tc_array.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rsruby'
|
3
|
+
|
4
|
+
class TestArray < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@r = RSRuby.instance
|
8
|
+
#@r.gctorture(:on => false)
|
9
|
+
@ruby_AoA = [[[0,6,12,18],[2,8,14,20],[4,10,16,22]],
|
10
|
+
[[1,7,13,19],[3,9,15,21],[5,11,17,23]]]
|
11
|
+
|
12
|
+
RSRuby.set_default_mode(RSRuby::NO_DEFAULT)
|
13
|
+
@r.array.autoconvert(RSRuby::NO_CONVERSION)
|
14
|
+
@r_array = @r.array({ :data => (0..24).to_a,
|
15
|
+
:dim => [2,3,4]})
|
16
|
+
@r.array.autoconvert(RSRuby::BASIC_CONVERSION)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_boolean
|
20
|
+
assert_equal [true,false], @r.c(true,false)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_convert_to_ruby
|
24
|
+
assert_equal(@ruby_AoA,@r_array.to_ruby)
|
25
|
+
end
|
26
|
+
|
27
|
+
#I suspect this only works in RPy with Numeric?
|
28
|
+
def test_convert_to_R
|
29
|
+
@r.list.autoconvert(RSRuby::NO_CONVERSION)
|
30
|
+
@r['[['].autoconvert(RSRuby::NO_CONVERSION)
|
31
|
+
o = @r['[['].call(@r.list(@ruby_AoA),1)
|
32
|
+
@r['[['].autoconvert(RSRuby::BASIC_CONVERSION)
|
33
|
+
#assert_equal(@r.all_equal(o,@r_array),true)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_dimensions
|
37
|
+
assert_equal(@r.dim(@r_array),[@ruby_AoA.length,
|
38
|
+
@ruby_AoA[0].length,
|
39
|
+
@ruby_AoA[0][0].length])
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_elements
|
43
|
+
assert_equal(@ruby_AoA[0][0][0],@r['[['].call(@r_array, 1,1,1))
|
44
|
+
assert_equal(@ruby_AoA[1][1][1],@r['[['].call(@r_array, 2,2,2))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_ruby_out_of_bounds
|
48
|
+
assert_raise NoMethodError do
|
49
|
+
@ruby_AoA[5][5][5]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_R_out_of_bounds
|
54
|
+
assert_raise RException do
|
55
|
+
@r['[['].call(@r_array, 5,5,5)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/test/tc_boolean.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rsruby'
|
3
|
+
|
4
|
+
class TestBoolean < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@r = RSRuby.instance
|
8
|
+
RSRuby.set_default_mode(RSRuby::NO_DEFAULT)
|
9
|
+
@r.c.autoconvert(RSRuby::BASIC_CONVERSION)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_true
|
13
|
+
assert_block "r.TRUE not working" do
|
14
|
+
(@r.typeof(@r.FALSE) == 'logical' and
|
15
|
+
@r.as_logical(@r.TRUE))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_false
|
20
|
+
assert_block "r.FALSE not working" do
|
21
|
+
(@r.typeof(@r.FALSE) == 'logical' and not
|
22
|
+
@r.as_logical(@r.FALSE))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_boolean_array
|
27
|
+
assert_equal([true,false,true,false],@r.c(true,false,true,false))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/test/tc_cleanup.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rsruby'
|
3
|
+
|
4
|
+
class TestCleanup < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@r = RSRuby.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_shutdown
|
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
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/tc_eval.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rsruby'
|
3
|
+
|
4
|
+
class TestEval < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@r = RSRuby.instance
|
8
|
+
@r.proc_table = {}
|
9
|
+
@r.class_table = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_eval_R
|
13
|
+
#Test integer, Float, String and Boolean return values
|
14
|
+
assert_equal(@r.eval_R("sum(1,2,3)"),6)
|
15
|
+
assert_equal(@r.eval_R("sum(1.5,2.5,3.5)"),7.5)
|
16
|
+
assert_equal(@r.eval_R("eval('R')"),"R")
|
17
|
+
assert_equal(@r.eval_R("is(1,'numeric')"),true)
|
18
|
+
assert_equal(@r.eval_R("is(1,'madeup')"),false)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rsruby'
|
3
|
+
|
4
|
+
class TestNewCases < Test::Unit::TestCase
|
5
|
+
@@test_dir = File.expand_path File.dirname(__FILE__)
|
6
|
+
|
7
|
+
def test_erobj
|
8
|
+
|
9
|
+
require 'rsruby/erobj'
|
10
|
+
r = RSRuby.instance
|
11
|
+
r.proc_table[lambda{|x| true}] = lambda{|x| ERObj.new(x)}
|
12
|
+
RSRuby.set_default_mode(RSRuby::PROC_CONVERSION)
|
13
|
+
|
14
|
+
f = r.c(1,2,3)
|
15
|
+
assert_equal('[1] 1 2 3',f.to_s)
|
16
|
+
assert_equal([1,2,3],f.to_ruby)
|
17
|
+
assert_instance_of(RObj,f.as_r)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_dataframe
|
22
|
+
|
23
|
+
require 'rsruby/dataframe'
|
24
|
+
r = RSRuby.instance
|
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])
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|