5

パッケージのtidy.source機能を上書きしようとしています。knitr問題は、パッケージによってインポートされるパッケージでtidy.source定義されていることです。私が実行した場合:formatRknitr

get("tidy.source", envir=asNamespace("knitr"))

元のコードを取得します。だから私はオーバーライドtidy.sourceしたくなります:

assignInNamespace ("tidy.source", function()print("My tidy.source"), "knitr")

しかし、私は得る:

Error in bindingIsLocked(x, ns) : no binding for "tidy.source"

実際tidy.source、で定義されformatR、によって継承されknitrます。と:

assignInNamespace ("tidy.source", function()print("My tidy.source"), "formatR")

すべてが明らかにスムーズですが、もう一度確認するget("tidy.source", envir=asNamespace("knitr"))と、内部にはknitr何も変更されていないことがわかります。

何か助けはありますか?

編集:

この質問は、 knitr / formatRの新しい開発リリースにより、部分的に廃止されました。この議論に気づき、彼のパッケージを更新することを決定してくれたYihuiに感謝します。見る:

https://github.com/yihui/formatR/commit/6f70360f359caa8d2bb33190a1c89530defb0e98

私は間違いなくSweaveからknitrに切り替えることできます

インポートされたパッケージ関数のオーバーライドに関する一般的な質問は、とにかく未解決のままです。knitr / formatRパッケージとは関係がなくなったので、より一般的な言葉で言い換えます。

パッケージimpをインポートするパッケージメインがあるとします。前者をロードすると、添付パッケージとその両方のリストにが表示され、ロードされた名前空間の名前の中に表示されます。"package:main""main""sub"

mainがエクスポートされたサブ関数expfuncをインポートすると仮定します。これにより、エクスポートされていないサブ関数prvfuncが順番に呼び出されます。expfunc.modを使用してexpfuncを変更/カスタマイズする場合は、次を使用することを検討してください。

assign("exp.sub.func", exp.sub.func.mod, asNamespace ("sub"))

その結果、実行することにより、sub::exp.sub.funcパッチが適用されたバージョン(つまり、exp func.mod)を取得します。
残念ながら、expfunc.modがprvfuncに依存し続ける限りエラーが発生します。

Error in [...] : object 'prv.sub.func' not found

実際には:

environment(sub::exp.sub.func) 

今すぐ戻ります:パッチを適用する前でした<environment: R_GlobalEnv><environment: namespace:sub>

問題は、パッチを適用した関数を適切な名前空間に移動する方法です。

上記の問題を実装するには、もちろんどのパッケージでも使用できます。私の場合、メインおよびインポートされた名前空間としてknitrformatRを使用し、パッチを適用した関数としてtidy.source()を使用しました。

4

4 に答える 4

3

formatR名前空間の関数を変更しても、knitrはすでにロードされているため、knitrが使用するものは変更されません。したがって、アンロードしてリロードすることができます。

assignInNamespace("tidy.source", function()print("My tidy.source"), "formatR")
detach('package:knitr', unload=TRUE)
library(knitr)
get("tidy.source", envir=asNamespace("knitr"))
#function()print("My tidy.source")
于 2012-11-28T02:01:07.073 に答える
2

関数の引数の後のコメントだけが必要な場合は、開発バージョンにサポートを追加しました。Githubからインストールできます。

assignInNamespace()通常、ドキュメントに示されているように、を使用してパッケージを変更することはお勧めできません。

于 2012-11-30T21:47:37.280 に答える
0

これは、 formatRパッケージtidy.sourceに含まれている関数ごとに、関数の引数の後にインラインコメントを許可するというバグのある試みである可能性があります。

