※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

第4章 変換システム

4.1 R から Ruby へ

RSRuby は4つの異なった変換モデルを持っています。 各モードはどこでも利用できます。 (この場合、すべての関数に影響します。)そして、局所的に単体で機能します。(?)ローカルモードです。変換システムはたいていの場合、デフォルトモードで事足りますが、複雑な変換が必要な場合には、多くの方法でカスタマイズすることも可能です。

4.1.1 モード

異なるモードについて以下で詳しく述べますが、それぞれが RSRuby 名前空間で定義された特別な定数により指定されます。 (例えば RSRuby::PROC_CONVERSION)。定数は以下のとおりです。:

* PROC_CONVERSION
* CLASS_CONVERSION
* BASIC_CONVERSION
* VECTOR_CONVERSION
* NO_CONVERSION
* NO_DEFAULT

変換モードを操作するために、以下の機能が RSRuby クラスから利用可能です。:

get default mode(): デフォルトの(グローバル)モードを返します。
set default mode(m): 現在のデフォルトの(グローバル)モードを m に設定します。 m は上で定義されたうちの1つである必要があります。

RObjオブジェクトへの呼び出しの結果は、以下の規則にしたがって Rubyに変換されます:

1. デフォルトモードが NO_DEFAULT に設定される場合、現在のデフォルトモードが使われます。
2. もし、現在のデフォルトモードが NO_DEFAULT に設定されている場合、RObj のローカルモードが使われます。
3. もし、現在のデフォルトモードでどんな変換も出来ない場合、オブジェクトは次のモードに順々に設定します(順番は PROC_CONVERSION, CLASS_CONVERSION, BASIC_CONVERSION, VECTOR_CONVERSION, NO_CONVERSION)。 NO_CONVERSION は必ず成功し、返値を引き継いで  RObj を返します。

Proc Conversion これは、RSRuby オブジェクトに保存された proc_table ハッシュに置かれた関数に従って、R オブジェクトを変換するユーザカスタマイズ可能なモードです。このハッシュキーは単一引数を持つ Proc オブジェクトです。この単一引数は、変換されるオブジェクトの RObj 表現です。 Ruby のハッシュは順序を持たず、関数が評価される順番を定義出来ないことに注意してください。順序付きハッシュ (やタプルの配列)を使用する新しい実装が好まれるでしょう。 いったん Proc (hash key) が見つかると true を返し、(1つの引数を受け取った Proc の) 変換値は RObj を変換するのに使われます。 この Proc によって返された値は必要なRuby表現を返すべきです。 例により明確にします。

irb> r = RSRuby.instance
  => #<RSRuby:0xb7add6c4>
irb> check_str = lambda{|x| RSRuby.instance.is_character(x)}
  => #<Proc:0xb7ad6180@(irb):2>
irb> reverse = lambda{|x| x.to_ruby.reverse}
  => #<Proc:0xb7acbb2c@(irb):3>
irb> r.proc_table[check_str] = reverse
  => #<Proc:0xb7acbb2c@(irb):3>
irb> RSRuby.set_default_mode(RSRuby::PROC_CONVERSION)
  => 4
irb> r.paste("hello","world")
  => "dlrow olleh"
irb> r.sum(1,2,3)
  => 6

Proc をセットアップして, check_str, R 関数により返された文字列をチェックします。 もし reverse Proc が呼ばれたら。この単純な RObj から Ruby オブジェクトへの変換は、今回は文字列で to_ruby とその逆を使っています。(?)この変換はペーストを使って示されます。 文字列 (やその逆)、整数型を返した合計などは影響を受けません。(?) As with RPy, within the conversion routine the conversion mode is switched to basic to prevent infinite recursion. Since each key is tested this mode can be ineffcient if the proc table becomes large. It should also be noted that by using a single key that always returns true the RSRuby conversion system can be completely bypassed and a custom conversion system plugged in.

Class Conversion CLASS_CONVERSION モードは、Hash で作られた各オブジェクトのための適切な変換ルーチンを提供する PROC_CONVERSION モードのようなものです。今回の場合は class_table が提供されます。 この Hash のキーは文字列か文字列の配列です。 Hash の値は PROC_CONVERSION モードで使った Procs 変換です。 R によって返されたそれぞれのオブジェクトは class_table のキーに対してテストされます。要求どおりにオブジェクトにマッチするように次のうち1つを満たす必要があります。:

  • R 属性クラスは文字列で、 class_table に見つけられる。
  • R 属性クラスは文字列の vector 型で、class_table に見つけられる。
  • R 属性クラスは文字列のタプル型で、class_table に見つけらたタプル要素の1つです。

以下の例では、すべて Ruby の整数型 5 で返された「data.frame」 R オブジェクトです。:

irb> r = RSRuby.instance
  => #<RSRuby:0xb7ae7224>
irb> RSRuby.set_default_mode(RSRuby::CLASS_CONVERSION)
  => 3
irb> conversion = Proc.new{|x| 5}
  => #<Proc:0xb7adde04@(irb):3>
irb> r.class_table[’data.frame’] = conversion
  => #<Proc:0xb7adde04@(irb):3>
irb> r.as_data_frame([1,2,3])
  => 5

Basic Conversion BASIC_CONVERSION mode attempts to convert the R object into a basic (by which I mean standard library) Ruby type. R types are generally not perfectly matched by basic Ruby types so some data might be lost in this conversion. If this is not desired by the user then the custom conversion modes (see above) should be used. Table 4.1 shows the conversion rules:

R object Ruby Class Notes NULL nil Logical TrueClass or FalseClass a,b Integer Integer (Fixnum or Bignum) a,b Real Float a,c Complex Complex a String String a Vector Array or Hash a,d List Array or Hash a,d Array Array d Other Fails a In R there are no true scalar types. All values are vectors, with scalars represented as vectors with length one. This can be confusing for Ruby programmers and so vectors of length one are converted to Ruby scalars while vectors of length more than one are returned as Arrays. b In R there is ’NA’ (not applicable) which is converted to Ruby as the lowest possible Fixnum in Ruby (which is system dependant). c The IEEE float values NaN and Inf are also converted to and from R and Ruby. d Vectors and lists in R can have a name attribute. If this attribute is set then the vector/list is converted to a Ruby Hash. When there is no name attribute a Ruby Array is returned. Note that Hashes do not retain any order information.

Table 4.1: R と Ruby in RSRuby の基本モードの変換例


Vector Conversion

VECTOR_CONVERSION モードは exactly the same as BASIC_MODE except that it always returns a Ruby Hash or Array no matter what the length of the returned R vector.


No Conversion

最終的な変換モードは NO_CONVERSION if all attempts at 前のモードが失敗したとき then they fall through to this mode which returns an RObj (R オブジェクトへの参照)を返すこのモードになったとき。 このモードは必ず成功します。

4.2 Ruby から R へ

Converting from Ruby to R is more straightforward. When a Ruby object is passed to an R function, the following steps are attempted until one succeeds: 1. If the Ruby object defines a as_r method then the result of that method is converted to R. If you have custom classes that you wish to be able to pass to R then this is the method you must define. 2. If the Ruby object is of class RObj then it is converted into the R object it represents. 3. The Ruby object is converted according to Table 4.1. 4. An ArgumentError exception is thrown giving the message ’Unsupported object passed to R’.