Nothing
#' Read an external file as a [`cff`] object
#'
#' @description
#' Read files and convert them to [`cff`] objects. Files supported
#' are:
#' - `CITATION.cff` files.
#' - `DESCRIPTION` files.
#' - **R** citation files (usually located in `inst/CITATION`).
#' - BibTeX files (with extension `*.bib`).
#'
#' [cff_read()] would try to guess the type of file provided in `path`. However
#' we provide a series of alias for each specific type of file:
#' - [cff_read_cff_citation()], that uses [yaml::read_yaml()].
#' - [cff_read_description()], using [desc::desc()].
#' - [cff_read_citation()] uses [utils::readCitationFile()].
#' - [cff_read_bib()] requires \CRANpkg{bibtex} (>= 0.5.0) and uses
#' [bibtex::read.bib()].
#'
#' @export
#' @rdname cff_read
#' @family reading
#' @seealso
#'
#' The underlying functions used for reading external files:
#' - [yaml::read_yaml()] for `CITATION.cff` files.
#' - [desc::desc()] for `DESCRIPTION` files.
#' - [utils::readCitationFile()] for **R** citation files.
#' - [bibtex::read.bib()] for BibTeX files (extension `*.bib`).
#'
#'
#' @param path Path to a file.
#' @param encoding Encoding to be assumed for `path`. See [readLines()].
#' @param meta A list of package metadata as obtained by
#' [utils::packageDescription()] or `NULL` (the default). See **Details**.
#' @param ... Arguments to be passed to other functions (i.e. to
#' [yaml::read_yaml()], [bibtex::read.bib()], etc.).
#'
#' @inheritParams cff_create
#'
#' @return
#'
#' * `cff_read_cff_citation()` and `cff_read_description()` returns a object
#' with class `cff`.
#' * `cff_read_citation()` and `cff_read_bib()` returns an object of classes
#' [`cff_ref_lst, cff`][cff_ref_lst] according to the `definitions.references`
#' specified in the
#' ```{r, echo=FALSE, results='asis'}
#'
#' cat(paste0(" [Citation File Format schema]",
#' "(https://github.com/citation-file-format/",
#' "citation-file-format/blob/main/schema-guide.md)."))
#'
#'
#' ```
#'
#' Learn more about the \CRANpkg{cffr} class system in [cff_class].
#'
#' @references
#'
#' - R Core Team (2023). _Writing R Extensions_.
#' <https://cran.r-project.org/doc/manuals/r-release/R-exts.html>
#'
#' - Hernangomez D (2022). "BibTeX and CFF, a potential crosswalk."
#' *The cffr package, Vignettes*. \doi{10.21105/joss.03900},
#' <https://docs.ropensci.org/cffr/articles/bibtex_cff.html>.
#'
#' @details
#'
#' For details of `cff_read_description()` see [cff_create()].
#'
#' ## The `meta` object
#'
#' Section 1.9 CITATION files of *Writing R Extensions* (R Core Team 2023)
#' specifies how to create dynamic `CITATION` files using `meta` object, hence
#' the `meta` argument in [cff_read_citation()] may be needed for reading
#' some files correctly.
#'
#' @examples
#'
#' # Create cff object from cff file
#'
#' from_cff_file <- cff_read(system.file("examples/CITATION_basic.cff",
#' package = "cffr"
#' ))
#'
#' head(from_cff_file, 7)
#'
#' # Create cff object from DESCRIPTION
#' from_desc <- cff_read(system.file("examples/DESCRIPTION_basic",
#' package = "cffr"
#' ))
#'
#' from_desc
#'
#' # Create cff object from BibTex
#'
#' if (requireNamespace("bibtex", quietly = TRUE)) {
#' from_bib <- cff_read(system.file("examples/example.bib",
#' package = "cffr"
#' ))
#'
#' # First item only
#' from_bib[[1]]
#' }
#' # Create cff object from CITATION
#' from_citation <- cff_read(system.file("CITATION", package = "cffr"))
#'
#' # First item only
#' from_citation[[1]]
#'
cff_read <- function(path, ...) {
if (length(path) > 1) {
cli::cli_abort(
"Use a single value, {.arg path} has length {.val {length(path)}}"
)
}
file_exist_abort(path, abort = TRUE)
filetype <- detect_x_source(path)
if (filetype == "dontknow") {
cli::cli_abort(
paste0(
"Don't recognize the file type of {.file {path}}.",
" Use a specific function (e.g. {.fn cffr:cff_read_description}"
)
)
}
endobj <- switch(filetype,
"cff_citation" = cff_read_cff_citation(path, ...),
"description" = cff_read_description(path, ...),
"bib" = cff_read_bib(path, ...),
"citation" = cff_read_citation(path, ...),
cli::cli_abort("Don't know how to read {.val {x}}.")
)
endobj
}
#' @export
#' @rdname cff_read
cff_read_cff_citation <- function(path, ...) {
file_exist_abort(path, abort = TRUE)
cffobj <- yaml::read_yaml(path, ...)
new_cff(cffobj)
}
#' @export
#' @rdname cff_read
cff_read_description <- function(path, cff_version = "1.2.0",
gh_keywords = TRUE,
authors_roles = c("aut", "cre"), ...) {
file_exist_abort(path, abort = TRUE)
pkg <- desc::desc(path)
pkg$coerce_authors_at_r()
msg <- paste0(
'To cite package "', pkg$get("Package"),
'" in publications use:'
)
field_list <- list(
"cff-version" = cff_version,
message = msg,
type = "software",
title = get_desc_title(pkg),
version = get_desc_version(pkg),
authors = get_desc_authors(pkg, authors_roles = authors_roles),
abstract = get_desc_abstract(pkg),
repository = get_desc_repository(pkg),
"repository-code" = get_desc_urls(pkg)$repo,
url = get_desc_urls(pkg)$url,
identifiers = get_desc_urls(pkg)$identifiers,
"date-released" = get_desc_date_released(pkg),
contact = get_desc_contacts(pkg),
keywords = get_desc_keywords(pkg),
license = unlist(get_desc_license(pkg)),
commit = get_desc_sha(pkg),
doi = get_desc_doi(pkg)
)
if (gh_keywords) {
ghtopics <- get_gh_topics(field_list)
field_list$keywords <- unique(c(field_list$keywords, ghtopics))
}
new_cff(field_list)
}
#' @export
#' @rdname cff_read
cff_read_citation <- function(path, meta = NULL, ...) {
file_exist_abort(path, abort = TRUE)
if (!any(is.null(meta), inherits(meta, "packageDescription"))) {
# nolint start
# Object for cli only
ex <- packageDescription("cffr")
# nolint end
cli::cli_alert_warning(
paste0(
"{.arg meta} should be {.val NULL} or {.obj_type_friendly {ex}}",
" not {.obj_type_friendly {meta}}. Using {.arg meta = NULL}"
)
)
meta <- NULL
}
new_meta <- clean_package_meta(meta)
the_cit <- try(utils::readCitationFile(path, meta = new_meta), silent = TRUE)
# If error then new try
if (inherits(the_cit, "try-error")) {
cli::cli_alert_warning(
paste0(
"It was not possible to read {.file {path}} with the {.arg meta} ",
"provided. Trying with {.code packageDescription('base')}"
)
)
new_meta <- packageDescription("base")
the_cit <- try(utils::readCitationFile(path, meta = new_meta),
silent = TRUE
)
# nocov start
if (inherits(the_cit, "try-error")) {
cli::cli_alert_danger(
"Can't read {.file path}, returning {.val NULL}"
)
return(NULL)
}
# nocov end
}
tocff <- as_cff(the_cit)
tocff
}
#' @export
#' @family bibtex
#' @rdname cff_read
cff_read_bib <- function(path, encoding = "UTF-8", ...) {
file_exist_abort(path, abort = TRUE)
# nocov start
if (!requireNamespace("bibtex", quietly = TRUE)) {
msg <- paste0(
"{.pkg bibtex} package required for using this function: ",
'{.run install.packages("bibtex")}'
)
cli::cli_abort(msg)
}
# nocov end
# Read from tempfile
read_bib <- bibtex::read.bib(file = path, encoding = encoding, ...)
tocff <- as_cff(read_bib)
tocff
}
# Internal safe ----
#' Internal version of cff_read_citation, safe
#' @noRd
cff_safe_read_citation <- function(desc_path, cit_path) {
if (!file_exist_abort(cit_path) || !file_exist_abort(desc_path)) {
return(NULL)
}
# Create meta
meta <- desc_to_meta(desc_path)
meta <- clean_package_meta(meta)
the_cit <- try(utils::readCitationFile(cit_path, meta = meta), silent = TRUE)
# Try
if (inherits(the_cit, "try-error")) {
return(NULL)
}
# Need to be named here
tocff <- as_cff(the_cit)
tocff
}
# See utils.R
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.