1

Suppose I have a functions.R script in which I have defined a few functions:

foo <- function(x) print(x-2)
bar <- function(x) print(x^3)
...

Now I want to include only foo (and not the whole functions.R in a chunk in RMarkdown.

If I wanted all functions to be included, following this answer, I could have done this via:

``` {r, code = readLines("functions.R")}
```

However, I only need foo in the chunk. How can I do it? Thanks in advance.

psyguy
  • 312
  • 3
  • 16
  • 1
    If you know what lines the functions you want are on, you could follow the approach [here](https://stackoverflow.com/a/12215731/8386140) – duckmayr Jul 08 '19 at 11:38
  • Thanks @duckmayr, I didn't know I could do that. However I'm a bit reluctant to do it that way since there might be changes to the scripts (adding/removing few lines somewhere) and that'll screw things up. – psyguy Jul 08 '19 at 12:22
  • 1
    Sure, would definitely be a very fragile approach; adding a more robust approach now – duckmayr Jul 08 '19 at 12:32

1 Answers1

3

I adapt the approach from this answer to a related question to solve this problem.1

I stored in the file functions.R your two example functions above:

foo <- function(x) print(x-2)
bar <- function(x) print(x^3)

I then create the following R Markdown document:

---
title: "SO Answer"
author: "duckmayr"
date: "7/8/2019"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

We set up a function to source an R script, but only assign to the global environment the functions we want:

```{r source_function}
source_functions <- function(fcn_names, file_name) {
    env <- new.env()
    source(file_name, local = env)
    for ( i in 1:length(fcn_names) ) {
        assign(fcn_names[i], get(fcn_names[i], envir = env), envir = .GlobalEnv)
    }
}
```

Then we can call it to get *only* the function `foo()`:

```{r get_foo}
source_functions("foo", "functions.R")
ls()
```

This will also work for multiple functions:

```{r get_foo_and_bar}
source_functions(c("foo", "bar"), "functions.R")
ls()
```

Which renders as:

enter image description here

We see that in the first call to source_functions(), only the foo() function is added to the global environment, but not the bar() function, which should work to solve your problem. If you wanted multiple functions from functions.R, this will also work as well, as demonstrated in the second call to source_functions().

Update: Showing the Functions' Code

We can edit our source_functions() function to show the code of the functions it sources, like so:

source_functions <- function(fcn_names, file_name) {
    env <- new.env()
    source(file_name, local = env)
    n <- length(fcn_names)
    result <- character(n)
    for ( i in 1:n ) {
        name <- fcn_names[i]
        fcn <- get(name, envir = env)
        code <- capture.output(show(fcn))
        code <- paste(code[-which(grepl("<env", code))], collapse = " ")
        assign(name, fcn, envir = .GlobalEnv)
        result[i] <- paste(name, "<-", code, collapse = " ")
    }
    return(result)
}

Then our document renders as

enter image description here


1 That question and answer (1) was not in the context of R Markdown, and more importantly (2) only demonstrated how to get all functions from an R script (without getting other objects) rather than particular functions.

duckmayr
  • 16,303
  • 3
  • 35
  • 53
  • Awesome! Is there a way, like with another function, include the raw code of the function in the output? (like a code written in the chunk, as `code = readLines("functions.R")` in the chunk definition does for the whole script.) – psyguy Jul 08 '19 at 14:08
  • 1
    @ManuelHaqi Sure, easily. The answer is updated to include that functionality – duckmayr Jul 08 '19 at 15:35
  • Thanks again @duckmayr. I actually meant it a bit differently: I want the function `echo`ed as a piece of code in the output. I have shown it in this [image](https://user-images.githubusercontent.com/8527082/60826981-a106e880-a19e-11e9-85ac-2205d286bccc.png). Your updated solution gives A, but B (or C) is what I mean. – psyguy Jul 08 '19 at 16:39
  • 1
    Ah, I see... that I think would be more difficult. If I have time later I'll see if I can figure that out – duckmayr Jul 08 '19 at 16:40