rinruby 2.0.3 → 2.1.0

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.
@@ -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
+