Is it possible to use variables set in index.Rmd in the other Yaml files?

This is indeed tricky, because a lot of things are mixed up in bookdown.

A bit of context first:

This kind of syntax will only work if the file is knit.

"`r rmarkdown::metadata$title`"

This is an inline r expression you can use in an rmarkdown file. And it works in the yaml header because the file is knitted before pandoc process it.

Inside another yaml file, it won't work because this external yaml is not process by knitr.

However, you can run expression in yaml using this syntax !expr. This is a feature from the yaml :package: that rmarkdown & friends is using with eval.expr set to TRUE

yaml::yaml.load("test: !expr 1+1", eval.expr = TRUE)
#> $test
#> [1] 2

Created on 2020-09-09 by the reprex package (v0.3.0.9001)

But for that to work, the r object need to be available.

We could try to use

book_filename: !expr rmarkdown::metadata$title

but rmarkdown::metadata needs to be filed up for that to work and I am not sure it will work.

This is an interesting use case. For now I believe you'll need to use workaround. And I could think of several but only the first one is working

  1. You can modify the yaml config file before rendering your book to modify the content programmatically. You can even use a temp one or have several yaml you would select when rendering

  2. You could try to set a R variable in the session to be used when loading the yaml file that contains a !expr call. You need to use clean_envir = FALSE for now (but it wil be deprecated)

  3. We could do some adjustment in bookdown. One example is can pass a list of bookdown configuration in render_book - This work a that way for output_format. See below.
    We need to open an option to discuss that.

Example for solution 1

bookname <- "mybook"
ori_yml <- "_bookdown.yml"
tmp_yml <- tempfile(fileext = ".yml")
yml_content <- yaml::read_yaml(ori_yml)
yml_content[["book_filename"]] <- bookname
yaml::write_yaml(yml_content, tmp_yml)
bookdown::render_book(
  "index.Rmd",
  output_format = "bookdown::epub_book",
  config_file = tmp_yml
)

Example for solution 2

Write this in your _bookdown.yml yaml

book_filename: !expr bookname

and use this code to render

bookname <- "mybook"
bookdown::render_book(
  "index.Rmd",
  output_format = "bookdown::epub_book",
  clean_envir = FALSE
)

I set output_format in both example just to show the the ebook name is changed as expected.

About edit configuration, you could apply one of this strategy too because you can set it in the _bookdown.yml too (see https://bookdown.org/yihui/bookdown/configuration.html)

About the modification of _output.yml option

You could use output_options argument to change that IMO. It works well for rmarkdown, and it works also for all output format. That means you can change that at rendering using somethink like this

bookdown::render_book(
  "index.Rmd",
  output_format = "bookdown::gitbook",
  output_options = list(
    config = 
      list(edit = "https://github.com/orgname/myproject/edit/master/%s"))
)

This would modify the config value if gitbook() format.

With this answer, I have just wanted to share some workaround. It is definitly not obvious at first.

I would like to have your opinion on this. I think it could be improved in some way for _bookdown.yml option to work as the modification of output options. Something like

bookdown::render_book(
  "index.Rmd",
  output_format = "bookdown::gitbook",
  config_options = list(book_filename = "my_book")
)

That would be merge with the config file used.

I eager to hear your feedback on this. And thanks a lot for all the feedback you gave us on bookdown !

1 Like