Class: Rserve::REXP

Inherits:
Object
  • Object
show all
Defined in:
lib/rserve/rexp.rb,
lib/rserve/rexp/s4.rb,
lib/rserve/rexp/raw.rb,
lib/rserve/rexp/list.rb,
lib/rserve/rexp/null.rb,
lib/rserve/rexp/double.rb,
lib/rserve/rexp/factor.rb,
lib/rserve/rexp/string.rb,
lib/rserve/rexp/symbol.rb,
lib/rserve/rexp/vector.rb,
lib/rserve/rexp/integer.rb,
lib/rserve/rexp/logical.rb,
lib/rserve/rexp/unknown.rb,
lib/rserve/rexp/wrapper.rb,
lib/rserve/rexp/function.rb,
lib/rserve/rexp/language.rb,
lib/rserve/rexp/reference.rb,
lib/rserve/rexp/environment.rb,
lib/rserve/rexp/genericvector.rb,
lib/rserve/rexp/expressionvector.rb

Overview

Basic class representing an object of any type in R. Each type in R in represented by a specific subclass. This class defines basic accessor methods (as_xxx), type check methods (XXX?), gives access to attributes (REXP.get_attribute, REXP.has_attribute?) as well as several convenience methods. If a given method is not applicable to a particular type, it will throw the MismatchError exception.

This root class will throw on any accessor call and returns false for all type methods. This allows subclasses to override accessor and type methods selectively.

Direct Known Subclasses

Environment, Function, Null, Reference, S4, Unknown, Vector

Defined Under Namespace

Modules: Wrapper Classes: Double, Environment, ExpressionVector, Factor, Function, GenericVector, Integer, Language, List, Logical, Null, Raw, Reference, S4, String, Symbol, Unknown, Vector

Constant Summary collapse

MismatchError =
Class.new(StandardError)
MaxDebugItems =

specifies how many items of a vector or list will be displayed in #toDebugString

32

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attr = nil) ⇒ REXP

Returns a new instance of REXP.

Raises:

  • (ArgumentError)

10
11
12
13
14
# File 'lib/rserve/rexp.rb', line 10

def initialize(attr=nil)
  # Sorry for this, but I think is necessary to maintain sanity of attributes
  raise ArgumentError, "Attribute should be a REXP::List, #{attr.class} provided" unless attr.nil? or attr.is_a? REXP::List
  @attr=attr
end

Instance Attribute Details

#attrObject (readonly)

Returns the value of attribute attr


9
10
11
# File 'lib/rserve/rexp.rb', line 9

def attr
  @attr
end

Class Method Details

.create_data_frame(l) ⇒ Object

creates a data frame object from a list object using integer row names.

  • @param [Rlist] a (named) list of vectors (REXP::Vector subclasses), each element corresponds to a column and all elements must have the same length.

  • @return [GenericVector] a data frame object representation.

Raises:


368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# File 'lib/rserve/rexp.rb', line 368

def self.create_data_frame(l)
  raise(MismatchError, "data frame (must have dim>0)") if l.nil? or l.size<1
  raise MismatchError, "data frame (contents must be vectors)" if (!(l[0].is_a? REXP::Vector))
  fe = l[0]
  return REXP::GenericVector.new(l,
  REXP::List.new(
  Rlist.new(
  [
  REXP::String.new("data.frame"),
  REXP::String.new(l.keys()),
  REXP::Integer.new([REXP::Integer::NA, -fe.length()])
  ],
  ["class", "names", "row.names" ])
  )
  )
end

Instance Method Details

#as_bytesArray

returns the contents as an array of bytes (if supported by the represented object).

Returns:

  • (Array)

Raises:


157
158
159
# File 'lib/rserve/rexp.rb', line 157

def as_bytes
  raise MismatchError , "byte"
end

#as_doubleFloat

convenience method corresponding to as_floats[0].

Returns:

  • (Float)

    first entry returned by as_doubles()


207
208
209
# File 'lib/rserve/rexp.rb', line 207

def as_double
  as_doubles[0]
end

#as_double_matrixArray

returns the content of the REXP as a ruby matrix of doubles (2D-array: m[cols]). You could use Matrix.rows(result) to create a ruby matrix. Matrix(c.eval(“matrix(c(1,2,3,4,5,6),2,3)”).as_double_matrix());</code>

Returns:

  • (Array)

    2D array of doubles in the form double[cols] or nil if the contents is no 2-dimensional matrix of doubles

Raises:


297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/rserve/rexp.rb', line 297