## ============ Possible (wrong?) ideas on inline comments ============

  tidy.source.mod=  function (source = "clipboard", keep.comment = getOption("keep.comment",
    TRUE), keep.blank.line = getOption("keep.blank.line", TRUE),
    keep.space = getOption("keep.space", FALSE), replace.assign = getOption("replace.assign",
        FALSE), left.brace.newline = getOption("left.brace.newline",
        FALSE), reindent.spaces = getOption("reindent.spaces",
        4), output = TRUE, text = NULL, width.cutoff = getOption("width"),
    ...)
{     
    if (is.null(text)) {
        if (source == "clipboard" && Sys.info()["sysname"] ==
            "Darwin") {
            source = pipe("pbpaste")
        }
        text = readLines(source, warn = FALSE)
    } 
    if (length(text) == 0L || all(grepl("^\\s*$", text))) {
        if (output)
            cat("\n", ...)
        return(list(text.tidy = "", text.mask = ""))
    } 
    text.lines = text
    if (keep.comment) {
        if (!keep.space)
            text.lines = gsub("^[[:space:]]+|[[:space:]]+$",
                "", text.lines)
        head.comment = grepl("^[[:space:]]*#", text.lines)
        if (any(head.comment)) {
            text.lines[head.comment] = gsub("\"", "'", text.lines[head.comment])
        }
        if (!keep.space) {
            head.comment = head.comment & !grepl("^\\s*#+'",
                text.lines)
            text.lines = reflow_comments(text.lines, head.comment,
                width.cutoff)
            head.comment = grepl("^[[:space:]]*#", text.lines)
        }
        text.lines[head.comment] = sprintf("invisible(\"%s%s%s\")",
            begin.comment, text.lines[head.comment], end.comment)
        blank.line = grepl("^[[:space:]]*$", text.lines)
        if (any(blank.line) && keep.blank.line) {
            else.line = grep("^[[:space:]]*else(\\W|)", text.lines)
            for (i in else.line) {
                j = i - 1
                while (blank.line[j]) {
                  blank.line[j] = FALSE
                  j = j - 1
                  warning("removed blank line ", j, " (you should not put an 'else' in a separate line!)")
                }
            }
            text.lines[blank.line] = sprintf("invisible(\"%s%s\")",
                begin.comment, end.comment)
        }
        text.lines = mask_inline(text.lines)
    } 
    #modified code
    ic=grepl( "%InLiNe_IdEnTiFiEr%", text.lines)
    text.lines[ic]=substr(text.lines[ic], 1, nchar(text.lines[ic])-1)
    text.lines[ic]=  paste0(text.lines[ic], "%InLiNe_IdEnTiFiEr_mod%\"")
    #end modified code
    text.mask = tidy_block(text.lines, width.cutoff, replace.assign)
    text.tidy = if (keep.comment)
        unmask.source(text.mask)
    else text.mask
    text.tidy = reindent_lines(text.tidy, reindent.spaces)
    if (left.brace.newline)
        text.tidy = move_leftbrace(text.tidy, reindent.spaces)
    #modified code
    text.tidy= unlist(sapply(text.tidy, strsplit, "%InLiNe_IdEnTiFiEr_mod%", USE.NAMES=FALSE))
    #end modified code
    if (output)
        cat(paste(text.tidy, collapse = "\n"), "\n", ...)
    invisible(list(text.tidy = text.tidy, text.mask = text.mask))
}     
## ====================================================


## ============ Implementation ============

## Clean-up
if("formatR" %in% loadedNamespaces() ) detach('package:formatR', unload=TRUE)
if(exists("tidy.source"))rm(tidy.source)
library("formatR")


## String with inline comments after arguments
text.input="paste(1 # comm
   ,7)
"     
## The same in vector format
text.input=strsplit(text.input, "\n")[[1]]

## Implementation without patch
tidy.source(text=text.input) #newline removed with  wrong result!
# paste(1  # comm, 7) 


# Tentative patch
unlockBinding("tidy.source", as.environment("package:formatR") )
assign("tidy.source", tidy.source.mod, pos="package:formatR")
environment(tidy.source)= asNamespace( "formatR" )

## Implementation with patch
tidy.source(text=text.input) # apparently ok:
# paste(1  # comm
# , 7) 
于 2012-11-30T13:53:37.017 に答える
0

私はおそらく解決策に近づいていますが、エクスポートされていないformatR関数を処理する必要があります。実際、元のtidy.sourceコード、つまりパッチが適用されたバージョンには、エクスポートされていないパッケージ関数への呼び出しがありますreflow_comments

問題と私が行った手順を説明するために、プライベート formatR関数を呼び出すパッチを適用したtidy.sourceのテストから始めましょう。

