alexgutteridge-rsruby 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 +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
|