def as_double_matrix
  ct = as_doubles()
  dim = get_attribute "dim"
  raise MismatchError, "matrix (dim attribute missing)" if dim.nil?
  ds = dim.as_integers
  raise MismatchError, "matrix (wrong dimensionality)"     if (ds.length!=2)
  as_nested_array
  
  #m,n = ds[0], ds[1]
  # R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4)
  # we need to copy everything, since we create 2d array from 1d array
  #r=m.times.map {|i| n.times.map {|j| ct[j*n+i]}}
end

#as_doublesArray

returns the contents as an array of floats (C double precision) (if supported by the represented object).

Returns:

  • (Array)

Raises:


142
143
144
# File 'lib/rserve/rexp.rb', line 142

def as_doubles
   raise MismatchError,"double"
end

#as_factorRFactor

returns the contents as a factor (if supported by the represented object).

Returns:

Raises:


169
170
171
# File 'lib/rserve/rexp.rb', line 169

def as_factor
  raise MismatchError,"factor"
end

#as_floatFloat

Alias for as_double()

Returns:

  • (Float)

213
214
215
# File 'lib/rserve/rexp.rb', line 213

def as_float
  as_double
end

#as_floatsArray

On Ruby, Float are stored in double precision.

Returns:

  • (Array)

149
150
151
# File 'lib/rserve/rexp.rb', line 149

def as_floats
  as_doubles
end

#as_integerInteger

convenience method corresponding to as_integer()[0]

Returns:

  • (Integer)

    first entry returned by as_integers()


194
195
196
# File 'lib/rserve/rexp.rb', line 194

def as_integer
  as_integers[0]
end

#as_integersArray

returns the contents as an array of integers (if supported by the represented object)

Returns:

  • (Array)

Raises:


134
135
136
# File 'lib/rserve/rexp.rb', line 134

def as_integers
  raise MismatchError, "int"
end

#as_listArray

returns the contents as a (named) list (if supported by the represented object)

Returns:

  • (Array)

Raises:


163
164
165
# File 'lib/rserve/rexp.rb', line 163

def as_list
  raise MismatchError,"list"
end

#as_matrixMatrix

Returns a standard library's matrix.

Returns:

  • (Matrix)

313
314
315
316
# File 'lib/rserve/rexp.rb', line 313

def as_matrix
  require 'matrix'
  Matrix.rows(as_double_matrix)
end

#as_nested_arrayArray

Returns the content of the REXP as a serie of nested arrays of X dimensions

Returns:

  • (Array)

Raises:


320
321
322
323
324
325
326
# File 'lib/rserve/rexp.rb', line 320

def as_nested_array
  ct=as_doubles
  dim = get_attribute "dim"
  raise MismatchError, "array (dim attribute missing" if dim.nil?
  ds = dim.as_integers.reverse
  split_array(ct,ds)
end

#as_stringString

convenience method corresponding to as_strings[0].

Returns:

  • (String)

    first entry returned by REXP.as_strings


225
226
227
# File 'lib/rserve/rexp.rb', line 225

def as_string
  as_strings[0]
end

#as_stringsArray

returns the contents as an array of Strings (if supported by the represented object).

Returns:

  • (Array)

Raises:


127
128
129
# File 'lib/rserve/rexp.rb', line 127

def as_strings
  raise MismatchError, "String"
end

#complex?boolean

check whether the REXP object is a complex vector

Returns:

  • (boolean)

    true if the receiver is a complex vector, false otherwise


108
109
110
# File 'lib/rserve/rexp.rb', line 108

def complex?
  false
end

#dimObject

Returns dimensions of the object (as determined by the REXP::dim() attribute).

@return [Array] an array of integers with corresponding dimensions or <code>nil</code> if the object has no dimension attribute

254
255
256
257
258
259
260
261
# File 'lib/rserve/rexp.rb', line 254

def dim
  begin
    return has_attribute?("dim") ? @attr.as_list['dim'].as_integers :  nil;
    rescue MismatchError
  # nothing to do
  end
  nil
end

#environment?boolean

check whether the REXP object is an environment.

Returns:

  • (boolean)

    true if the receiver is an environment, false otherwise


74
75
76
# File 'lib/rserve/rexp.rb', line 74

def environment?
  false
end

#expression?boolean

check whether the REXP object is an expression vector.

Returns:

  • (boolean)

    true if the receiver is an expression vector, false otherwise


86
87
88
# File 'lib/rserve/rexp.rb', line 86

def expression?
  false
end

#factor?boolean

check whether the REXP object is a factor.

Returns:

  • (boolean)

    true if the receiver is a factor, false otherwise


49
50
51
# File 'lib/rserve/rexp.rb', line 49

def factor?
  false
end

#get_attribute(name) ⇒ Rlist?

Retrieve an attribute of the given name from this object.

