rinruby 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ #=RinRuby: Accessing the R[http://www.r-project.org] interpreter from pure Ruby
2
+ #
3
+ #RinRuby is a Ruby library that integrates the R interpreter in Ruby, making R's statistical routines and graphics available within Ruby. The library consists of a single Ruby script that is simple to install and does not require any special compilation or installation of R. Since the library is 100% pure Ruby, it works on a variety of operating systems, Ruby implementations, and versions of R. RinRuby's methods are simple, making for readable code. The {website [rinruby.ddahl.org]}[http://rinruby.ddahl.org] describes RinRuby usage, provides comprehensive documentation, gives several examples, and discusses RinRuby's implementation.
4
+ #
5
+
6
+ if defined?(R)
7
+ require 'rinruby'
8
+ else
9
+ R = :dummy
10
+ require 'rinruby'
11
+ Object::send(:remove_const, :R)
12
+ end
13
+
14
+ class RinRubyWithoutRConstant < RinRuby
15
+ DEFAULT_PORT_NUMBER = 38542
16
+ def initialize(*args)
17
+ if args.size == 1 and args[0].kind_of?(Hash) then
18
+ args[0][:port_number] ||= DEFAULT_PORT_NUMBER
19
+ else
20
+ args[3] ||= DEFAULT_PORT_NUMBER
21
+ end
22
+ super(*args)
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Rinruby
2
+ VERSION = "2.1.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rinruby"
8
+ spec.version = Rinruby::VERSION
9
+ spec.authors = ["David Dahl", "Scott Crawford", "Claudio Bustos"]
10
+ spec.email = ["rinruby@ddahl.org", "scott@ddahl.org", "clbustos@gmail.com"]
11
+ spec.summary = %q{RinRuby is a Ruby library that integrates the R interpreter in Ruby}
12
+ spec.description = %q{RinRuby is a Ruby library that integrates the R interpreter in Ruby, making R's statistical routines and graphics available within Ruby. The library consists of a single Ruby script that is simple to install and does not require any special compilation or installation of R. Since the library is 100% pure Ruby, it works on a variety of operating systems, Ruby implementations, and versions of R. RinRuby's methods are simple, making for readable code. The {website [rinruby.ddahl.org]}[http://rinruby.ddahl.org] describes RinRuby usage, provides comprehensive documentation, gives several examples, and discusses RinRuby's implementation.}
13
+ spec.homepage = "http://rinruby.ddahl.org"
14
+ spec.license = "Copyright 2005-2008 David B. Dahl"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec", ">= 2.11"
23
+ spec.add_development_dependency "hoe"
24
+ end
@@ -1,148 +1,235 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'rinruby'
2
3
  puts "RinRuby #{RinRuby::VERSION} specification"
3
4
 
4
- describe RinRuby do
5
+ shared_examples 'RinRubyCore' do
6
+ let(:params){
7
+ {
8
+ :echo_enabled => false,
9
+ :interactive => false,
10
+ :executable => nil,
11
+ :port_number => 38500,
12
+ :port_width => 1000,
13
+ }
14
+ }
5
15
  describe "on init" do
16
+ after{(r.quit rescue nil) if defined?(r)}
6
17
  it "should accept parameters as specified on Dahl & Crawford(2009)" do
7
-
8
- platform = case RUBY_PLATFORM
9
- when /mswin/ then 'windows'
10
- when /mingw/ then 'windows'
11
- when /bccwin/ then 'windows'
12
- else
13
- "other"
14
- end
15
- if platform=='windows'
16
- pending("Difficult to test without specific location of R executable on Windows")
17
- else
18
-
19
- r=RinRuby.new(false, false, "R", 38500, 1)
20
- r.echo_enabled.should_not be_true
21
- r.interactive.should_not be_true
22
- r.executable.should=="R"
23
- r.port_number.should==38500
24
- r.port_width.should==1
25
- end
18
+ expect(r.echo_enabled).to be_falsy
19
+ expect(r.interactive).to be_falsy
20
+ case r.instance_variable_get(:@platform)
21
+ when /^windows/ then
22
+ expect(r.executable).to match(/Rterm\.exe["']?$/)
23
+ else
24
+ expect(r.executable).to eq("R")
25
+ end
26
26
  end
27
27
  it "should accept :echo and :interactive parameters" do
28
- r=RinRuby.new(:echo=>false, :interactive=>false)
29
- r.echo_enabled.should_not be_true
30
- r.interactive.should_not be_true
31
-
32
- end
33
- it "should accept :port_number" do
34
- port=38442+rand(3)
35
- r=RinRuby.new(:port_number=>port,:port_width=>1)
36
- r.port_number.should==port
37
- r.quit
38
- end
39
- it "should accept :port_width" do
40
- port=38442
41
- port_width=rand(10)
42
- r=RinRuby.new(:port=>port, :port_width=>port_width)
43
- r.port_width.should==port_width
44
- r.port_number.should satisfy {|v| v>=port and v < port+port_width}
45
- end
46
- end
47
- before do
48
- R.echo(false)
49
- end
50
- subject {R}
51
- context "basic methods" do
52
- it {should respond_to :eval}
53
- it {should respond_to :quit}
54
- it {should respond_to :assign}
55
- it {should respond_to :pull}
56
- it {should respond_to :quit}
57
- it {should respond_to :echo}
58
- it "return correct values for complete?" do
59
- R.eval("x<-1").should be_true
60
- end
61
- it "return false for complete? for incorrect expressions" do
62
- R.complete?("x<-").should be_false
63
- end
64
- it "correct eval should return true" do
65
- R.complete?("x<-1").should be_true
66
- end
67
- it "incorrect eval should raise an ParseError" do
68
- lambda {R.eval("x<-")}.should raise_error(RinRuby::ParseError)
28
+ params.merge!(:echo_enabled => true, :interactive => true)
29
+ expect(r.echo_enabled).to be_truthy
30
+ expect(r.interactive).to be_truthy
31
+ end
32
+ it "should accept custom :port_number" do
33
+ params.merge!(:port_number => 38442+rand(3), :port_width => 1)
34
+ expect(r.port_number).to eq(params[:port_number])
35
+ end
36
+ it "should accept custom :port_width" do
37
+ params.merge!(:port_number => 38442, :port_width => rand(10)+1)
38
+ expect(r.port_width).to eq(params[:port_width])
39
+ expect(r.port_number).to satisfy {|v|
40
+ ((params[:port_number])...(params[:port_number] + params[:port_width])).include?(v)
41
+ }
69
42
  end
70
43
  end
71
- context "on assing" do
72
- it "should assign correctly" do
73
- x=rand
74
- R.assign("x",x)
75
- R.pull("x").should==x
76
- end
77
- it "should be the same using assign than R#= methods" do
78
- x=rand
79
- R.assign("x1",x)
80
- R.x2=x
81
- R.pull("x1").should==x
82
- R.pull("x2").should==x
83
- end
84
- it "should raise an ArgumentError error on setter with 0 parameters" do
85
- lambda {R.unknown_method=() }.should raise_error(ArgumentError)
86
- end
87
-
88
- end
89
- context "on pull" do
90
- it "should be the same using pull than R# methods" do
91
- x=rand
92
- R.x=x
93
- R.pull("x").should==x
94
- R.x.should==x
95
- end
96
- it "should raise an NoMethod error on getter with 1 or more parameters" do
97
- lambda {R.unknown_method(1) }.should raise_error(NoMethodError)
44
+
45
+ describe "R interface" do
46
+ # In before(:each) or let(including subject) blocks, Assignment to instance variable
47
+ # having a same name defined in before(:all) will not work intentionally,
48
+ # because a new instance variable will be created for the following examples.
49
+ # For workaround, two-step indirect assignment to a hash created in before(:all) is applied.
50
+ before(:all){@cached_env = {:r => nil}} # make placeholder
51
+ subject{@cached_env[:r] ||= r}
52
+ after(:all){@cached_env[:r].quit rescue nil}
53
+ describe "basic methods" do
54
+ it {is_expected.to respond_to(:eval)}
55
+ it {is_expected.to respond_to(:assign)}
56
+ it {is_expected.to respond_to(:pull)}
57
+ it {is_expected.to respond_to(:quit)}
58
+ it {is_expected.to respond_to(:echo)}
59
+ it "return correct values for complete?" do
60
+ expect(subject.eval("x<-1")).to be_truthy
61
+ end
62
+ it "return false for complete? for incorrect expressions" do
63
+ expect(subject.complete?("x<-")).to be_falsy
64
+ end
65
+ it "correct eval should return true" do
66
+ expect(subject.complete?("x<-1")).to be_truthy
67
+ end
68
+ it "incorrect eval should raise an ParseError" do
69
+ expect{subject.eval("x<-")}.to raise_error(RinRuby::ParseError)
70
+ end
98
71
  end
99
72
 
100
- it "should pull a String" do
101
- R.eval("x<-'Value'")
102
- R.pull('x').should=='Value'
103
- end
104
- it "should pull an Integer" do
105
- R.eval("x<-1")
106
- R.pull('x').should==1
107
- end
108
- it "should pull a Float" do
109
- R.eval("x<-1.5")
110
- R.pull('x').should==1.5
111
- end
112
- it "should pull an Array of Numeric" do
113
- R.eval("x<-c(1,2.5,3)")
114
- R.pull('x').should==[1,2.5,3]
115
- end
116
- it "should pull an Array of strings" do
117
- R.eval("x<-c('a','b')")
118
- R.pull('x').should==['a','b']
119
- end
73
+ context "on pull" do
74
+ it "should pull a String" do
75
+ subject.eval("x<-'Value'")
76
+ expect(subject.pull('x')).to eql('Value')
77
+ end
78
+ it "should pull an Integer" do
79
+ [0x12345678, -0x12345678].each{|v| # for check endian, and range
80
+ subject.eval("x<-#{v}L")
81
+ expect(subject.pull('x')).to eql(v)
82
+ }
83
+ end
84
+ it "should pull a Float" do
85
+ [1.5, 1.0].each{|v|
86
+ subject.eval("x<-#{v}e0")
87
+ expect(subject.pull('x')).to eql(v)
88
+ }
89
+ [1 << 32, -(1 << 32)].each{|v| # big integer will be treated as float
90
+ subject.eval("x<-#{v}")
91
+ expect(subject.pull('x')).to eql(v.to_f)
92
+ }
93
+ end
94
+ it "should pull a Logical" do
95
+ {:T => true, :F => false}.each{|k, v|
96
+ subject.eval("x<-#{k}")
97
+ expect(subject.pull('x')).to eql(v)
98
+ }
99
+ end
100
+ it "should pull an Array of String" do
101
+ subject.eval("x<-c('a','b')")
102
+ expect(subject.pull('x')).to eql(['a','b'])
103
+ end
104
+ it "should pull an Array of Integer" do
105
+ subject.eval("x<-c(1L,2L,-5L,-3L)")
106
+ expect(subject.pull('x')).to eql([1,2,-5,-3])
107
+ end
108
+ it "should pull an Array of Float" do
109
+ subject.eval("x<-c(1.1,2.2,5,3)")
110
+ expect(subject.pull('x')).to eql([1.1,2.2,5.0,3.0])
111
+ subject.eval("x<-c(1L,2L,5L,3.0)") # numeric vector
112
+ expect(subject.pull('x')).to eql([1.0,2.0,5.0,3.0])
113
+ end
114
+ it "should pull an Array of Logical" do
115
+ subject.eval("x<-c(T, F)")
116
+ expect(subject.pull('x')).to eql([true, false])
117
+ end
120
118
 
121
- it "should push a Matrix" do
122
- matrix=Matrix[[rand,rand,rand],[rand,rand,rand]]
123
- lambda {R.assign('x',matrix)}.should_not raise_error
124
- rx=R.x
125
- matrix.row_size.times {|i|
126
- matrix.column_size.times {|j|
127
- matrix[i,j].should be_within(1e-10).of(rx[i,j])
119
+ it "should pull a Matrix" do
120
+ [
121
+ proc{ # integer matrix
122
+ v = rand(100000000) # get 8 digits
123
+ [v, "#{v}L"]
124
+ },
125
+ proc{ # float matrix
126
+ v = rand(100000000) # get 8 digits
127
+ [Float("0.#{v}"), "0.#{v}"]
128
+ },
129
+ ].each{|gen_proc|
130
+ nrow, ncol = [10, 10] # 10 x 10 small matrix
131
+ subject.eval("x<-matrix(nrow=#{nrow}, ncol=#{ncol})")
132
+ rx = Matrix[*((1..nrow).collect{|i|
133
+ (1..ncol).collect{|j|
134
+ v_rb, v_R = gen_proc.call
135
+ subject.eval("x[#{i},#{j}]<-#{v_R}")
136
+ v_rb
137
+ }
138
+ })]
139
+ expect(subject.pull('x')).to eql(rx)
128
140
  }
129
- }
141
+ end
142
+
143
+ it "should be the same using pull than R# methods" do
144
+ subject.eval("x <- #{rand(100000000)}")
145
+ expect(subject.pull("x")).to eql(subject.x)
146
+ end
147
+ it "should raise an NoMethod error on getter with 1 or more parameters" do
148
+ expect{subject.unknown_method(1)}.to raise_error(NoMethodError)
149
+ end
130
150
  end
131
151
 
132
- end
152
+ context "on assign (PREREQUISITE: all pull tests are passed)" do
153
+ it "should assign a String" do
154
+ x = 'Value'
155
+ subject.assign("x", x)
156
+ expect(subject.pull('x')).to eql(x)
157
+ end
158
+ it "should assign an Integer" do
159
+ [0x12345678, -0x12345678].each{|x|
160
+ subject.assign("x", x)
161
+ expect(subject.pull('x')).to eql(x)
162
+ }
163
+ end
164
+ it "should assign a Float" do
165
+ [rand, 1 << 32, -(1 << 32)].each{|x|
166
+ subject.assign("x", x)
167
+ expect(subject.pull('x')).to eql(x.to_f)
168
+ }
169
+ end
170
+ it "should assign a Logical" do
171
+ [true, false].each{|x|
172
+ subject.assign("x", x)
173
+ expect(subject.pull('x')).to eql(x)
174
+ }
175
+ end
176
+ it "should assign an Array of String" do
177
+ x = ['a', 'b']
178
+ subject.assign("x", x)
179
+ expect(subject.pull('x')).to eql(x)
180
+ end
181
+ it "should assign an Array of Integer" do
182
+ x = [1, 2, -5, -3]
183
+ subject.assign("x", x)
184
+ expect(subject.pull('x')).to eql(x)
185
+ end
186
+ it "should assign an Array of Float" do
187
+ subject.assign("x", [1.1, 2.2, 5, 3])
188
+ expect(subject.pull('x')).to eql([1.1,2.2,5.0,3.0])
189
+ end
190
+ it "should assign an Array of Logical" do
191
+ x = [true, false]
192
+ subject.assign("x", x)
193
+ expect(subject.pull('x')).to eql(x)
194
+ end
133
195
 
196
+ it "should assign a Matrix" do
197
+ [
198
+ proc{rand(100000000)}, # integer matrix
199
+ proc{rand}, # float matrix
200
+ ].each{|gen_proc|
201
+ x = Matrix::build(100, 200){|i, j| gen_proc.call} # 100 x 200 matrix
202
+ subject.assign("x", x)
203
+ expect(subject.pull('x')).to eql(x)
204
+ }
205
+ end
206
+
207
+ it "should be the same using assign than R#= methods" do
208
+ x = rand(100000000)
209
+ subject.assign("x1", x)
210
+ subject.x2 = x
211
+ expect(subject.pull("x1")).to eql(subject.pull("x2"))
212
+ end
213
+ it "should raise an ArgumentError error on setter with 0 parameters" do
214
+ expect{subject.unknown_method=() }.to raise_error(ArgumentError)
215
+ end
216
+ end
217
+ end
218
+
134
219
  context "on quit" do
135
- before(:each) do
136
- @r=RinRuby.new(:echo=>false)
137
- end
138
220
  it "return true" do
139
- @r.quit.should be_true
221
+ expect(r.quit).to be_truthy
140
222
  end
141
223
  it "returns an error if used again" do
142
- @r.quit
143
- lambda {@r.eval("x=1")}.should raise_error(RinRuby::EngineClosed)
224
+ r.quit
225
+ expect{r.eval("x=1")}.to raise_error(RinRuby::EngineClosed)
144
226
  end
145
227
  end
146
-
147
-
148
228
  end
229
+
230
+ describe RinRuby do
231
+ let(:r){
232
+ RinRuby.new(*([:echo_enabled, :interactive, :executable, :port_number, :port_width].collect{|k| params[k]}))
233
+ }
234
+ include_examples 'RinRubyCore'
235
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'rinruby_without_r_constant'
3
+
4
+ describe RinRubyWithoutRConstant do
5
+ let(:r){
6
+ RinRubyWithoutRConstant.new(*([:echo_enabled, :interactive, :executable, :port_number, :port_width].collect{|k| params[k]}))
7
+ }
8
+ include_examples 'RinRubyCore'
9
+ end
@@ -1,16 +1,28 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
2
2
  $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
3
- require 'rinruby'
4
3
  require 'rspec'
5
-
6
4
  require 'matrix'
7
5
 
8
6
  RSpec.configure do |config|
9
-
7
+ config.expect_with :rspec do |c|
8
+ c.syntax = [:should, :expect]
9
+ end
10
+
11
+ # Use color in STDOUT
12
+ config.color = true
13
+
14
+ # Use color not only in STDOUT but also in pagers and files
15
+ config.tty = true
16
+
17
+ # Use the specified formatter
18
+ config.formatter = :documentation # :progress, :html, :textmate
10
19
  end
11
20
 
21
+
12
22
  class String
13
23
  def deindent
14
- gsub /^[ \t]*/, ''
24
+ gsub /^[ \t]*/, ''
15
25
  end
16
26
  end
27
+
28
+