4

要するに(実際の質問)

または(実際のソースファイルを調査するのではなく、ソースされた)によって返されたオブジェクトからS4参照クラス(を参照)を定義する実際のソースコード/式にアクセスするにはどうすればよいですか??setRefClassgetClass("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))。クラスに関しては、ここでも正しい照合が重要です。そうでない場合、統合ファイルを入手しようとすると、再びエラーが発生します。

どちらの側面でも、クラス/関数/メソッドの実際のソースコード/式にアクセスする方法を選択できると便利です。

  1. それぞれのソースファイルに保存されているコードの調査に基づく(parse(file=*)
  2. または、それぞれのオブジェクトから直接必要な情報にアクセスすることに基づいています。

2番目のオプションは、上記の実際の質問へのリンクです。

4

2 に答える 2

1

クラス定義

ファイルを評価できないため (照合順序がわからないため)、source定義されたクラスの探索はテーブルにありません。ここでは、各ファイルのテキストを文字ベクトルに解析し、'setRefClass' で始まる解析済みの行を保持します。パーサーは空白を削除し、他の変換を行ってテキストをより均一にフォーマットしますが、以下は一貫したクラス定義 (名前付き引数の使用など) に依存します。

fls <- dir()
names(fls) <- fls
p0 <- lapply(fls, function(fl) as.character(parse(text=readLines(fl))))
p1 <- lapply(p0, grep, pattern="^setRefClass", value=TRUE)

定義されているクラス、含まれているクラス、およびクラス定義が発生するファイル名を含む data.frame を目指しましょう

df <- data.frame(Class=NA_character_, contains=NA_character_,
                 File=rep(fls, sapply(p1, length)),
                 stringsAsFactors=FALSE)

パターンマッチング/置換を使用してそれを埋めます

p2 <- unlist(p1, use.names=FALSE)
pat <- '.*Class = "([[:alnum:]]+)".*'
df[,"Class"] <- sub(pat, "\\1", p2)

pat <- '.*contains = "([[:alnum:]]+)".*'
idx <- grep(pat, p2)
df[idx,"contains"] <- sub(pat, "\\1", p2[idx])

最後に (楽しみのために、同じく B から派生したクラス A1 を class_A.R ファイルに追加しました)

> df
  Class contains      File
1     A        B class_A.R
2    A1        B class_A.R
3     B        C class_B.R
4     C     <NA> class_C.R

Class / contains データ フレームを取得するためのもう 1 つの戦略は、setRefClass の呼び出しをインターセプトすることです。

gClass <- character()
gcontains <- character()
setRefClass <- function(Class, fields, contains=NA_character_, ...)
{
    gClass <<- c(gClass, Class)
    gcontains <<- c(gcontains, contains)
}

gClassまたgcontains、関連ファイルをソース化した後に依存関係グラフを構築するための関連データが含まれます (クラス定義が利用可能でなくてもファイルをソース化できると仮定します)。

for (fl in dir()) source(fl)

依存関係

必要なのは、依存関係を持つクラスの依存関係グラフです。そこで、 BioconductorのグラフRBGLパッケージを使用して、適切なグラフを作成します。

## From --> To == contains --> Class
m <- as.matrix(df[!is.na(df$contains), c("contains", "Class")])
gr <- ftM2graphNEL(m, edgemode="directed")

次に、各ベース パッケージ ( ) から始まる幅優先検索を要求しdf[is.na(df$contains), "Class"]、結果の順序を使用して適切な照合順序を取得します。

o <- bfs(gr, "C")                       # order: breadth-first search
unique(df[match(o, df$Class), "File"])

そう

classDefFilesCollateOrder <- function(fls)
{
    names(fls) <- fls
    p0 <- lapply(fls, function(fl) as.character(parse(text=readLines(fl))))
    p1 <- lapply(p0, grep, pattern="^setRefClass", value=TRUE)

    df <- data.frame(Class=NA_character_, contains=NA_character_,
                     File=rep(fls, sapply(p1, length)),
                     stringsAsFactors=FALSE)

    p2 <- unlist(p1, use.names=FALSE)
    pat <- '.*Class = "([[:alnum:]]+)".*'
    df[,"Class"] <- sub(pat, "\\1", p2)

    pat <- '.*contains = "([[:alnum:]]+)".*'
    idx <- grep(pat, p2)
    df[idx, "contains"] <- sub(pat, "\\1", p2[idx])

    ## From --> To == contains --> Class
    m <- as.matrix(df[!is.na(df$contains), c("contains", "Class")])
    gr <- ftM2graphNEL(m, edgemode="directed")

    ## single class only
    base <- df$Class[is.na(df$contains)]
    if (length(base) != 1)
        stop("don't yet know how to deal with more than 1 base class")
    o <- bfs(gr, base)

    unique(df[match(o, df$Class), "File"])
}
于 2012-08-15T21:11:11.273 に答える
1

コマンドの「ソース」コードは保存されないため、オブジェクトを調べてもわかりません。

setRefClassコンソールに入力して を押して、 のソースを見てみましょう[ENTER]。あなたが行ったことは、関数に引数を渡しただけであることに注意してください...新しい式を定義していません。したがって、getRefClassクラスがそれ自体について知っているすべてを取得しているとき。

setRefClass の引数を再構築する parseRefClassArgs 関数を作成することで、再構築できます。

于 2012-08-15T18:38:40.927 に答える