Module: R
- Defined in:
- lib/R_interface/rlist.rb,
lib/R_interface/r.rb,
lib/R_interface/rpkg.rb,
lib/R_interface/r_arrow.rb,
lib/R_interface/rdevice.rb,
lib/R_interface/rmatrix.rb,
lib/R_interface/robject.rb,
lib/R_interface/rsymbol.rb,
lib/R_interface/rvector.rb,
lib/R_interface/rclosure.rb,
lib/R_interface/rsupport.rb,
lib/R_interface/r_methods.rb,
lib/R_interface/rlanguage.rb,
lib/R_interface/r_module_s.rb,
lib/R_interface/rdata_frame.rb,
lib/R_interface/rexpression.rb,
lib/R_interface/renvironment.rb,
lib/R_interface/ruby_callback.rb,
lib/R_interface/rsupport_scope.rb,
lib/R_interface/rindexed_object.rb,
lib/R_interface/ruby_extensions.rb,
lib/R_interface/ruby_extensions.rb,
lib/R_interface/ruby_extensions.rb,
lib/R_interface/runary_operators.rb,
lib/R_interface/rbinary_operators.rb,
lib/R_interface/new_bridge_adapter.rb,
lib/R_interface/rlogical_operators.rb,
lib/R_interface/rmd_indexed_object.rb
Overview
Copyright © 2018 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify, and distribute this software and its documentation, without fee and without a signed licensing agreement, is hereby granted, provided that the above copyright notice, this paragraph and the following two paragraphs appear in all copies, modifications, and distributions.
IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Defined Under Namespace
Modules: Arrow, Async, BinaryOperators, CallBinOp, ExecBinOp, ExecUniOp, ExpBinOp, ExpUniOp, IndexedObject, LogicalOperators, MDIndexedObject, S, Scope, Support, UnaryOperators Classes: BatchEvaluationError, Closure, DataFrame, Device, Environment, Language, List, Matrix, NewBridgeAdapter, NotAvailable, NullCheckResult, Object, Package, RExpression, RSymbol, RubyCallback, SymbolRef, UnboxDepthError, Vector
Constant Summary collapse
- RCONSTANTS =
["LETTERS", "letters", "month.abb", "month.name", "pi"]
- NA =
NotAvailable.new
- NULL_IS_NULL =
NullCheckResult.new(true).freeze
- NULL_IS_FALSE =
NullCheckResult.new(false).freeze
Class Method Summary collapse
- .[](name) ⇒ Object
-
.batch {|col| ... } ⇒ Object
Queue several eval_r_with_result assignments and send them in one bridge round-trip.
-
.bridge ⇒ Object
R↔Ruby bridge: NewBridge only.
-
.call2(fn, *args, **kwargs) ⇒ Object
Build a call object with rlang::call2().
-
.const_missing(name) ⇒ Object
----------------------------------------------------------------------------------------.
- .empty_symbol ⇒ Object
-
.ensure_rlang! ⇒ Object
-------------------------------------------------------------------------- rlang helpers (reintroduced legacy API surface) --------------------------------------------------------------------------.
-
.eval_r_async(code, timeout: nil, &block) ⇒ Object
Async string eval against R;
blockreceivesNewBridge::EvalResult(+#value+ matcheseval_ron success). -
.exec(fn, *args, **kwargs) ⇒ Object
Execute a function call with dynamic args via rlang::exec().
-
.expr(arg) ⇒ Object
Build an R expression/symbol using rlang::expr().
-
.install_and_loads(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) ⇒ Object
----------------------------------------------------------------------------------------.
- .install_rlibs(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) ⇒ Object
-
.internal_eval(symbol, *args) ⇒ Object
----------------------------------------------------------------------------------------.
-
.method_missing(symbol, *args, &block) ⇒ Object
---------------------------------------------------------------------------------------- Executes a missing method.
-
.with_callback_timeout_ms(callback_timeout_ms) ⇒ Object
---------------------------------------------------------------------------------------- Checks to see if the given libs are installed in R and if not, install them install ----------------------------------------------------------------------------------------.
Class Method Details
.[](name) ⇒ Object
45 46 47 |
# File 'lib/R_interface/r.rb', line 45 def self.[](name) R::SymbolRef.new(name) end |
.batch {|col| ... } ⇒ Object
Queue several eval_r_with_result assignments and send them in one bridge round-trip.
Fail-fast: on the first R error, remaining queued ops are not run (+R::BatchEvaluationError+,
#failed_index is 0-based). Same outcomes as sequential eval_r_with_result when all succeed.
94 95 96 97 98 99 100 |
# File 'lib/R_interface/r.rb', line 94 def self.batch col = R::Support::BatchCollector.new yield col raise ArgumentError, 'R.batch requires at least one eval_with_result assignment' if col.ops.empty? R::Support.batch_eval_with_result(col.ops) end |
.bridge ⇒ Object
R↔Ruby bridge: NewBridge only.
60 61 62 63 |
# File 'lib/R_interface/r.rb', line 60 def self.bridge require_relative 'new_bridge_adapter' R::NewBridgeAdapter.instance end |
.call2(fn, *args, **kwargs) ⇒ Object
Build a call object with rlang::call2().
230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/R_interface/r.rb', line 230 def self.call2(fn, *args, **kwargs) ensure_rlang! var_name = R::Support.generate_var_name parts = [R::Support.parse_arg(fn)] parts.concat(args.map { |a| R::Support.parse_arg(a) }) unless args.empty? unless kwargs.empty? kw = kwargs.map { |k, v| "#{k.to_s.gsub(/__/, ".")} = #{R::Support.parse_arg(v)}" } parts.concat(kw) end R.bridge.eval_r("#{var_name} <- rlang::call2(#{parts.join(', ')})") R::Object.build(var_name) end |
.const_missing(name) ⇒ Object
57 58 59 |
# File 'lib/R_interface/rpkg.rb', line 57 def self.const_missing(name) R::Package[name.to_s.downcase] end |
.empty_symbol ⇒ Object
12 13 14 |
# File 'lib/R_interface/rsupport.rb', line 12 def self.empty_symbol "" end |
.ensure_rlang! ⇒ Object
rlang helpers (reintroduced legacy API surface)
213 214 215 216 217 218 |
# File 'lib/R_interface/r.rb', line 213 def self.ensure_rlang! ok = R::Support.eval("requireNamespace('rlang', quietly=TRUE)") return if ok == true raise "R package 'rlang' is required for this API. Install with: Rscript -e \"install.packages('rlang', repos='https://cloud.r-project.org/')\"" end |
.eval_r_async(code, timeout: nil, &block) ⇒ Object
Async string eval against R; block receives NewBridge::EvalResult (+#value+ matches eval_r on success).
103 104 105 |
# File 'lib/R_interface/r.rb', line 103 def self.eval_r_async(code, timeout: nil, &block) R.bridge.eval_r_async(code, timeout: timeout, &block) end |
.exec(fn, *args, **kwargs) ⇒ Object
Execute a function call with dynamic args via rlang::exec().
244 245 246 247 |
# File 'lib/R_interface/r.rb', line 244 def self.exec(fn, *args, **kwargs) ensure_rlang! R.rlang___exec(fn, *args, **kwargs) end |
.expr(arg) ⇒ Object
Build an R expression/symbol using rlang::expr().
221 222 223 224 225 226 227 |
# File 'lib/R_interface/r.rb', line 221 def self.expr(arg) ensure_rlang! var_name = R::Support.generate_var_name parsed = R::Support.parse_arg(arg) R.bridge.eval_r("#{var_name} <- rlang::expr(#{parsed})") R::Object.build(var_name) end |
.install_and_loads(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) ⇒ Object
203 204 205 206 207 |
# File 'lib/R_interface/r.rb', line 203 def self.install_and_loads(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) R.install_rlibs(*libs, install_timeout_sec: install_timeout_sec, callback_timeout_ms: callback_timeout_ms, bridge_timeout_sec: bridge_timeout_sec) # Use library() so load failures throw immediately with a clear R error libs.each { |lib| R.library(lib) } end |
.install_rlibs(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) ⇒ Object
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 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/R_interface/r.rb', line 135 def self.install_rlibs(*libs, install_timeout_sec: nil, callback_timeout_ms: nil, bridge_timeout_sec: nil) with_callback_timeout_ms(callback_timeout_ms) do # Use a fixed local library directory and ensure R can see it lib_dir = File.("~/R/x86_64-pc-linux-gnu-library/galaaz") FileUtils.mkdir_p(lib_dir) unless Dir.exist?(lib_dir) R.bridge.eval_r(".libPaths(c('#{lib_dir.gsub("'", "\\\\'")}', .libPaths()))", timeout: bridge_timeout_sec) packages = R.c(*libs) # installed.packages() returns a matrix; package names are in the row names. # Using [:all, "Package"] on this matrix ends up calling [[ with a missing # row subscript in R, which raises "missing subscript". Instead, rely on # the row names vector for the list of installed packages. installed_mat = R.installed__packages(nil) installed_names = R.rownames(installed_mat) new_packages = packages[!(packages._ :in, installed_names)] new_packages_str = new_packages.to_s if(new_packages.length > 0 && new_packages_str != "character(0)") $stderr.puts "[RUBY] The following packages are missing and will be installed: #{new_packages_str}" $stderr.puts "[RUBY] Installing to: #{lib_dir}" # Get packages as Ruby array using :native mode pkg_list = [] new_packages.each(:native) { |pkg| pkg_list << pkg } $stderr.puts "[RUBY] Package list: #{pkg_list.inspect}" # Install each package pkg_list.each do |pkg| $stderr.puts "[RUBY] Installing #{pkg}..." if install_timeout_sec timeout_i = Integer(install_timeout_sec) R.bridge.eval_r("options(timeout=#{timeout_i})", timeout: bridge_timeout_sec) end r_cmd = "install.packages('#{pkg.gsub("'", "\\\\'")}', repos='https://cloud.r-project.org', lib='#{lib_dir.gsub("'", "\\\\'")}', dependencies=NA)" $stderr.puts "[RUBY] R command: #{r_cmd}" result = R.bridge.eval_r(r_cmd, timeout: bridge_timeout_sec) $stderr.puts "[RUBY] Install output: #{result.inspect}" if result.to_s.include?("ANTICONF") || result.to_s.include?("Configuration failed") $stderr.puts "[RUBY] WARNING: Package #{pkg} failed to install due to missing system libraries." $stderr.puts "[RUBY] For kableExtra, you may need: libfontconfig1-dev libxml2-dev libfreetype6-dev" end ensure begin R.bridge.eval_r("options(timeout=60)", timeout: bridge_timeout_sec) rescue StandardError nil end end # Re-check installed packages after install attempt installed_mat = R.installed__packages(nil) installed_names = R.rownames(installed_mat) still_missing = packages[!(packages._ :in, installed_names)] if still_missing.length > 0 raise "Failed to install packages: #{still_missing.to_s}. Check stderr output above for [RUBY] debug messages." end end end end |
.internal_eval(symbol, *args) ⇒ Object
87 88 89 |
# File 'lib/R_interface/r.rb', line 87 def self.internal_eval(symbol, *args) R::Support.process_missing(symbol, true, *args) end |
.method_missing(symbol, *args, &block) ⇒ Object
Executes a missing method. If a block is given, then the method needs to be executed in the scope of the block. @bug: Not ready yeat
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/R_interface/r.rb', line 72 def self.method_missing(symbol, *args, &block) if (block_given?) val = R::Support.process_missing(symbol, false, *args) return R::Support.new_scope(symbol, val, *args, &block) end R::Support.process_missing(symbol, false, *args) end |
.with_callback_timeout_ms(callback_timeout_ms) ⇒ Object
Checks to see if the given libs are installed in R and if not, install them install
125 126 127 128 129 130 131 132 133 |
# File 'lib/R_interface/r.rb', line 125 def self.with_callback_timeout_ms(callback_timeout_ms) return yield if callback_timeout_ms.nil? old = ENV['GALAAZ_CALLBACK_TIMEOUT_MS'] ENV['GALAAZ_CALLBACK_TIMEOUT_MS'] = Integer(callback_timeout_ms).to_s yield ensure ENV['GALAAZ_CALLBACK_TIMEOUT_MS'] = old unless callback_timeout_ms.nil? end |