要するに(実際の質問)
または(実際のソースファイルを調査するのではなく、ソースされた後)によって返されたオブジェクトからS4参照クラス(を参照)を定義する実際のソースコード/式にアクセスするにはどうすればよいですか??setRefClass
getClass("MyClass")
getRefClass("MyClass")
私がした宿題
すべてがRのオブジェクトなので、ソースコード/式を取得できます。
1)それぞれのオブジェクトを調査するだけの通常の機能:
foo <- function(x) print(x)
> foo
function(x) print(x)
2)特定のメソッドのメソッドオブジェクトを次の方法で取得することによる形式手法selectMethod
:
setGeneric(name="myMethod", signature=c("x"),
def=function(x) standardGeneric("myMethod")
)
setMethod(
f="myMethod",
signature=signature(x="numeric"),
definition=function(x) print(x)
)
def <- selectMethod(f="myMethod", signature=c(x="numeric"))
# Get actual source code/expression
> attributes(def)$srcref
function(x) print(x)
ただし、S4リファレンスクラスでは状況が異なるようです。
setRefClass(Class="MyClass", fields=list(x.1="character"))
def <- getRefClass("MyClass")
# Inspect object >> no expression
> def
Generator object for class "MyClass":
Class fields:
Name: x.1
Class: character
Class Methods:
"callSuper", "copy", "export", "field", "getClass", "getRefClass", "import",
"initFields", "show", "trace", "untrace"
Reference Superclasses:
"envRefClass"
def.temp <- attributes(attributes(def)$.xData$def)
# Inspect attributes >> no expression
> attributes(def.temp)
$names
[1] "fieldClasses" "fieldPrototypes" "refMethods" "refSuperClasses"
[5] "slots" "contains" "virtual" "prototype"
[9] "validity" "access" "className" "package"
[13] "subclasses" "versionKey" "sealed" "class"
# Alternatively:
> names(attributes(getClass("MyClass")))
[1] "fieldClasses" "fieldPrototypes" "refMethods" "refSuperClasses"
[5] "slots" "contains" "virtual" "prototype"
[9] "validity" "access" "className" "package"
[13] "subclasses" "versionKey" "sealed" "class"
クラスを正確に定義する実際のソースコード/式が格納されている属性が見つからないようです。
念のために言っておきますが、この式は私がアクセスしたいものです
setRefClass(Class="MyClass", fields=list(x.1="character"))
背景/動機
私はS4参照クラス( )をよく使用するため、クラスの継承?setRefClass
などのOOPの側面が日常業務で大きな役割を果たします。また、整理された状態を維持するために「ファイルごとに1つの定義」パラダイムに従います。そのため、さまざまなクラス定義は、ファイル名がそれぞれのクラスの名前に対応する個別のファイルに格納されます。
人生のすべてと同様に、いくつかの利点がありますが、そのようなアプローチにはいくつかの固有の欠点もあります。
アスペクト1
短期間でも長期間でも、個々のソースファイルのアルファベット順のファイル順序と一致しない継承構造になってしまいます。したがって、ファイルを次々にソースするだけでは、必要なスーパークラスがまだソースされていない特定のポイントでエラーが発生します。
dir.create("classes", showWarnings=FALSE)
write("setRefClass(Class=\"A\", contains=\"B\", fields=list(x.3=\"logical\"))",
file="classes/class_A.R")
write("setRefClass(Class=\"B\", contains=\"C\", fields=list(x.2=\"numeric\"))",
file="classes/class_B.R")
write("setRefClass(Class=\"C\", fields=list(x.1=\"character\"))",
file="classes/class_C.R")
class_A.R
はフォルダ内の最初のファイルですが、ソースを作成するには、classes
最初にソースを作成する必要がありますclass_B.R
(このファイルはクラスを定義しているB
ため)。これにはクラスが必要でC
あり、したがって、の事前のソーシングが必要ですclass_C.R
。
したがって、正しい照合は次のようになります。
c("class_C.R", "class_B.R", "class_A.R")
アスペクト2
特定のタスクでは、「ファイルごとに複数の定義」パラダイムが必要です。パラダイム化するときに必要なオブジェクト/関数/クラスをワーカープロセスにすばやく簡単に配布し、実際にパッケージをビルドするときにコードを整理します。
path <- "classes/classes.R"
file.create(path)
write("setRefClass(Class=\"C\", fields=list(x.1=\"character\"))",
file=path, append=TRUE)
write("setRefClass(Class=\"B\", contains=\"C\", fields=list(x.2=\"numeric\"))",
file=path, append=TRUE)
write("setRefClass(Class=\"A\", contains=\"B\", fields=list(x.3=\"logical\"))",
file=path, append=TRUE)
広告アスペクト1
正しい照合順序を指定するある種の手動照合参照を保持するという考えは、コンピューターが私のために簡単に実行できる(正しい照合を見つける)仕事だと思うので、好きではありません。ここで行う必要があるのは、各クラスのスーパークラス(その依存関係の一種)を見つけることだけです。次に、正しい照合を取得するのは簡単です。
編集
誰かが興味を持った場合:私はこれのための実用的なアプローチを思いついた。コードを見たい場合に備えて、私に連絡してください。contains
これは、スーパークラスをリストする引数の値を調査するために、それぞれのクラスdefソースファイルを(評価せずに)解析することに基づいています。その後、最終的に正しい照合が行われるまで、これらのスーパークラスのソースファイルに対してプロセス全体が再帰的に繰り返されます。それほど時間もかかりません。
概要は次のとおりです。
x <- list.files("classes", full.names=TRUE)
code <- base::parse(file=x[1])
> code
expression(setRefClass(Class="A", contains="B", fields=list(x.3="logical")))
superclasses <- eval(code[[1]][["contains"]])
> superclasses
[1] "B"
# Next: investigate source file for class 'B'
広告アスペクト2
また、手動でのコピーと貼り付けも好きではないので、個々のファイルに保存されているか、それぞれのオブジェクトから描画されたソースコードを単一の「統合」ファイルに統合できるルーチンを実装しました(およびを介しdeparse(<source_code_expression>)
てwrite(..., append=TRUE)
)。クラスに関しては、ここでも正しい照合が重要です。そうでない場合、統合ファイルを入手しようとすると、再びエラーが発生します。
どちらの側面でも、クラス/関数/メソッドの実際のソースコード/式にアクセスする方法を選択できると便利です。
- それぞれのソースファイルに保存されているコードの調査に基づく(
parse(file=*)
) - または、それぞれのオブジェクトから直接必要な情報にアクセスすることに基づいています。
2番目のオプションは、上記の実際の質問へのリンクです。