Class: Rri::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/rri/engine.rb

Overview

The main class to interface with R

Engine internally holds an instance of the java class JRIEngine which is used for all interaction with R. On top of this it provides a few abstractions to easily convert between ruby and R types.

The main methods of the high level API are #eval_and_convert and #convert_and_assign. The high level API converts to/from R/ruby using a type conversion system described in the README.

It also provides a couple of helper methods just to make the users life easier when working with the lower level java API, most notably #simple_eval and #simple_assign. These functions do not convert values but instead work with references to R objects and are preferred when you don't really care about converting to/from ruby (e.g. intermediate steps of calculations and similar)

Apart from the methods on this ruby class the user can also use any other method on JRIEngine, it will be forwarded via #method_missing.

Constant Summary collapse

DEFAULT_ENGINE_OPTIONS =

Default options used when creating an engine

{
  :r_arguments => ["--no-save"],
  :callback_object => nil,
  :run_repl => false
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Engine

Create a new instance of Engine

Parameters:

  • options (Hash) (defaults to: {})

    A Hash of options to override the defaults, or not given in which case the defaults will be used.



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rri/engine.rb', line 119

def initialize(options = {})
  combined_options = DEFAULT_ENGINE_OPTIONS.merge(options)
  
  @engine = Jri::JRIEngine.new(combined_options[:r_arguments].to_java(:string),
                               combined_options[:callback_object],
                               combined_options[:run_repl])
                              
  # the R thread wont die unless we call #close on @engine, so make sure this
  # happens when this object is finalized.
  ObjectSpace.define_finalizer(self, self.class.finalize(@engine))
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Forward any method calls not recognized to JRIEngine



132
133
134
135
136
137
138
# File 'lib/rri/engine.rb', line 132

def method_missing(method, *args, &block)
  if @engine.respond_to? method
    @engine.send(method, *args, &block)
  else
    super
  end
end

Class Method Details

.add_r_converter(converter) ⇒ Array

Add a custom converter used to convert ruby objects to R objects

Parameters:

  • converter (#convert)

    the converter to add

Returns:

  • (Array)

    known (class level) converters



38
39
40
41
# File 'lib/rri/engine.rb', line 38

def self.add_r_converter(converter)
  @@r_converters ||= []
  @@r_converters << converter
end

.add_ruby_converter(converter) ⇒ Array

Add a custom converter used to convert R objects to ruby objects

Parameters:

  • converter (#convert)

    the converter to add

Returns:

  • (Array)

    known (class level) converters



75
76
77
78
# File 'lib/rri/engine.rb', line 75

def self.add_ruby_converter(converter)
  @@ruby_converters ||= []
  @@ruby_converters << converter
end

.clear_r_convertersObject

Clear all class level custom R converters



55
56
57
# File 'lib/rri/engine.rb', line 55

def self.clear_r_converters
  @@r_converters = []
end

.clear_ruby_convertersObject

Clear all class level custom ruby converters



92
93
94
# File 'lib/rri/engine.rb', line 92

def self.clear_ruby_converters
  @@ruby_converters = []
end

.default_r_convertersArray

Get default converters to convert ruby objects to R objects

Returns:

  • (Array)

    all default converters



62
63
64
65
66
67
68
69
# File 'lib/rri/engine.rb', line 62

def self.default_r_converters
  [
    RConverters::FloatConverter.new,
    RConverters::IntegerConverter.new,
    RConverters::StringConverter.new,
    RConverters::ArrayConverter.new
  ]
end

.default_ruby_convertersArray

Get default converters to convert R objects to ruby objects

Returns:

  • (Array)

    all default converters



99
100
101
102
103
104
105
# File 'lib/rri/engine.rb', line 99

def self.default_ruby_converters
  [
    RubyConverters::DoubleConverter.new,
    RubyConverters::IntegerConverter.new,
    #RubyConverters::StringConverter.new,
  ]
end

.finalize(engine) ⇒ Proc

Helper to make sure all engines are finalized so the R thread dies as it should

Parameters:

  • engine

    engine to finalize

Returns:

  • (Proc)

    that closes the engine



111
112
113
# File 'lib/rri/engine.rb', line 111

def self.finalize(engine)
  proc { engine.close }
end

.r_convertersArray

Get all class level custom converters to convert ruby objects to R objects

Converters are returned in the reversed order to how they were added (i.e. the last added is applied first)

Returns:

  • (Array)

    all class level custom converters



49
50
51
52
# File 'lib/rri/engine.rb', line 49

def self.r_converters
  @@r_converters ||= []
  @@r_converters.reverse
end

.ruby_convertersArray

Get all class level custom converters to convert R objects to ruby objects

Converters are returned in the reversed order to how they were added (i.e. the last added is applied first)

Returns:

  • (Array)

    all class level custom converters



86
87
88
89
# File 'lib/rri/engine.rb', line 86

def self.ruby_converters
  @@ruby_converters ||= []
  @@ruby_converters.reverse
end

Instance Method Details

#add_r_converter(converter) ⇒ Array

Add a custom converter used to convert ruby objects to R objects

Parameters:

  • converter (#convert)

    the converter to add

Returns:

  • (Array)

    known (instance level) converters



144
145
146
147
# File 'lib/rri/engine.rb', line 144

def add_r_converter(converter)
  @r_converters ||= []
  @r_converters << converter
end

#add_ruby_converter(converter) ⇒ Array

Add a custom converter used to convert R objects to ruby objects

Parameters:

  • converter (#convert)

    the converter to add

Returns:

  • (Array)

    known (instance level) converters



169
170
171
172
# File 'lib/rri/engine.rb', line 169

def add_ruby_converter(converter)
  @ruby_converters ||= []
  @ruby_converters << converter
end

#clear_r_convertersObject

Clear all instance level custom R converters



161
162
163
# File 'lib/rri/engine.rb', line 161

def clear_r_converters
  @r_converters = []
end

#clear_ruby_convertersObject

Clear all instance level custom R converters



175
176
177
# File 'lib/rri/engine.rb', line 175

def clear_ruby_converters
  @ruby_converters = []
end

#convert_and_assign(obj, symbol) ⇒ nil

Convert a ruby value to an R type and assign it to an R variable.

Parameters:

  • obj

    ruby object to convert and assign to R varible

  • symbol (#to_s)

    what to call the R variable

Returns:

  • (nil)

Raises:



227
228
229
230
231
# File 'lib/rri/engine.rb', line 227

def convert_and_assign(obj, symbol)
  success, rexp = convert_to_r_object(obj)
  raise RriException.new("Failed to convert ruby object to R object for: #{obj}") unless success
  simple_assign(symbol, rexp)
end

#convert_to_r_object(obj) ⇒ Array

Convert a ruby object to a R object

Applies converters in 3 levels:

  • custom converters that is set for only this engine instance
  • custom converters that are set for all engine instances
  • default converters

Converters are applied in the reverse order they were added in.

Parameters:

  • obj

    ruby object to convert

Returns:

  • (Array)

    an array of size 2 where first element is a boolean indicating succes, and the second element is the converted object if conversion successful (otherwise the original obj)



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/rri/engine.rb', line 269

def convert_to_r_object(obj)
  # first try converters defined for just this instance
  success, value = apply_local_r_converters(obj)
  return [success, value] if success

  # then try converters defined in general
  success, value = apply_r_converters(obj)
  return [success, value] if success

  # and finally apply the default converters   
  success, value = apply_default_r_converters(obj)
  return [success, value] if success

  # give up
  [false, obj]
end

#convert_to_ruby_object(rexp) ⇒ Array

Convert an R object to a ruby object

Applies converters in 3 levels:

  • custom converters that is set for only this engine instance
  • custom converters that are set for all engine instances
  • default converters

Converters are applied in the reverse order they were added in.

Parameters:

  • rexp (REXP)

    R object to convert

Returns:

  • (Array)

    an array of size 2 where first element is a boolean indicating succes, and the second element is the converted object if conversion was successful (otherwise the original rexp)



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/rri/engine.rb', line 299

def convert_to_ruby_object(rexp)
  # first try converters defined for just this instance
  success, value = apply_local_ruby_converters(rexp)
  return [success, value] if success

  # then try converters defined in general
  success, value = apply_ruby_converters(rexp)
  return [success, value] if success

  # and finally apply the default converters   
  success, value = apply_default_ruby_converters(rexp)
  return [success, value] if success

  # give up
  [false, rexp]
end

#eval_and_convert(expression) ⇒ Object

Eval expression and convert result to the corresponding ruby type

Parameters:

  • expression (String)

    the R epxression to evaluate

Returns:

  • the result converted to the corresponding ruby type

Raises:



206
207
208
209
210
# File 'lib/rri/engine.rb', line 206

def eval_and_convert(expression)
  success, value = convert_to_ruby_object(@engine.parseAndEval(expression))
  raise RriException.new("Failed to convert R object to ruby object for: #{value}") unless success
  value
end

#get_and_convert(symbol) ⇒ Object

Get a variable from R and convert it to a ruby object

Always uses the global environment.

Parameters:

  • symbol (#to_s)

    name of the R variable to get

Returns:

  • the R variable converted to a ruby object

Raises:



249
250
251
252
253
254
# File 'lib/rri/engine.rb', line 249

def get_and_convert(symbol)
  rexp = @engine.get(symbol.to_s, nil, true)
  success, value = convert_to_ruby_object(rexp)
  raise RriException.new("Failed to convert R object to ruby object for: #{value}") unless success
  value
end

#r_convertersArray

Get all instance level custom converters to convert ruby objects to R objects

Converters are returned in the reversed order to how they were added (i.e. the last added is applied first)

Returns:

  • (Array)

    all instance level custom converters



155
156
157
158
# File 'lib/rri/engine.rb', line 155

def r_converters
  @r_converters ||= []
  @r_converters.reverse
end

#ruby_convertersArray

Get all instance level custom converters to convert R objects to ruby objects

Converters are returned in the reversed order to how they were added (i.e. the last added is applied first)

Returns:

  • (Array)

    all instance level custom converters



185
186
187
188
# File 'lib/rri/engine.rb', line 185

def ruby_converters
  @ruby_converters ||= []
  @ruby_converters.reverse
end

#simple_assign(symbol, rexp) ⇒ nil

Helper method to assign expressions to R variables

Always uses the global environment.

Parameters:

  • symbol (#to_s)

    what to call the R variable

Returns:

  • (nil)


218
219
220
# File 'lib/rri/engine.rb', line 218

def simple_assign(symbol, rexp)
  @engine.assign(symbol.to_s, rexp, nil)
end

#simple_eval(expression) ⇒ REXPReference

Helper method to evaluate expressions but avoid any R-to-ruby conversions

Always uses the global environment and returns an R reference which the user can pass along to other R functions later on.

Parameters:

  • expression (String)

    the R expression to evaluate

Returns:

  • (REXPReference)

    reference to the result of the expression



197
198
199
200
# File 'lib/rri/engine.rb', line 197

def simple_eval(expression)
  parsed_expression = @engine.parse(expression, false)
  @engine.eval(parsed_expression, nil, false)
end

#simple_get(symbol) ⇒ REXPReference

Helper method to get a variable from R

Always uses the global environment.

Parameters:

  • symbol (#to_s)

    name of the R variable to get

Returns:

  • (REXPReference)

    reference to the R variable



239
240
241
# File 'lib/rri/engine.rb', line 239

def simple_get(symbol)
  @engine.get(symbol.to_s, nil, false)
end