### Listing 1 - Modified tidy.source             

tidy.source.mod=function (source, output, text){ 
  #Print body first line of reflow_comments      
  head(reflow_comments,1)                        
}                                                

source, output, text先に使用したニット から渡されるパラメータが必要です。

これで、 tidy.sourcetidy.source.modでパッチを適用できます。

### Listing 2 - Patch tidy.source                       

## General clean up                                     
if("knitr" %in% loadedNamespaces() ) detach('package:knitr', unload=TRUE)
if("formatR" %in% loadedNamespaces() ) detach('package:formatR', unload=TRUE)
if(exists("tidy.source"))rm(tidy.source)                
library("formatR")                                      

## Info                                                 
environment(tidy.source )                               
# <environment: namespace:formatR>                      
environment(formatR::tidy.source )                      
# <environment: namespace:formatR>                      

## Change tidy.source with tidy.source.mod              
unlockBinding("tidy.source", env=as.environment("package:formatR"))
assign("tidy.source", tidy.source.mod, envir=as.environment("package:formatR"))
lockBinding("tidy.source", env=as.environment("package:formatR"))
unlockBinding("tidy.source", env=asNamespace ("formatR"))
assign("tidy.source", tidy.source.mod, asNamespace ("formatR") )
environment(tidy.source)= asNamespace( "formatR" )      
lockBinding("tidy.source", env=asNamespace ("formatR")) 

結果を確認できます。

### Listing 3 - Check results                                                  

getAnywhere(tidy.source)                                                       
# A single object matching 'tidy.source' was found                             
# It was found in the following places                                         
#   .GlobalEnv                                                                 
#   package:formatR                                                            
#   namespace:formatR                                                          
# with value                                                                   

# function (){                                                                 
#   head(reflow_comments,1)                                                    
# }                                                                            
# <environment: namespace:formatR>                                             

tidy.source()                                                                  
# 1 function (text, idx = grepl("^\\\\s*#+", text), width = getOption("width"))

どうやらtidy.sourceはtidy.source.modに正しく置き換えられました; 名前空間が更新されたため、tidy.sourceはエクスポートされていない関数(の最初の行)にアクセスでき reflow_commentsます。

knitrを処理するには、編み物をするファイルも必要です。ここでは、簡単にするためにテキスト文字列を使用します。

### Listing 4 - Sample file/text to knit

library("knitr") 

text="           
\\documentclass{article}
\\begin{document}

<<comme, include=TRUE>>=
print('hello')   
@                

\\end{document}  
"                

knitrはパッチが適用されたtidy.sourceを見ることができますか?これは、Rdebugを使用して確認できます

debug(knit)                                   
knit(text=text) #will enter debug session (prompt s'd be like 'Browse[2]>')
# debugging in: knit(text = text)             
# debug: {                                    
# knit body, very long, omitted               
# }                                           
tidy.source #command given inside the debug session
# function (){                                
#   head(reflow_comments,1)                   
# }                                           
tidy.source() # :-( reflow_comments is not accessible
Q  #quit debug session                        

undebug(knit)                                 

残念ながら、ニットからはパッチが適用されたtidy.sourceが表示されますが、エクスポートされていないformatR関数にはアクセスできません。これは、通常、パッチが適用されていないtidy.sourceを介してニットで可能です。

ここで、いくつかのヒントは、formatR::tidy.source()どちらも機能しない可能性があります。

formatR::tidy.source()
# Error in head(reflow_comments, 1) (from #2) : object 'reflow_comments' not found

namespace:formatRの環境は次のとおりです。

environment(formatR::tidy.source )
# <environment: R_GlobalEnv>

それは<environment: namespace:formatR>パッチを適用する前でした(リスト2の情報を参照)。パッチをenvironment(tidy.source )適用すると簡単にリセットされましたが、namespace:formatRの場合は次のエラーが発生します。

environment(formatR::tidy.source )=asNamespace( "formatR" )
# Error in environment(formatR::tidy.source) = asNamespace("formatR") :
#  object 'formatR' not found 

私はまだ探しています...

于 2012-11-30T03:16:41.753 に答える