Parameters:

  • attribute (String)

    name.

Returns:

  • (Rlist, nil)

    attribute value or nil if the attribute does not exist


236
237
238
# File 'lib/rserve/rexp.rb', line 236

def get_attribute(name)
  has_attribute?(name)  ? @attr.as_list[name] : nil
end

#has_attribute?(name) ⇒ boolean

checks whether this object has a given attribute.

Parameters:

  • attribute (String)

    name.

Returns:

  • (boolean)

    true if the attribute exists, false otherwise


244
245
246
# File 'lib/rserve/rexp.rb', line 244

def has_attribute? (name)
  !@attr.nil? and @attr.list? and !@attr.as_list[name].nil?
end

#inherits?(klass) ⇒ boolean

determines whether this object inherits from a given class in the same fashion as the inherits() function in R does (i.e. ignoring S4 inheritance).

Parameters:

  • klass (String)

    class name.

Returns:

  • (boolean)

    true if this object is of the class klass, false otherwise.


267
268
269
270
271
272
273
274
275
276
277
# File 'lib/rserve/rexp.rb', line 267

def inherits?(klass)
  return false if (!has_attribute? "class")
  begin
    c = get_attribute("class").as_strings;
    if (!c.nil?)
      return c.any? {|v| v.equals klass}
    end
  rescue MismatchError
  end
  false
end

#integer?boolean

check whether the REXP object is an integer vector.

Returns:

  • (boolean)

    true if the receiver is an integer vector, false otherwise


36
37
38
# File 'lib/rserve/rexp.rb', line 36

def integer?
  false
end

#language?boolean

check whether the REXP object is a language object.

Returns:

  • (boolean)

    true if the receiver is a language object, false otherwise


80
81
82
# File 'lib/rserve/rexp.rb', line 80

def language?
  false
end

#lengthInteger

returns the length of a vector object. Note that we use R semantics here, i.e. a matrix will have a length of m * n since it is represented by a single vector (see REXP.dim) for retrieving matrix and multidimentional-array dimensions).

Returns:

  • (Integer)

    length (number of elements) in a vector object.

Raises:


176
177
178
# File 'lib/rserve/rexp.rb', line 176

def length
  raise MismatchError, "vector"
end

#list?boolean

check whether the REXP object is a list (either generic vector or a pairlist - i.e. REXP.asList() will succeed).

Returns:

  • (boolean)

    true if the receiver is a generic vector or a pair-list, false otherwise


56
57
58
# File 'lib/rserve/rexp.rb', line 56

def list?
  false
end

#logical?boolean

check whether the REXP object is a logical vector.

Returns:

  • (boolean)

    true if the receiver is a logical vector, false otherwise */


68
69
70
# File 'lib/rserve/rexp.rb', line 68

def logical?
  false
end

#na?boolean

returns a boolean vector of the same length as this vector with true for NA values and false for any other values.

Returns:

  • (boolean)

    a boolean vector of the same length as this vector with true for NA values and false for any other values.

Raises:


184
185
186
# File 'lib/rserve/rexp.rb', line 184

def na?
  raise MismatchError, "vector"
end

#null?boolean

check whether the REXP object is NULL.

Returns:

  • (boolean)

    true if the receiver is NULL, false otherwise


42
43
44
# File 'lib/rserve/rexp.rb', line 42

def null?
  false
end

#numeric?boolean

check whether the REXP object is a numeric vector.

Returns:

  • (boolean)

    true if the receiver is a numeric vector, false otherwise


30
31
32
# File 'lib/rserve/rexp.rb', line 30

def numeric?
  false
end

#pair_list?boolean

check whether the REXP object is a pair-list.

Returns:

  • (boolean)

    true if the receiver is a pair-list, false otherwise


62
63
64
# File 'lib/rserve/rexp.rb', line 62

def pair_list?
  false
end

#raw?boolean

check whether the REXP object is a raw vector

Returns:

  • (boolean)

    true if the receiver is a raw vector, false otherwise


103
104
105
# File 'lib/rserve/rexp.rb', line 103

def raw?
  false
end

#recursive?boolean

check whether the REXP object is a recursive obejct

Returns:

  • (boolean)

    true if the receiver is a recursive object, false otherwise


113
114
115
# File 'lib/rserve/rexp.rb', line 113

def recursive?
  false
end

#reference?boolean

check whether the REXP object is a reference to an R object

Returns:

  • (boolean)

    true if the receiver is a reference, false otherwise


118
119
120
# File 'lib/rserve/rexp.rb', line 118

def reference?
  false
end

#split_array(ar, dims) ⇒ Object

:nodoc:


328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/rserve/rexp.rb', line 328

