Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache of generic objects? #138

Closed
syoh opened this issue Feb 15, 2012 · 8 comments
Closed

cache of generic objects? #138

syoh opened this issue Feb 15, 2012 · 8 comments
Labels
bug Bugs
Milestone

Comments

@syoh
Copy link

syoh commented Feb 15, 2012

Hi Yihui,

Thank you for such great work. knitr is so useful and much better than any of "sweave" variations.

Following is the problem I am having.
I have an external source file (extsource.R) with some function definitions.
One of the functions is a generic object (setGeneric)

The steps I have tried:

  1. Delete cache directory
  2. All functions work with <<ext1,cache=TRUE>>=
  3. fext3 not found in cached version: <<ext1,cache=TRUE>>=,
  4. fext3 found again if not cached <<ext1,cache=FALSE>>=
  5. fext3 not found again: <<ext1,cache=TRUE>>=

It seems to me that the cache does not save generic objects.

######## knit.test.Rnw

\documentclass{article}

\begin{document}
<<>>=
read_chunk('extsource.R')
@ 

<<ext1,cache=TRUE>>=
@ 

<<ext2,cache=TRUE,dependson=ext1>>=
@ 

Run functions:
<<>>=
fext1('a')
fext2('b')
fext3('c')
@ 

\end{document}


############# extsource.R

## @knitr ext1
fext1 <- function(x){
  str <- paste("I am in ext1",x)
  print(str)
}

setGeneric("fext3",
           function(x, ...){
             standardGeneric("fext3")
           })

setMethod("fext3", "character",
          function(x){
            str <- paste("I am in ext3 cf",x)
            print(str)
          })

## @knitr ext2
fext2 <- function(x){
  str <- paste("I am in ext2",x)
  print(str)
  fext1(x)
}
@yihui
Copy link
Owner

yihui commented Feb 15, 2012

This seems weird. I cannot reproduce the error. Did you use an interactive R session or run R non-interactively via Rscript? Which version of knitr are you using? (packageVersion('knitr'))

@syoh
Copy link
Author

syoh commented Feb 15, 2012

I am using version 0.2.2

packageVersion('knitr')
[1] ‘0.2.2’

and I am running the script via a bash script.
following is the relevant line:

R -q -e "library('knitr');knit('$FILENAME')"

Sang

On Wed, Feb 15, 2012 at 3:51 PM, Yihui Xie <
reply@reply.github.com

wrote:

This seems weird. I cannot reproduce the error. Did you use an interactive
R session or run R non-interactively via Rscript? Which version of knitr
are you using? (packageVersion('knitr'))


Reply to this email directly or view it on GitHub:
#138 (comment)

@yihui
Copy link
Owner

yihui commented Feb 16, 2012

I see the problem now. I will investigate it soon. Thanks!

@yihui
Copy link
Owner

yihui commented Feb 16, 2012

The reason is fext3 was created in the global environment (default behavior of setGeneric()), so knitr is unaware of it; the code is evaluated in an empty environment so that knitr knows which objects are created in this chunk, and only these objects are saved. There are a number of possible solutions, and I think the simplest one is to manually copy fext3 to knitr's environment so knitr can save it correctly -- you simply add one line to the code for chunk ext1:

assign('fext3', fext3, envir = knit_env())

A second solution has the same idea, but tackles the problem using a custom chunk hook (looks complicated but it is a good case for learning chunk hooks):

\documentclass{article}

\begin{document}
<<>>=
library(methods)
read_chunk('extsource.R')
knit_hooks$set(cache.obj = function(before, options, envir) {
  if (!before) {
    ## after the chunk has been evaluated, copy an object to knitr's environment
    obj <- options$cache.obj
    assign(obj, get(obj, envir = globalenv()), envir = envir)
    return(NULL)
  }
})
@ 

% add an option cache.obj here
<<ext1, cache=TRUE, cache.obj=fext3>>=
@ 

<<ext2, cache=TRUE, dependson=ext1>>=
@ 

Run functions:
<<>>=
fext1('a')
fext2('b')
fext3('c')
@ 

\end{document}

A slight advantage of using the hook is there will not be an additional line of code appearing in your source code, but even with the first approach, you can get rid of that line in the output (http://yihui.name/knitr/demo/output/).

@syoh
Copy link
Author

syoh commented Feb 16, 2012

Thank you for your clear explanation.
It makes perfect sense now, and I understand the inner workings of knitr a
bit better.

Thanks again.

Sang

On Wed, Feb 15, 2012 at 6:34 PM, Yihui Xie <
reply@reply.github.com

wrote:

The reason is fext3 was created in the global environment (default
behavior of setGeneric()), so knitr is unaware of it; the code is
evaluated in an empty environment so that knitr knows which objects are
created in this chunk, and only these objects are saved. There are a number
of possible solutions, and I think the simplest one is to manually copy
fext3 to knitr's environment so knitr can save it correctly -- you simply
add one line to the code for chunk ext1:

assign('fext3', fext3, envir = knit_env())

A second solution has the same idea, but tackles the problem using a
custom chunk hook (looks complicated but it is a good case for learning
chunk hooks):

\documentclass{article}

\begin{document}
<<>>=
library(methods)
read_chunk('extsource.R')
knit_hooks$set(cache.obj = function(before, options, envir) {
 if (!before) {
   ## after the chunk has been evaluated, copy an object to knitr's
environment
   obj <- options$cache.obj
   assign(obj, get(obj, envir = globalenv()), envir = envir)
   return(NULL)
 }
})
@

% add an option cache.obj here
<<ext1, cache=TRUE, cache.obj=fext3>>=
@

<<ext2, cache=TRUE, dependson=ext1>>=
@

Run functions:
<<>>=
fext1('a')
fext2('b')
fext3('c')
@

\end{document}

Reply to this email directly or view it on GitHub:
#138 (comment)

@yihui yihui closed this as completed Feb 16, 2012
@yihui
Copy link
Owner

yihui commented Mar 11, 2012

Hi, in fact I was trapped by myself and gave you a nasty solution. It turns out to be very easy to keep track of global objects such as those created by setGeneric(). In the development version, I have done so. Now you do not need any tricks, and knitr should be able to catch your generic objects.

Note you need library(methods) if you use Rscript -e instead of R -e because the former does not load methods by default.

@syoh
Copy link
Author

syoh commented Mar 11, 2012

Great news!
Thank you for being so diligent in keeping your package updated.
It makes using your sw contribution so much easier and enjoyable.

On Sat, Mar 10, 2012 at 8:05 PM, Yihui Xie <
reply@reply.github.com

wrote:

Hi, in fact I was trapped by myself and gave you a nasty solution. It
turns out to be very easy to keep track of global objects such as those
created by setGeneric(). In the development version, I have done so. Now
you do not need any tricks, and knitr should be able to catch your generic
objects.

Note you need library(methods) if you use Rscript -e instead of R -e
because the former does not load methods by default.


Reply to this email directly or view it on GitHub:
#138 (comment)

kohske pushed a commit to kohske/knitr that referenced this issue Jun 21, 2012
@github-actions
Copy link

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue by following the issue guide (https://yihui.org/issue/), and link to this old issue if necessary.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Bugs
Projects
None yet
Development

No branches or pull requests

2 participants