Class: RinRuby
Direct Known Subclasses
Defined Under Namespace
Classes: R_Character, R_DataType, R_Double, R_Integer, R_Logical
Constant Summary collapse
- EngineClosed =
Exception for closed engine
Class.new(RuntimeError)
- ParseError =
Parse error
Class.new(RuntimeError)
- RinRuby_Env =
".RinRuby"- RinRuby_Endian =
([1].pack("L").unpack("C*")[0] == 1) ? (:little) : (:big)
- VERSION =
"2.1.0"
Instance Attribute Summary collapse
-
#echo_enabled ⇒ Object
Returns the value of attribute echo_enabled.
-
#executable ⇒ Object
readonly
Returns the value of attribute executable.
-
#hostname ⇒ Object
readonly
Returns the value of attribute hostname.
-
#interactive ⇒ Object
readonly
Returns the value of attribute interactive.
-
#port_number ⇒ Object
readonly
Returns the value of attribute port_number.
-
#port_width ⇒ Object
readonly
Returns the value of attribute port_width.
-
#readline ⇒ Object
readonly
Returns the value of attribute readline.
Class Method Summary collapse
Instance Method Summary collapse
-
#assign(name, value) ⇒ Object
Data is copied from Ruby to R using the assign method or a short-hand equivalent.
- #complete?(string) ⇒ Boolean
-
#echo(enable = nil, stderr = nil) ⇒ Object
The echo method controls whether the eval method displays output from R and, if echo is enabled, whether messages, warnings, and errors from stderr are also displayed.
-
#eval(string, echo_override = nil, &b) ⇒ Object
The eval instance method passes the R commands contained in the supplied string and displays any resulting plots or prints the output.
-
#initialize(*args) ⇒ RinRuby
constructor
RinRuby is invoked within a Ruby script (or the interactive “irb” prompt denoted >>) using:.
-
#method_missing(symbol, *args) ⇒ Object
If a method is called which is not defined, then it is assumed that the user is attempting to either pull or assign a variable to R.
-
#prompt(regular_prompt = "> ", continue_prompt = "+ ") ⇒ Object
When sending code to Ruby using an interactive prompt, this method will change the prompt to an R prompt.
-
#pull(string, singletons = false) ⇒ Object
Data is copied from R to Ruby using the pull method or a short-hand equivalent.
-
#quit ⇒ Object
The quit method will properly close the bridge between Ruby and R, freeing up system resources.
Constructor Details
#initialize(*args) ⇒ RinRuby
RinRuby is invoked within a Ruby script (or the interactive “irb” prompt denoted >>) using:
>> require "rinruby"
The previous statement reads the definition of the RinRuby class into the current Ruby interpreter and creates an instance of the RinRuby class named R. There is a second method for starting an instance of R which allows the user to use any name for the instance, in this case myr:
>> require "rinruby"
>> myr = RinRuby.new
>> myr.eval "rnorm(1)"
Any number of independent instances of R can be created in this way.
Parameters that can be passed to the new method using a Hash:
-
:echo: By setting the echo to false, output from R is suppressed, although warnings are still printed. This option can be changed later by using the echo method. The default is true.
-
:interactive: When interactive is false, R is run in non-interactive mode, resulting in plots without an explicit device being written to Rplots.pdf. Otherwise (i.e., interactive is true), plots are shown on the screen. The default is true.
-
:executable: The path of the R executable (which is “R” in Linux and Mac OS X, or “Rterm.exe” in Windows) can be set with the executable argument. The default is nil which makes RinRuby use the registry keys to find the path (on Windows) or use the path defined by $PATH (on Linux and Mac OS X).
-
:port_number: This is the smallest port number on the local host that could be used to pass data between Ruby and R. The actual port number used depends on port_width.
-
:port_width: RinRuby will randomly select a uniform number between port_number and port_number + port_width - 1 (inclusive) to pass data between Ruby and R. If the randomly selected port is not available, RinRuby will continue selecting random ports until it finds one that is available. By setting port_width to 1, RinRuby will wait until port_number is available. The default port_width is 1000.
It may be desirable to change the parameters to the instance of R, but still call it by the name of R. In that case the old instance of R which was created with the ‘require “rinruby”’ statement should be closed first using the quit method which is explained below. Unless the previous instance is killed, it will continue to use system resources until exiting Ruby. The following shows an example by changing the parameter echo:
>> require "rinruby"
>> R.quit
>> R = RinRuby.new(false)
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/rinruby.rb', line 109 def initialize(*args) @opts = {:echo=>true, :interactive=>true, :executable=>nil, :port_number=>38442, :port_width=>1000, :hostname=>'127.0.0.1', :persistent => true} if args.size==1 and args[0].is_a? Hash @opts.merge!(args[0]) else [:echo, :interactive, :executable, :port_number, :port_width].zip(args).each{|k, v| @opts[k] = ((v == nil) ? @opts[k] : v) } end [:port_width, :executable, :hostname, :interactive, [:echo, :echo_enabled]].each{|k_src, k_dst| Kernel.eval("@#{k_dst || k_src} = @opts[:#{k_src}]", binding) } @echo_stderr = false raise Errno::EADDRINUSE unless (@port_number = (@opts[:port_number]...(@opts[:port_number] + @opts[:port_width])).to_a.shuffle.find{|i| begin @server_socket = TCPServer::new(@hostname, i) rescue Errno::EADDRINUSE false end }) @platform = case RUBY_PLATFORM when /mswin/, /mingw/, /bccwin/ then 'windows' when /cygwin/ then 'windows-cygwin' when /java/ require 'java' #:nodoc: "#{java.lang.System.getProperty('os.name') =~ /[Ww]indows/ ? 'windows' : 'default'}-java" else 'default' end @executable ||= ( @platform =~ /windows/ ) ? self.class.find_R_on_windows(@platform =~ /cygwin/) : 'R' @platform_options = [] if @interactive then if @executable =~ /Rterm\.exe["']?$/ then @platform_options += ['--ess'] elsif @platform !~ /java$/ then # intentionally interactive off under java @platform_options += ['--no-readline', '--interactive'] end end cmd = %Q<#{executable} #{@platform_options.join(' ')} --slave> cmd = (@platform =~ /^windows(?!-cygwin)/) ? "#{cmd} 2>NUL" : "exec #{cmd} 2>/dev/null" if @platform_options.include?('--interactive') then require 'pty' @reader, @writer, @r_pid = PTY::spawn("stty -echo && #{cmd}") else @writer = @reader = IO::popen(cmd, 'w+') @r_pid = @reader.pid end raise EngineClosed if (@reader.closed? || @writer.closed?) @writer.puts <<-EOF assign("#{RinRuby_Env}", new.env(), envir = globalenv()) EOF @socket = nil [:socket_io, :assign, :pull, :check].each{|fname| self.send("r_rinruby_#{fname}")} @writer.flush @eval_count = 0 eval("0", false) # cleanup @reader # JRuby on *NIX runs forcefully in non-interactive, where stop() halts R execution immediately in default. # To continue when R error occurs, an error handler is added as a workaround # @see https://stat.ethz.ch/R-manual/R-devel/library/base/html/stop.html eval("options(error=dump.frames)") if @platform =~ /^(?!windows-).*java$/ end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args) ⇒ Object
If a method is called which is not defined, then it is assumed that the user is attempting to either pull or assign a variable to R. This allows for the short-hand equivalents to the pull and assign methods. For example:
>> R.x = 2
is the same as:
>> R.assign("x",2)
Also:
>> n = R.x
is the same as:
>> n = R.pull("x")
The parameters passed to method_missing are those used for the pull or assign depending on the context.
300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/rinruby.rb', line 300 def method_missing(symbol, *args) name = symbol.id2name if name =~ /(.*)=$/ raise ArgumentError, "You shouldn't assign nil" if args==[nil] super if args.length != 1 assign($1,args[0]) else super if args.length != 0 pull(name) end end |
Instance Attribute Details
#echo_enabled ⇒ Object
Returns the value of attribute echo_enabled.
78 79 80 |
# File 'lib/rinruby.rb', line 78 def echo_enabled @echo_enabled end |
#executable ⇒ Object (readonly)
Returns the value of attribute executable.
79 80 81 |
# File 'lib/rinruby.rb', line 79 def executable @executable end |
#hostname ⇒ Object (readonly)
Returns the value of attribute hostname.
82 83 84 |
# File 'lib/rinruby.rb', line 82 def hostname @hostname end |
#interactive ⇒ Object (readonly)
Returns the value of attribute interactive.
76 77 78 |
# File 'lib/rinruby.rb', line 76 def interactive @interactive end |
#port_number ⇒ Object (readonly)
Returns the value of attribute port_number.
80 81 82 |
# File 'lib/rinruby.rb', line 80 def port_number @port_number end |
#port_width ⇒ Object (readonly)
Returns the value of attribute port_width.
81 82 83 |
# File 'lib/rinruby.rb', line 81 def port_width @port_width end |
#readline ⇒ Object (readonly)
Returns the value of attribute readline.
77 78 79 |
# File 'lib/rinruby.rb', line 77 def readline @readline end |
Class Method Details
.find_R_dir_on_windows(cygwin = false, &b) ⇒ Object
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 |
# File 'lib/rinruby.rb', line 968 def find_R_dir_on_windows(cygwin = false, &b) res = [] b ||= proc{} # Firstly, check registry ['HKEY_LOCAL_MACHINE', 'HKEY_CURRENT_USER'].each{|root| if cygwin then [:w, :W].collect{|opt| # [64bit, then 32bit registry] [:R64, :R].collect{|mode| `regtool list -#{opt} /#{root}/Software/R-core/#{mode} 2>/dev/null`.lines.collect{|v| v =~ /^\d\.\d\.\d/ ? $& : nil }.compact.sort{|a, b| # latest version has higher priority b <=> a }.collect{|ver| ["-#{opt}", "/#{root}/Software/R-core/#{mode}/#{ver}/InstallPath"] } } }.flatten(2).each{|args| v = `cygpath '#{`regtool get #{args.join(' ')}`.strip}'`.strip b.call((res << v)[-1]) unless (v.empty? || res.include?(v)) } else scrub(`reg query "#{root}\\Software\\R-core" /v "InstallPath" /s 2>nul`).each_line{|line| next unless line.strip =~ /^\s*InstallPath\s+REG_SZ\s+(.+)/ b.call((res << $1)[-1]) unless res.include?($1) } end } # Secondly, check default install path ["Program Files", "Program Files (x86)"].each{|prog_dir| Dir::glob(File::join(cygwin ? "/cygdrive/c" : "C:", prog_dir, "R", "*")).each{|path| b.call((res << path)[-1]) unless res.include?(path) } } res end |
.find_R_on_windows(cygwin = false) ⇒ Object
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
# File 'lib/rinruby.rb', line 1007 def find_R_on_windows(cygwin = false) return 'R' if cygwin && system('which R > /dev/nul 2>&1') find_R_dir_on_windows(cygwin){|path| ['bin', 'bin/x64', 'bin/i386'].product( cygwin ? [path.gsub(' ','\ '), path] : [path.gsub('\\','/')]).each{|bin_dir, base_dir| r_exe = File::join(base_dir, bin_dir, "Rterm.exe") return %Q<"#{r_exe}"> if File.exists?(r_exe) } } raise "Cannot locate R executable" end |
Instance Method Details
#assign(name, value) ⇒ Object
Data is copied from Ruby to R using the assign method or a short-hand equivalent. For example:
>> names = ["Lisa","Teasha","Aaron","Thomas"]
>> R.assign "people", names
>> R.eval "sort(people)"
produces the following :
[1] "Aaron" "Lisa" "Teasha" "Thomas"
The short-hand equivalent to the assign method is simply:
>> R.people = names
Some care is needed when using the short-hand of the assign method since the label (i.e., people in this case) must be a valid method name in Ruby. For example, R.copy.of.names = names will not work, but R.copy_of_names = names is permissible.
The assign method supports Ruby variables of type Fixnum (i.e., integer), Bignum (i.e., integer), Float (i.e., double), String, and arrays of one of those three fundamental types. Note that Fixnum or Bignum values that exceed the capacity of R’s integers are silently converted to doubles. Data in other formats must be coerced when copying to R.
Parameters that can be passed to the assign method:
-
name: The name of the variable desired in R.
-
value: The value the R variable should have. The assign method supports Ruby variables of type Fixnum (i.e., integer), Bignum (i.e., integer), Float (i.e., double), String, and arrays of one of those three fundamental types. Note that Fixnum or Bignum values that exceed the capacity of R’s integers are silently converted to doubles. Data in other formats must be coerced when copying to R.
The assign method is an alternative to the simplified method, with some additional flexibility. When using the simplified method, the parameters of name and value are automatically used, in other words:
>> R.test = 144
is the same as:
>> R.assign("test",144)
Of course it would be confusing to use the shorthand notation to assign a variable named eval, echo, or any other already defined function. RinRuby would assume you were calling the function, rather than trying to assign a variable.
When assigning an array containing differing types of variables, RinRuby will follow R’s conversion conventions. An array that contains any Strings will result in a character vector in R. If the array does not contain any Strings, but it does contain a Float or a large integer (in absolute value), then the result will be a numeric vector of Doubles in R. If there are only integers that are sufficiently small (in absolute value), then the result will be a numeric vector of integers in R.
348 349 350 351 352 |
# File 'lib/rinruby.rb', line 348 def assign(name, value) if_assignable(name){|fun| assign_engine(fun, value) } end |
#complete?(string) ⇒ Boolean
902 903 904 |
# File 'lib/rinruby.rb', line 902 def complete?(string) if_complete(string.lines) end |
#echo(enable = nil, stderr = nil) ⇒ Object
The echo method controls whether the eval method displays output from R and, if echo is enabled, whether messages, warnings, and errors from stderr are also displayed.
Parameters that can be passed to the eval method
-
enable: Setting enable to false will turn all output off until the echo command is used again with enable equal to true. The default is nil, which will return the current setting.
-
stderr: Setting stderr to true will force messages, warnings, and errors from R to be routed through stdout. Using stderr redirection is typically not needed, and is thus disabled by default. Echoing must be enabled when using stderr redirection.
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/rinruby.rb', line 421 def echo(enable=nil, stderr=nil) next_enabled = (enable == nil) ? @echo_enabled : (enable ? true : false) next_stderr = case stderr when nil (next_enabled ? @echo_stderr : false) else (stderr ? true : false) end if (next_enabled == false) && (next_stderr == true) then # prohibited combination raise "You can only redirect stderr if you are echoing is enabled." end if @echo_stderr != next_stderr then @writer.print(<<-__TEXT__) sink(#{'stdout(),' if next_stderr}type='message') __TEXT__ @writer.flush end [@echo_enabled = next_enabled, @echo_stderr = next_stderr] end |
#eval(string, echo_override = nil, &b) ⇒ Object
The eval instance method passes the R commands contained in the supplied string and displays any resulting plots or prints the output. For example:
>> sample_size = 10
>> R.eval "x <- rnorm(#{sample_size})"
>> R.eval "summary(x)"
>> R.eval "sd(x)"
produces the following:
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.88900 -0.84930 -0.45220 -0.49290 -0.06069 0.78160
[1] 0.7327981
This example used a string substitution to make the argument to first eval method equivalent to x <- rnorm(10). This example used three invocations of the eval method, but a single invoke is possible using a here document:
>> R.eval <<EOF
x <- rnorm(#{sample_size})
summary(x)
sd(x)
EOF
Parameters that can be passed to the eval method
-
string: The string parameter is the code which is to be passed to R, for example, string = “hist(gamma(1000,5,3))”. The string can also span several lines of code by use of a here document, as shown:
R.eval <<EOF x<-rgamma(1000,5,3) hist(x) EOF -
echo_override: This argument allows one to set the echo behavior for this call only. The default for echo_override is nil, which does not override the current echo behavior.
-
b: echo block, which will be used as echo_override when echo_override equals to nil
225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/rinruby.rb', line 225 def eval(string, echo_override = nil, &b) echo_proc = case echo_override # echo on when echo_proc == nil when Proc echo_override when nil b || (@echo_enabled ? nil : proc{}) else echo_override ? nil : proc{} end if_parseable(string){|fun| eval_engine("#{fun}()", &echo_proc) } end |
#prompt(regular_prompt = "> ", continue_prompt = "+ ") ⇒ Object
When sending code to Ruby using an interactive prompt, this method will change the prompt to an R prompt. From the R prompt commands can be sent to R exactly as if the R program was actually running. When the user is ready to return to Ruby, then the command exit() will return the prompt to Ruby. This is the ideal situation for the explorative programmer who needs to run several lines of code in R, and see the results after each command. This is also an easy way to execute loops without the use of a here document. It should be noted that the prompt command does not work in a script, just Ruby’s interactive irb.
Parameters that can be passed to the prompt method:
-
regular_prompt: This defines the string used to denote the R prompt.
-
continue_prompt: This is the string used to denote R’s prompt for an incomplete statement (such as a multiple for loop).
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/rinruby.rb', line 248 def prompt(regular_prompt="> ", continue_prompt="+ ") warn "'interactive' mode is off in this session " unless @interactive @readline ||= begin # initialize @readline at the first invocation require 'readline' proc{|prompt| Readline.readline(prompt, true)} rescue LoadError proc{|prompt| print prompt $stdout.flush gets.strip rescue nil } end cmds = [] while true cmds << @readline.call(cmds.empty? ? regular_prompt : continue_prompt) if cmds[-1] then # the last "nil" input suspend current stack break if /^\s*exit\s*\(\s*\)\s*$/ =~ cmds[0] begin completed, eval_res = if_complete(cmds){|fun| [true, eval_engine("#{fun}()")] } next unless completed break unless eval_res rescue ParseError => e puts e. end end cmds = [] end true end |
#pull(string, singletons = false) ⇒ Object
Data is copied from R to Ruby using the pull method or a short-hand equivalent. The R object x defined with an eval method can be copied to Ruby object copy_of_x as follows:
>> R.eval "x <- rnorm(10)"
>> copy_of_x = R.pull "x"
>> puts copy_of_x
which produces the following :
-0.376404489256671
-1.0759798269397
-0.494240140140996
0.131171385795721
-0.878328334369391
-0.762290423047929
-0.410227216105828
0.0445512804225151
-1.88887454545995
0.781602719849499
RinRuby also supports a convenient short-hand notation when the argument to pull is simply a previously-defined R object (whose name conforms to Ruby’s requirements for method names). For example:
>> copy_of_x = R.x
The explicit assign method, however, can take an arbitrary R statement. For example:
>> summary_of_x = R.pull "as.numeric(summary(x))"
>> puts summary_of_x
produces the following:
-1.889
-0.8493
-0.4522
-0.4929
-0.06069
0.7816
Notice the use above of the as.numeric function in R. This is necessary since the pull method only supports R vectors which are numeric (i.e., integers or doubles) and character (i.e., strings). Data in other formats must be coerced when copying to Ruby.
Parameters that can be passed to the pull method:
-
string: The name of the variable that should be pulled from R. The pull method only supports R vectors which are numeric (i.e., integers or doubles) or character (i.e., strings). The R value of NA is pulled as nil into Ruby. Data in other formats must be coerced when copying to Ruby.
-
singletons: R represents a single number as a vector of length one, but in Ruby it is often more convenient to use a number rather than an array of length one. Setting singleton=false will cause the pull method to shed the array, while singletons=true will return the number of string within an array. The default is false.
The pull method is an alternative to the simplified form where the parameters are automatically used. For example:
>> puts R.test
is the same as:
>> puts R.pull("test")
407 408 409 410 411 |
# File 'lib/rinruby.rb', line 407 def pull(string, singletons=false) if_parseable(string){|fun| pull_engine("#{fun}()", singletons) } end |
#quit ⇒ Object
The quit method will properly close the bridge between Ruby and R, freeing up system resources. This method does not need to be run when a Ruby script ends.
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/rinruby.rb', line 182 def quit begin @writer.puts "q(save='no')" @writer.close rescue end @reader.close rescue nil @server_socket.close rescue nil true end |