def split_array(ar, dims) # :nodoc:
  #puts "#{ar} - #{dims}"
  if dims.size==1
    raise "Improper size ar:#{ar} , dims=#{dims[0]}" if ar.size!=dims[0]
    return ar 
  elsif dims.size==2
    return Array.new() if dims.any? {|v| v==0}
    dims.reverse!
    # should rearrange values as R do
    # dims[0]=cols, dims[1]=rows
    if(true)
    out=[]
    ar.each_with_index {|v,i| 
      r=(i/dims[0]).to_i;
      c=i%dims[0];
      #p "#{r} : #{c}";
      out[c*dims[1]+r]=v
    }
    #p out
    
    raise "out size should equal to ar size" if ar.size!=out.size
    ar=out
    end
  end
  dims_c=dims.dup
  current_dim=dims_c.shift
  current_size=ar.size/current_dim
  #puts "dims: #{dims_c} cs:#{current_size}, cd:#{current_dim}"
  parts=current_dim.times.map do |i|
    split_array(ar[i*current_size, current_size], dims_c)
  end
  parts
end

#string?boolean

check whether the REXP object is a character vector (string).

Returns:

  • (boolean)

    true if the receiver is a character vector, false otherwise


22
23
24
# File 'lib/rserve/rexp.rb', line 22

def string?
  false
end

#symbol?boolean

check whether the REXP object is a symbol.

Returns:

  • (boolean)

    true if the receiver is a symbol, false otherwise


92
93
94
# File 'lib/rserve/rexp.rb', line 92

def symbol?
  false
end

#to_debug_stringString

returns representation that it useful for debugging (e.g. it includes attributes and may include vector values)

Returns:

  • (String)

    extended description of the obejct – it may include vector values


284
285
286
# File 'lib/rserve/rexp.rb', line 284

def to_debug_string
  (!@attr.nil?) ? (("<"+@attr.to_debug_string()+">")+to_s()) : to_s
end

#to_fFloat

Alias for as_float()

Returns:

  • (Float)

219
220
221
# File 'lib/rserve/rexp.rb', line 219

def to_f
  as_double
end

#to_iInteger

Alias for as_integer().

Returns:


201
202
203
# File 'lib/rserve/rexp.rb', line 201

def to_i
  as_integers[0]
end

#to_rubyObject

Retrieves the best Ruby representation of data

If R object has attributes, the Ruby object is extended with Rserve::WithAttributes. If R object have names, the Ruby object is extended with Rserve::WithNames and their elements can be accessed with [] using numbers and literals.

Returns:

  • (Object)

    Ruby object.


390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/rserve/rexp.rb', line 390

def to_ruby
  v=to_ruby_internal
  if !v.nil? and !v.is_a? Numeric and !v.is_a? TrueClass and !v.is_a? FalseClass
    v.extend Rserve::WithAttributes
    v.attributes=attr.to_ruby unless attr.nil?
    if !v.attributes.nil? and v.attributes.has_name? 'names'
      v.attributes['names']=[v.attributes['names']] unless v.attributes['names'].is_a? Array or v.attributes['names'].nil?
      v.extend Rserve::WithNames
      v.names=v.attributes['names']
    end
    if v.attributes and v.attributes.has_name? 'dim' and v.attributes.has_name? 'dimnames' and v.attributes['dim'].size == 2
      if v.is_a? Array
        v.extend Rserve::With2DSizes
        v.sizes = v.attributes['dim']
      end
      v.extend Rserve::With2DNames
      v.names = v.attributes['dimnames'].map{|dimension_names| (dimension_names.nil? or dimension_names.is_a?(Array)) ? dimension_names : [dimension_names]}
    end
  end
  
  # Hack: change attribute row.names according to spec 
  if !attr.nil? and attr.as_list.has_name? 'class' and attr.as_list['class'].as_string=='data.frame' and (attr.as_list['row.names'].is_a?(REXP::Integer)) and attr.as_list['row.names'].as_integers[0]==REXP::Integer::NA
    v.attributes['row.names']=(1..(-attr.as_list['row.names'].as_integers[1])).to_a
  end
  
  v
end

#to_ruby_internalObject

Return the bare-bone representation of REXP as a Ruby Object. Called by REXP.to_ruby, so shouldn't be used directly by developers.


420
421
422
# File 'lib/rserve/rexp.rb', line 420

def to_ruby_internal
  raise "You should implement to_ruby_internal for #{self.class}"
end

#vector?boolean

check whether the REXP object is a vector.

Returns:

  • (boolean)

    true if the receiver is a vector, false otherwise


98
99
100
# File 'lib/rserve/rexp.rb', line 98

def vector?
  false
end