From f8c3a985f6527f9634a74b7392d560531a448e47 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Tue, 18 Aug 2026 22:35:53 +0000 Subject: [PATCH 1/4] Move data.table from Depends to Imports --- DESCRIPTION | 6 +++--- NAMESPACE | 15 ++++++++++++++- R/call-numbers-and-subject.R | 14 +++++++------- R/marc-field-deconstruction.R | 1 + R/other-code-translations.R | 4 ++-- R/special-attributes.R | 15 ++++++++++----- R/split-map-filter-reduce.R | 4 ++++ R/the-web.R | 1 + R/utilities.R | 22 +++++++++++++++------- R/worldcat-api.R | 1 + man/car.Rd | 1 + man/cp_lb_attributes.Rd | 1 + man/dt_add_to_col_names.Rd | 1 + man/dt_counts_and_percents.Rd | 1 + man/dt_del_cols.Rd | 1 + man/dt_keep_cols.Rd | 1 + man/dt_na_breakdown.Rd | 1 + man/dt_percent_not_na.Rd | 1 + man/dt_set_clean_names.Rd | 1 + man/fread_plus_date.Rd | 1 + man/fwrite_plus_date.Rd | 1 + man/get_clean_names.Rd | 1 + man/recombine_with_sep_closure.Rd | 1 + man/remove_duplicates_and_nas.Rd | 1 + man/set_lb_attribute.Rd | 1 + man/set_lb_date.Rd | 1 + man/split_map_filter_reduce.Rd | 3 ++- tests/testthat.R | 1 + tests/testthat/setup.R | 1 + 29 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 tests/testthat/setup.R diff --git a/DESCRIPTION b/DESCRIPTION index 9e0c691..ecf406a 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -13,13 +13,13 @@ Description: Provides functions for validating and normalizing bibliographic and provides various loadable data files such call number / subject crosswalks and code tables. License: GPL-3 -Depends: R (>= 3.5.0), data.table, utils -Imports: curl, methods, pbapply, stringr, xml2 +Depends: R (>= 3.5.0), utils +Imports: curl, data.table, methods, pbapply, stringr, xml2 Suggests: assertr, testthat, knitr, magrittr, rmarkdown Encoding: UTF-8 -RoxygenNote: 7.2.1 VignetteBuilder: knitr NeedsCompilation: no Packaged: 2021-05-05 13:51:08 UTC; tonyfischetti Author: Tony Fischetti [aut, cre] URL: https://github.com/NYPL/libbib +Config/roxygen2/version: 8.0.0 diff --git a/NAMESPACE b/NAMESPACE index b64330f..97a156a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -58,6 +58,19 @@ export(worldcat_api_search) export(worldcat_permalink_from_isbn) export(worldcat_permalink_from_issn) export(worldcat_permalink_from_oclc_number) -import(data.table) import(pbapply) import(utils) +importFrom(data.table,"%chin%") +importFrom(data.table,":=") +importFrom(data.table,.N) +importFrom(data.table,as.data.table) +importFrom(data.table,copy) +importFrom(data.table,data.table) +importFrom(data.table,fcase) +importFrom(data.table,fread) +importFrom(data.table,fwrite) +importFrom(data.table,rbindlist) +importFrom(data.table,setattr) +importFrom(data.table,setcolorder) +importFrom(data.table,setindex) +importFrom(data.table,setnames) diff --git a/R/call-numbers-and-subject.R b/R/call-numbers-and-subject.R index 07458d7..fb63755 100755 --- a/R/call-numbers-and-subject.R +++ b/R/call-numbers-and-subject.R @@ -28,7 +28,7 @@ REGEX.VALID.LCCALL.BARE <- make.valid.lccall.regex(allow.bare=TRUE) #' letter, or a second-level subclassification #' description based on the all the letters #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Library of Congress call number (string) #' @param subclassification A logical indicating whether the letters of @@ -119,7 +119,7 @@ get_lc_call_subject_classification <- function(x, subclassification=FALSE, #' whether or not the input fits the canonical LC Call #' Number pattern #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Library of Congress call number (string) #' @param allow.bare A logical indicating whether an LC Call with only @@ -164,7 +164,7 @@ attr(is_valid_lc_call, "assertr_vectorized") <- TRUE #' call number and returns the first letter if and only if #' the LC Call Number is valid #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Library of Congress call number (string) #' @param allow.bare A logical indicating whether an LC Call with only @@ -209,7 +209,7 @@ get_lc_call_first_letter <- function(x, allow.bare=FALSE){ #' call number and returns all the subject letters if and only if #' the LC Call Number is valid #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' @import utils #' #' @param x A Library of Congress call number (string) @@ -261,7 +261,7 @@ get_all_lc_call_subject_letters <- function(x, allow.bare=FALSE){ #' This uses the hundreds place of the DDC number #' and returns the most general subject classification. #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Dewey Decimal call number #' @@ -313,7 +313,7 @@ get_dewey_decimal_subject_class <- function(x){ #' This uses the first two digits of the DDC number #' and returns the second most general subject classification. #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Dewey Decimal call number #' @@ -365,7 +365,7 @@ get_dewey_decimal_subject_division <- function(x){ #' This uses the first three digits of the DDC number #' and returns the third most general subject classification. #' -#' @import data.table +#' @importFrom data.table := data.table setindex #' #' @param x A Dewey Decimal call number #' diff --git a/R/marc-field-deconstruction.R b/R/marc-field-deconstruction.R index c7952da..7eacf2f 100755 --- a/R/marc-field-deconstruction.R +++ b/R/marc-field-deconstruction.R @@ -25,6 +25,7 @@ #' # 3: Cartographic material Monograph/Item #' #' @export +#' @importFrom data.table fcase marc_leader_get_info <- function(x){ if(!methods::is(x, "character")) stop("x must be a string or NA") diff --git a/R/other-code-translations.R b/R/other-code-translations.R index 5d1bf28..0e1db44 100755 --- a/R/other-code-translations.R +++ b/R/other-code-translations.R @@ -5,7 +5,7 @@ #' Takes a language code (defined in the Marc standards) #' and returns the language name. #' -#' @import data.table +#' @importFrom data.table data.table setindex #' #' @param x A language code (defined in the Marc standards) or a vector #' of language codes @@ -46,7 +46,7 @@ get_language_from_code <- function(x){ #' Interestingly, although it's called 'country' in the Marc standard, #' cities, states, and other non-countries also have codes #' -#' @import data.table +#' @importFrom data.table data.table setindex #' #' @param x A country code (defined in the Marc standards) or a vector #' of country codes diff --git a/R/special-attributes.R b/R/special-attributes.R index 8f0e666..62509cc 100755 --- a/R/special-attributes.R +++ b/R/special-attributes.R @@ -5,7 +5,7 @@ #' Takes an object, attribute name, and a value and sets a special #' libbib attribute by reference #' -#' @import data.table +#' @importFrom data.table fread fwrite setattr #' #' @param x An object to set the attribute on #' @param type The name of the attribute to set. \code{lb.} will be appended @@ -17,6 +17,7 @@ #' @return Nothing, since the object is modified by reference. #' #' @examples +#' library(data.table) #' set_lb_attribute(mtcars, "source", "R built-in dataset") #' #' versicolor <- iris[iris$Species=="versicolor", ] @@ -35,7 +36,7 @@ set_lb_attribute <- function(x, type, value){ #' Takes an object and a date and sets a special attribute, "lb.date" #' by reference #' -#' @import data.table +#' @importFrom data.table fread fwrite setattr #' #' @param x An object to set the attribute on #' @param value Either a value of class \code{Date} or a string in ISO 8601 @@ -44,6 +45,7 @@ set_lb_attribute <- function(x, type, value){ #' @return Nothing, since the object is modified by reference. #' #' @examples +#' library(data.table) #' set_lb_date(mtcars, "2021-05-08") #' attributes(mtcars)$lb.date #' # [1] "2021-05-08 @@ -66,7 +68,7 @@ set_lb_date <- function(x, value){ #' (attributes beginning with \code{lb.}) from the first object #' to the second, by reference. #' -#' @import data.table +#' @importFrom data.table fread fwrite setattr #' #' @param a The first object (the one with the attributes to copy) #' @param b The second object (the one to copy those attributes to) @@ -74,6 +76,7 @@ set_lb_date <- function(x, value){ #' @return Nothing, since the object is modified by reference. #' #' @examples +#' library(data.table) #' #' tmp1 <- "a" #' set_lb_date(tmp1, "2021-05-08") @@ -162,7 +165,7 @@ fread_plus_helper <- function(fname){ #' \code{allow.fallback.date} is \code{TRUE}, then the \code{lb.date} #' attribute is set to the current date. #' -#' @import data.table +#' @importFrom data.table fread fwrite setattr #' #' @param fname The file name to read #' @param allow.fallback.date A logical indicating whether, if no @@ -174,6 +177,7 @@ fread_plus_helper <- function(fname){ #' @return A \code{data.table} with an attribute called \code{lb.date} set #' #' @examples +#' library(data.table) #' \dontrun{ #' # there's a file called "iris-2021-05-08.csv" on disk #' dat <- fread_plus_date("iris.csv") @@ -243,7 +247,7 @@ fread_plus_date <- function(fname, allow.fallback.date=TRUE, ...){ #' the base file name (after any directories) with the exception of #' the file extension. #' -#' @import data.table +#' @importFrom data.table fread fwrite setattr #' #' @param DT a \code{data.table} to write to disk #' @param fname The file name to write the \code{data.table} to. The @@ -262,6 +266,7 @@ fread_plus_date <- function(fname, allow.fallback.date=TRUE, ...){ #' @param ... Arbitrary arguments to pass to \code{fwrite} #' #' @examples +#' library(data.table) #' \dontrun{ #' #' set_lb_date(iris, "2021-05-08") diff --git a/R/split-map-filter-reduce.R b/R/split-map-filter-reduce.R index 4ed9474..2b83601 100755 --- a/R/split-map-filter-reduce.R +++ b/R/split-map-filter-reduce.R @@ -16,6 +16,7 @@ #' @seealso \code{\link{split_map_filter_reduce}} #' #' @examples +#' library(data.table) #' car(c(8, 6, 7, 5, 3, 0, 9)) # 8 #' mt <- as.data.table(mtcars) #' dt_del_cols(mt, "cyl", "disp", "hp") @@ -41,6 +42,7 @@ car <- function(x){ #' @seealso \code{\link{split_map_filter_reduce}} #' #' @examples +#' library(data.table) #' #' remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) #' # 8 6 7 5 3 0 9 @@ -75,6 +77,7 @@ remove_duplicates_and_nas <- function(x){ #' @seealso \code{\link{paste}} #' #' @examples +#' library(data.table) #' #' lambda <- recombine_with_sep_closure() #' lambda(c(8, 6, 7)) # "8;6;7" @@ -150,6 +153,7 @@ recombine_with_sep_closure <- function(sep=";"){ #' @seealso \code{\link{recombine_with_sep_closure}} #' #' @examples +#' library(data.table) #' #' someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", #' "1861897952; 978-1-86189-795-4") diff --git a/R/the-web.R b/R/the-web.R index fc8a967..3af825b 100755 --- a/R/the-web.R +++ b/R/the-web.R @@ -33,6 +33,7 @@ #' # "https://lccn.loc.gov/73167510/marcxml" #' #' @export +#' @importFrom data.table fcase loc_permalink_from_lccn <- function(x, normalize=TRUE, format=""){ if(all(is.na(x))) return(as.character(x)) if(!methods::is(x, "character")) diff --git a/R/utilities.R b/R/utilities.R index 2a08bbe..8b3ba18 100755 --- a/R/utilities.R +++ b/R/utilities.R @@ -9,7 +9,7 @@ #' Takes a data.table and a quoted sequence of column names #' and removes the specified column names from the data.table #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT A data.table #' @param ... arbitrary number of column names in quotes @@ -17,6 +17,7 @@ #' @return Returns data.table with those columns removed #' #' @examples +#' library(data.table) #' mt <- as.data.table(mtcars) #' dt_del_cols(mt, "cyl", "disp", "hp") #' @@ -36,7 +37,7 @@ dt_del_cols <- function(DT, ...){ #' Takes a data.table and a quoted sequence of column names #' and removes all columns but the ones specified #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT A data.table #' @param ... arbitrary number of column names in quotes @@ -44,6 +45,7 @@ dt_del_cols <- function(DT, ...){ #' @return Returns data.table with only those columns #' #' @examples +#' library(data.table) #' mt <- as.data.table(mtcars) #' dt_keep_cols(mt, "mpg", "am", "gear", "carb") #' @@ -119,7 +121,7 @@ dt_pivot <- function(DT, theby, theexp, percent.cutoff=0, value.name="value", #' The quoted group-by variable must be a character or factor. If it is #' not, it will be temporarily converted into one and a warning is issued. #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT The data.table object to operate on #' @param group_by_this A quoted column to group by @@ -137,6 +139,7 @@ dt_pivot <- function(DT, theby, theexp, percent.cutoff=0, value.name="value", #' percent column (out of 100) to two decimal places #' #' @examples +#' library(data.table) #' #' iris_dt <- as.data.table(iris) #' dt_counts_and_percents(iris_dt, "Species") @@ -196,6 +199,7 @@ dt_counts_and_percents <- function(DT, group_by_this, percent.cutoff=0, #' @seealso \code{\link{make.unique}} #' #' @examples +#' library(data.table) #' ejemplo <- iris #' names(ejemplo) <- c("Sepal Length", "Sepal@Width", "Petal Length", #' "Petal\\nWidth", "SpĂȘcies") @@ -231,7 +235,7 @@ get_clean_names <- function(dat, lower=TRUE){ #' All space/whitespace characters are replaced with underscores, #' as are all characters not from A-Z, a-z, an underscore, or a digit #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT a data.table #' @param lower A logical indicating whether all column names should be @@ -242,6 +246,7 @@ get_clean_names <- function(dat, lower=TRUE){ #' @seealso \code{\link{get_clean_names}} #' #' @examples +#' library(data.table) #' #' ejemplo <- as.data.table(iris) #' setnames(ejemplo, c("Sepal Length", "Sepal@Width", "Petal Length", @@ -265,7 +270,7 @@ dt_set_clean_names <- function(DT, lower=TRUE){ #' NA. #' The percent is out of 100 and contains up to two decimal places #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT A data.table object #' @param acolumn a quoted column name @@ -275,6 +280,7 @@ dt_set_clean_names <- function(DT, lower=TRUE){ #' @seealso \code{\link{is.na}} #' #' @examples +#' library(data.table) #' #' mt <- as.data.table(mtcars) #' mt[mpg<16, mpg:=NA] @@ -303,7 +309,7 @@ dt_percent_not_na <- function(DT, acolumn){ #' #' The quoted group-by variable must be a character or factor #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT The data.table object to operate on #' @param acolumn a quoted column name @@ -317,6 +323,7 @@ dt_percent_not_na <- function(DT, acolumn){ #' percent column (out of 100) to two decimal places #' #' @examples +#' library(data.table) #' #' iris_dt <- as.data.table(iris) #' iris_dt[sample(1:.N, 10), Species:=NA_character_] @@ -347,7 +354,7 @@ dt_na_breakdown <- function(DT, acolumn, big.mark=FALSE){ #' be added to end of the each column's name. If \code{prefix} #' is \code{TRUE}, the string is added to the beginning, instead. #' -#' @import data.table +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames #' #' @param DT A data.table #' @param astring A string to add to each column name @@ -372,6 +379,7 @@ dt_na_breakdown <- function(DT, acolumn, big.mark=FALSE){ #' column names. #' #' @examples +#' library(data.table) #' DT <- as.data.table(iris) #' #' dt_add_to_col_names(DT, "_post") diff --git a/R/worldcat-api.R b/R/worldcat-api.R index bb8de24..06cd591 100755 --- a/R/worldcat-api.R +++ b/R/worldcat-api.R @@ -1069,6 +1069,7 @@ worldcat_api_search_helper <- function(sru, max_records=100, #' #' } #' @export +#' @importFrom data.table fcase rbindlist setcolorder worldcat_api_search <- function(sru, max_records=10, sru_query_assist=getOption("libbib.sru_query_assist", TRUE), frbrGrouping="on", start_at=1, diff --git a/man/car.Rd b/man/car.Rd index 7339703..4db84e7 100644 --- a/man/car.Rd +++ b/man/car.Rd @@ -20,6 +20,7 @@ Equivalent to Lisp's \code{car} function Originally for use as a reduction function in \code{split_map_filter_reduce} } \examples{ +library(data.table) car(c(8, 6, 7, 5, 3, 0, 9)) # 8 mt <- as.data.table(mtcars) dt_del_cols(mt, "cyl", "disp", "hp") diff --git a/man/cp_lb_attributes.Rd b/man/cp_lb_attributes.Rd index 42b476e..c5dc252 100644 --- a/man/cp_lb_attributes.Rd +++ b/man/cp_lb_attributes.Rd @@ -20,6 +20,7 @@ Takes two objects and copies all special libbib attributes to the second, by reference. } \examples{ +library(data.table) tmp1 <- "a" set_lb_date(tmp1, "2021-05-08") diff --git a/man/dt_add_to_col_names.Rd b/man/dt_add_to_col_names.Rd index 15abd4e..85e6903 100644 --- a/man/dt_add_to_col_names.Rd +++ b/man/dt_add_to_col_names.Rd @@ -48,6 +48,7 @@ be added to end of the each column's name. If \code{prefix} is \code{TRUE}, the string is added to the beginning, instead. } \examples{ +library(data.table) DT <- as.data.table(iris) dt_add_to_col_names(DT, "_post") diff --git a/man/dt_counts_and_percents.Rd b/man/dt_counts_and_percents.Rd index ad48523..1e9bcbb 100644 --- a/man/dt_counts_and_percents.Rd +++ b/man/dt_counts_and_percents.Rd @@ -43,6 +43,7 @@ The quoted group-by variable must be a character or factor. If it is not, it will be temporarily converted into one and a warning is issued. } \examples{ +library(data.table) iris_dt <- as.data.table(iris) dt_counts_and_percents(iris_dt, "Species") diff --git a/man/dt_del_cols.Rd b/man/dt_del_cols.Rd index 8b6b04b..96ccc19 100644 --- a/man/dt_del_cols.Rd +++ b/man/dt_del_cols.Rd @@ -19,6 +19,7 @@ Takes a data.table and a quoted sequence of column names and removes the specified column names from the data.table } \examples{ +library(data.table) mt <- as.data.table(mtcars) dt_del_cols(mt, "cyl", "disp", "hp") diff --git a/man/dt_keep_cols.Rd b/man/dt_keep_cols.Rd index 870e310..642dd4f 100644 --- a/man/dt_keep_cols.Rd +++ b/man/dt_keep_cols.Rd @@ -19,6 +19,7 @@ Takes a data.table and a quoted sequence of column names and removes all columns but the ones specified } \examples{ +library(data.table) mt <- as.data.table(mtcars) dt_keep_cols(mt, "mpg", "am", "gear", "carb") diff --git a/man/dt_na_breakdown.Rd b/man/dt_na_breakdown.Rd index c276592..928d3fb 100644 --- a/man/dt_na_breakdown.Rd +++ b/man/dt_na_breakdown.Rd @@ -34,6 +34,7 @@ The final row is a total count The quoted group-by variable must be a character or factor } \examples{ +library(data.table) iris_dt <- as.data.table(iris) iris_dt[sample(1:.N, 10), Species:=NA_character_] diff --git a/man/dt_percent_not_na.Rd b/man/dt_percent_not_na.Rd index 1614e6e..02727b7 100644 --- a/man/dt_percent_not_na.Rd +++ b/man/dt_percent_not_na.Rd @@ -21,6 +21,7 @@ NA. The percent is out of 100 and contains up to two decimal places } \examples{ +library(data.table) mt <- as.data.table(mtcars) mt[mpg<16, mpg:=NA] diff --git a/man/dt_set_clean_names.Rd b/man/dt_set_clean_names.Rd index 90bf9e5..25883a9 100644 --- a/man/dt_set_clean_names.Rd +++ b/man/dt_set_clean_names.Rd @@ -25,6 +25,7 @@ All space/whitespace characters are replaced with underscores, as are all characters not from A-Z, a-z, an underscore, or a digit } \examples{ +library(data.table) ejemplo <- as.data.table(iris) setnames(ejemplo, c("Sepal Length", "Sepal@Width", "Petal Length", diff --git a/man/fread_plus_date.Rd b/man/fread_plus_date.Rd index 2c917c8..7ec72a9 100644 --- a/man/fread_plus_date.Rd +++ b/man/fread_plus_date.Rd @@ -48,6 +48,7 @@ with an ISO 8601 date appended to that file name on your disk, and attribute is set to the current date. } \examples{ +library(data.table) \dontrun{ # there's a file called "iris-2021-05-08.csv" on disk dat <- fread_plus_date("iris.csv") diff --git a/man/fwrite_plus_date.Rd b/man/fwrite_plus_date.Rd index d160778..ca78c99 100644 --- a/man/fwrite_plus_date.Rd +++ b/man/fwrite_plus_date.Rd @@ -60,6 +60,7 @@ the base file name (after any directories) with the exception of the file extension. } \examples{ +library(data.table) \dontrun{ set_lb_date(iris, "2021-05-08") diff --git a/man/get_clean_names.Rd b/man/get_clean_names.Rd index ffc98f2..0338aa9 100644 --- a/man/get_clean_names.Rd +++ b/man/get_clean_names.Rd @@ -29,6 +29,7 @@ will show stating such and the duplicate column names will be make unique. } \examples{ +library(data.table) ejemplo <- iris names(ejemplo) <- c("Sepal Length", "Sepal@Width", "Petal Length", "Petal\\\\nWidth", "SpĂȘcies") diff --git a/man/recombine_with_sep_closure.Rd b/man/recombine_with_sep_closure.Rd index ea20c69..b20656b 100644 --- a/man/recombine_with_sep_closure.Rd +++ b/man/recombine_with_sep_closure.Rd @@ -22,6 +22,7 @@ elements of that vector together Can be used as a reduction function in \code{split_map_filter_reduce} } \examples{ +library(data.table) lambda <- recombine_with_sep_closure() lambda(c(8, 6, 7)) # "8;6;7" diff --git a/man/remove_duplicates_and_nas.Rd b/man/remove_duplicates_and_nas.Rd index f62d451..834e404 100644 --- a/man/remove_duplicates_and_nas.Rd +++ b/man/remove_duplicates_and_nas.Rd @@ -20,6 +20,7 @@ elements and without NA values Can be used as a filtering function in \code{split_map_filter_reduce} } \examples{ +library(data.table) remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) # 8 6 7 5 3 0 9 diff --git a/man/set_lb_attribute.Rd b/man/set_lb_attribute.Rd index e8d1dc5..564a3a9 100644 --- a/man/set_lb_attribute.Rd +++ b/man/set_lb_attribute.Rd @@ -24,6 +24,7 @@ Takes an object, attribute name, and a value and sets a special libbib attribute by reference } \examples{ +library(data.table) set_lb_attribute(mtcars, "source", "R built-in dataset") versicolor <- iris[iris$Species=="versicolor", ] diff --git a/man/set_lb_date.Rd b/man/set_lb_date.Rd index f638c85..e2be22b 100644 --- a/man/set_lb_date.Rd +++ b/man/set_lb_date.Rd @@ -20,6 +20,7 @@ Takes an object and a date and sets a special attribute, "lb.date" by reference } \examples{ +library(data.table) set_lb_date(mtcars, "2021-05-08") attributes(mtcars)$lb.date # [1] "2021-05-08 diff --git a/man/split_map_filter_reduce.Rd b/man/split_map_filter_reduce.Rd index 070492a..c00f5e6 100644 --- a/man/split_map_filter_reduce.Rd +++ b/man/split_map_filter_reduce.Rd @@ -53,7 +53,7 @@ Returns a vector } \description{ This function takes a vector of strings, splits those strings -on a particular character; string; or regex patters, applies a +on a particular character; string; or regex pattern, applies a user-specified function to each sub-element of the now split element, filters those sub-elements using a user-specified function, and, finally, recombines each element's sub-elements using a user specified reduction @@ -70,6 +70,7 @@ might be useful for, as an example, batch normalizing ISBNs that, for each bibliographic record, is separated by a semicolon } \examples{ +library(data.table) someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", "1861897952; 978-1-86189-795-4") diff --git a/tests/testthat.R b/tests/testthat.R index 74b686b..3c5b203 100755 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,4 +1,5 @@ library(testthat) library(libbib) +library(data.table) test_check("libbib") diff --git a/tests/testthat/setup.R b/tests/testthat/setup.R new file mode 100644 index 0000000..96fc90c --- /dev/null +++ b/tests/testthat/setup.R @@ -0,0 +1 @@ +library(data.table) From 5097e2a53e3de1c9085ac0d8de48c1fd64409131 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Tue, 18 Aug 2026 23:48:51 +0000 Subject: [PATCH 2/4] Prune library(data.table) to only examples that require it --- R/special-attributes.R | 5 - R/split-map-filter-reduce.R | 3 - R/utilities.R | 1 - libbib.Rcheck/00_pkg_src/libbib/DESCRIPTION | 25 + libbib.Rcheck/00_pkg_src/libbib/Makefile | 52 + libbib.Rcheck/00_pkg_src/libbib/NAMESPACE | 76 + libbib.Rcheck/00_pkg_src/libbib/NEWS.md | 149 ++ libbib.Rcheck/00_pkg_src/libbib/R/bibcodes.R | 899 ++++++++ .../libbib/R/books_serials_etc_sample_data.R | 17 + .../libbib/R/call-numbers-and-subject.R | 414 ++++ .../libbib/R/country_code_crosswalk-data.R | 16 + .../libbib/R/dewey_subject_crosswalk-data.R | 16 + .../libbib/R/language_code_crosswalk-data.R | 16 + .../libbib/R/lc_subject_classification-data.R | 16 + .../R/lc_subject_subclassification-data.R | 16 + .../libbib/R/marc-field-deconstruction.R | 142 ++ .../libbib/R/other-code-translations.R | 85 + .../00_pkg_src/libbib/R/special-attributes.R | 295 +++ .../libbib/R/split-map-filter-reduce.R | 216 ++ libbib.Rcheck/00_pkg_src/libbib/R/the-web.R | 217 ++ libbib.Rcheck/00_pkg_src/libbib/R/utilities.R | 502 +++++ .../00_pkg_src/libbib/R/worldcat-api.R | 1148 ++++++++++ libbib.Rcheck/00_pkg_src/libbib/README.md | 284 +++ .../00_pkg_src/libbib/build/vignette.rds | Bin 0 -> 234 bytes .../libbib/data/books_serials_etc_sample.rda | Bin 0 -> 3392 bytes .../libbib/data/country_code_crosswalk.rda | Bin 0 -> 4285 bytes .../libbib/data/dewey_subject_crosswalk.rda | Bin 0 -> 13418 bytes .../libbib/data/language_code_crosswalk.rda | Bin 0 -> 5077 bytes .../libbib/data/lc_subject_classification.rda | Bin 0 -> 545 bytes .../data/lc_subject_subclassification.rda | Bin 0 -> 7537 bytes .../inst/doc/using-the-worldcat-search-api.R | 272 +++ .../doc/using-the-worldcat-search-api.Rmd | 991 +++++++++ .../doc/using-the-worldcat-search-api.html | 1345 ++++++++++++ .../libbib/man/books_serials_etc_sample.Rd | 20 + libbib.Rcheck/00_pkg_src/libbib/man/car.Rd | 31 + .../libbib/man/check_isbn_10_check_digit.Rd | 34 + .../libbib/man/check_isbn_13_check_digit.Rd | 34 + .../libbib/man/check_issn_check_digit.Rd | 36 + .../libbib/man/convert_to_isbn_13.Rd | 32 + .../libbib/man/country_code_crosswalk.Rd | 20 + .../00_pkg_src/libbib/man/cp_lb_attributes.Rd | 35 + .../libbib/man/dewey_subject_crosswalk.Rd | 20 + .../libbib/man/dt_add_to_col_names.Rd | 71 + .../libbib/man/dt_counts_and_percents.Rd | 55 + .../00_pkg_src/libbib/man/dt_del_cols.Rd | 26 + .../00_pkg_src/libbib/man/dt_keep_cols.Rd | 26 + .../00_pkg_src/libbib/man/dt_na_breakdown.Rd | 43 + .../libbib/man/dt_percent_not_na.Rd | 33 + .../libbib/man/dt_set_clean_names.Rd | 38 + .../00_pkg_src/libbib/man/fread_plus_date.Rd | 63 + .../00_pkg_src/libbib/man/fwrite_plus_date.Rd | 71 + .../man/get_all_lc_call_subject_letters.Rd | 35 + .../00_pkg_src/libbib/man/get_clean_names.Rd | 42 + .../libbib/man/get_country_from_code.Rd | 34 + .../man/get_dewey_decimal_subject_class.Rd | 34 + .../man/get_dewey_decimal_subject_division.Rd | 34 + .../man/get_dewey_decimal_subject_section.Rd | 36 + .../libbib/man/get_isbn_10_check_digit.Rd | 42 + .../libbib/man/get_isbn_13_check_digit.Rd | 41 + .../libbib/man/get_issn_check_digit.Rd | 41 + .../libbib/man/get_language_from_code.Rd | 30 + .../libbib/man/get_lc_call_first_letter.Rd | 35 + .../man/get_lc_call_subject_classification.Rd | 70 + .../00_pkg_src/libbib/man/is_valid_isbn_10.Rd | 38 + .../00_pkg_src/libbib/man/is_valid_isbn_13.Rd | 33 + .../00_pkg_src/libbib/man/is_valid_issn.Rd | 39 + .../00_pkg_src/libbib/man/is_valid_lc_call.Rd | 37 + .../libbib/man/language_code_crosswalk.Rd | 20 + .../libbib/man/lc_subject_classification.Rd | 20 + .../man/lc_subject_subclassification.Rd | 20 + .../libbib/man/loc_permalink_from_lccn.Rd | 45 + .../libbib/man/marc_008_get_info.Rd | 63 + .../libbib/man/marc_leader_get_info.Rd | 35 + .../00_pkg_src/libbib/man/normalize_isbn.Rd | 54 + .../libbib/man/normalize_isbn_10.Rd | 49 + .../libbib/man/normalize_isbn_13.Rd | 43 + .../00_pkg_src/libbib/man/normalize_issn.Rd | 55 + .../00_pkg_src/libbib/man/normalize_lccn.Rd | 45 + .../oclc_classify_link_from_standard_num.Rd | 39 + .../libbib/man/recombine_with_sep_closure.Rd | 39 + .../libbib/man/remove_duplicates_and_nas.Rd | 33 + .../00_pkg_src/libbib/man/set_lb_attribute.Rd | 34 + .../00_pkg_src/libbib/man/set_lb_date.Rd | 29 + .../libbib/man/split_map_filter_reduce.Rd | 111 + .../man/worldcat_api_bib_read_info_by.Rd | 110 + .../libbib/man/worldcat_api_classify_by.Rd | 89 + .../libbib/man/worldcat_api_locations_by.Rd | 175 ++ .../libbib/man/worldcat_api_search.Rd | 132 ++ .../man/worldcat_permalink_from_isbn.Rd | 42 + .../man/worldcat_permalink_from_issn.Rd | 36 + .../worldcat_permalink_from_oclc_number.Rd | 31 + .../00_pkg_src/libbib/tests/testthat.R | 4 + .../libbib/tests/testthat/test-bibcodes.R | 422 ++++ .../testthat/test-call-numbers-and-subject.R | 177 ++ .../testthat/test-marc-field-deconstruction.R | 21 + .../testthat/test-other-code-translations.R | 25 + .../testthat/test-split-map-filter-reduce.R | 85 + .../libbib/tests/testthat/test-the-web.R | 94 + .../libbib/tests/testthat/test-utilities.R | 106 + .../libbib/tests/testthat/test-worldcat-api.R | 121 ++ .../using-the-worldcat-search-api.Rmd | 991 +++++++++ libbib.Rcheck/00check.log | 93 + libbib.Rcheck/R_check_bin/R | 2 + libbib.Rcheck/R_check_bin/Rscript | 2 + libbib.Rcheck/Rdlatex.log | 515 +++++ libbib.Rcheck/libbib-Ex.R | 1573 ++++++++++++++ libbib.Rcheck/libbib-Ex.Rout | 1860 +++++++++++++++++ libbib.Rcheck/libbib-Ex.pdf | Bin 0 -> 3611 bytes libbib.Rcheck/libbib-Ex.timings | 53 + libbib.Rcheck/libbib-manual.log | 593 ++++++ libbib.Rcheck/libbib-manual.pdf | Bin 0 -> 195491 bytes libbib.Rcheck/libbib/DESCRIPTION | 26 + libbib.Rcheck/libbib/INDEX | 113 + libbib.Rcheck/libbib/Meta/Rd.rds | Bin 0 -> 2392 bytes libbib.Rcheck/libbib/Meta/data.rds | Bin 0 -> 301 bytes libbib.Rcheck/libbib/Meta/features.rds | Bin 0 -> 122 bytes libbib.Rcheck/libbib/Meta/hsearch.rds | Bin 0 -> 2125 bytes libbib.Rcheck/libbib/Meta/links.rds | Bin 0 -> 1069 bytes libbib.Rcheck/libbib/Meta/nsInfo.rds | Bin 0 -> 851 bytes libbib.Rcheck/libbib/Meta/package.rds | Bin 0 -> 1144 bytes libbib.Rcheck/libbib/Meta/vignette.rds | Bin 0 -> 234 bytes libbib.Rcheck/libbib/NAMESPACE | 76 + libbib.Rcheck/libbib/NEWS.md | 149 ++ libbib.Rcheck/libbib/R/libbib | 27 + libbib.Rcheck/libbib/R/libbib.rdb | Bin 0 -> 105225 bytes libbib.Rcheck/libbib/R/libbib.rdx | Bin 0 -> 1574 bytes libbib.Rcheck/libbib/README.md | 284 +++ .../libbib/data/books_serials_etc_sample.rda | Bin 0 -> 3392 bytes .../libbib/data/country_code_crosswalk.rda | Bin 0 -> 4285 bytes .../libbib/data/dewey_subject_crosswalk.rda | Bin 0 -> 13418 bytes .../libbib/data/language_code_crosswalk.rda | Bin 0 -> 5077 bytes .../libbib/data/lc_subject_classification.rda | Bin 0 -> 545 bytes .../data/lc_subject_subclassification.rda | Bin 0 -> 7537 bytes libbib.Rcheck/libbib/doc/index.html | 30 + .../doc/using-the-worldcat-search-api.R | 272 +++ .../doc/using-the-worldcat-search-api.Rmd | 991 +++++++++ .../doc/using-the-worldcat-search-api.html | 1345 ++++++++++++ libbib.Rcheck/libbib/help/AnIndex | 67 + libbib.Rcheck/libbib/help/aliases.rds | Bin 0 -> 728 bytes libbib.Rcheck/libbib/help/libbib.rdb | Bin 0 -> 118452 bytes libbib.Rcheck/libbib/help/libbib.rdx | Bin 0 -> 1583 bytes libbib.Rcheck/libbib/help/paths.rds | Bin 0 -> 785 bytes libbib.Rcheck/libbib/html/00Index.html | 162 ++ libbib.Rcheck/libbib/html/R.css | 142 ++ libbib.Rcheck/tests/startup.Rs | 4 + libbib.Rcheck/tests/testthat.R | 4 + libbib.Rcheck/tests/testthat.Rout | 26 + libbib.Rcheck/tests/testthat/test-bibcodes.R | 422 ++++ .../testthat/test-call-numbers-and-subject.R | 177 ++ .../testthat/test-marc-field-deconstruction.R | 21 + .../testthat/test-other-code-translations.R | 25 + .../testthat/test-split-map-filter-reduce.R | 85 + libbib.Rcheck/tests/testthat/test-the-web.R | 94 + libbib.Rcheck/tests/testthat/test-utilities.R | 106 + .../tests/testthat/test-worldcat-api.R | 121 ++ libbib_1.6.4.tar.gz | Bin 0 -> 143689 bytes man/cp_lb_attributes.Rd | 1 - man/fread_plus_date.Rd | 1 - man/fwrite_plus_date.Rd | 1 - man/get_clean_names.Rd | 1 - man/recombine_with_sep_closure.Rd | 1 - man/remove_duplicates_and_nas.Rd | 1 - man/set_lb_attribute.Rd | 1 - man/set_lb_date.Rd | 1 - man/split_map_filter_reduce.Rd | 1 - tests/testthat.R | 1 - tests/testthat/setup.R | 1 - 167 files changed, 21373 insertions(+), 20 deletions(-) create mode 100755 libbib.Rcheck/00_pkg_src/libbib/DESCRIPTION create mode 100644 libbib.Rcheck/00_pkg_src/libbib/Makefile create mode 100644 libbib.Rcheck/00_pkg_src/libbib/NAMESPACE create mode 100644 libbib.Rcheck/00_pkg_src/libbib/NEWS.md create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/bibcodes.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/books_serials_etc_sample_data.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/call-numbers-and-subject.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/country_code_crosswalk-data.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/dewey_subject_crosswalk-data.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/language_code_crosswalk-data.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_classification-data.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_subclassification-data.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/marc-field-deconstruction.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/other-code-translations.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/special-attributes.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/split-map-filter-reduce.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/the-web.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/utilities.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/R/worldcat-api.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/README.md create mode 100644 libbib.Rcheck/00_pkg_src/libbib/build/vignette.rds create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/books_serials_etc_sample.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/country_code_crosswalk.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/dewey_subject_crosswalk.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/language_code_crosswalk.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_classification.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_subclassification.rda create mode 100644 libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.Rmd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.html create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/books_serials_etc_sample.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/car.Rd create mode 100755 libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_10_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_13_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/check_issn_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/convert_to_isbn_13.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/country_code_crosswalk.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/cp_lb_attributes.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dewey_subject_crosswalk.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_add_to_col_names.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_counts_and_percents.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_del_cols.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_keep_cols.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_na_breakdown.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_percent_not_na.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/dt_set_clean_names.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/fread_plus_date.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/fwrite_plus_date.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_all_lc_call_subject_letters.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_clean_names.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_country_from_code.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_class.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_division.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_section.Rd create mode 100755 libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_10_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_13_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_issn_check_digit.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_language_from_code.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_first_letter.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_subject_classification.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_10.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_13.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/is_valid_issn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/is_valid_lc_call.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/language_code_crosswalk.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_classification.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_subclassification.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/loc_permalink_from_lccn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/marc_008_get_info.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/marc_leader_get_info.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_10.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_13.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/normalize_issn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/normalize_lccn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/oclc_classify_link_from_standard_num.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/recombine_with_sep_closure.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/remove_duplicates_and_nas.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/set_lb_attribute.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/set_lb_date.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/split_map_filter_reduce.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_bib_read_info_by.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_classify_by.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_locations_by.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_search.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_isbn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_issn.Rd create mode 100644 libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_oclc_number.Rd create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-bibcodes.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-call-numbers-and-subject.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-marc-field-deconstruction.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-other-code-translations.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-split-map-filter-reduce.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-the-web.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-utilities.R create mode 100755 libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-worldcat-api.R create mode 100644 libbib.Rcheck/00_pkg_src/libbib/vignettes/using-the-worldcat-search-api.Rmd create mode 100644 libbib.Rcheck/00check.log create mode 100755 libbib.Rcheck/R_check_bin/R create mode 100755 libbib.Rcheck/R_check_bin/Rscript create mode 100644 libbib.Rcheck/Rdlatex.log create mode 100644 libbib.Rcheck/libbib-Ex.R create mode 100644 libbib.Rcheck/libbib-Ex.Rout create mode 100644 libbib.Rcheck/libbib-Ex.pdf create mode 100644 libbib.Rcheck/libbib-Ex.timings create mode 100644 libbib.Rcheck/libbib-manual.log create mode 100644 libbib.Rcheck/libbib-manual.pdf create mode 100644 libbib.Rcheck/libbib/DESCRIPTION create mode 100644 libbib.Rcheck/libbib/INDEX create mode 100644 libbib.Rcheck/libbib/Meta/Rd.rds create mode 100644 libbib.Rcheck/libbib/Meta/data.rds create mode 100644 libbib.Rcheck/libbib/Meta/features.rds create mode 100644 libbib.Rcheck/libbib/Meta/hsearch.rds create mode 100644 libbib.Rcheck/libbib/Meta/links.rds create mode 100644 libbib.Rcheck/libbib/Meta/nsInfo.rds create mode 100644 libbib.Rcheck/libbib/Meta/package.rds create mode 100644 libbib.Rcheck/libbib/Meta/vignette.rds create mode 100644 libbib.Rcheck/libbib/NAMESPACE create mode 100644 libbib.Rcheck/libbib/NEWS.md create mode 100644 libbib.Rcheck/libbib/R/libbib create mode 100644 libbib.Rcheck/libbib/R/libbib.rdb create mode 100644 libbib.Rcheck/libbib/R/libbib.rdx create mode 100644 libbib.Rcheck/libbib/README.md create mode 100644 libbib.Rcheck/libbib/data/books_serials_etc_sample.rda create mode 100644 libbib.Rcheck/libbib/data/country_code_crosswalk.rda create mode 100644 libbib.Rcheck/libbib/data/dewey_subject_crosswalk.rda create mode 100644 libbib.Rcheck/libbib/data/language_code_crosswalk.rda create mode 100644 libbib.Rcheck/libbib/data/lc_subject_classification.rda create mode 100644 libbib.Rcheck/libbib/data/lc_subject_subclassification.rda create mode 100644 libbib.Rcheck/libbib/doc/index.html create mode 100644 libbib.Rcheck/libbib/doc/using-the-worldcat-search-api.R create mode 100644 libbib.Rcheck/libbib/doc/using-the-worldcat-search-api.Rmd create mode 100644 libbib.Rcheck/libbib/doc/using-the-worldcat-search-api.html create mode 100644 libbib.Rcheck/libbib/help/AnIndex create mode 100644 libbib.Rcheck/libbib/help/aliases.rds create mode 100644 libbib.Rcheck/libbib/help/libbib.rdb create mode 100644 libbib.Rcheck/libbib/help/libbib.rdx create mode 100644 libbib.Rcheck/libbib/help/paths.rds create mode 100644 libbib.Rcheck/libbib/html/00Index.html create mode 100644 libbib.Rcheck/libbib/html/R.css create mode 100644 libbib.Rcheck/tests/startup.Rs create mode 100755 libbib.Rcheck/tests/testthat.R create mode 100644 libbib.Rcheck/tests/testthat.Rout create mode 100755 libbib.Rcheck/tests/testthat/test-bibcodes.R create mode 100755 libbib.Rcheck/tests/testthat/test-call-numbers-and-subject.R create mode 100755 libbib.Rcheck/tests/testthat/test-marc-field-deconstruction.R create mode 100755 libbib.Rcheck/tests/testthat/test-other-code-translations.R create mode 100755 libbib.Rcheck/tests/testthat/test-split-map-filter-reduce.R create mode 100755 libbib.Rcheck/tests/testthat/test-the-web.R create mode 100755 libbib.Rcheck/tests/testthat/test-utilities.R create mode 100755 libbib.Rcheck/tests/testthat/test-worldcat-api.R create mode 100644 libbib_1.6.4.tar.gz delete mode 100644 tests/testthat/setup.R diff --git a/R/special-attributes.R b/R/special-attributes.R index 62509cc..682da92 100755 --- a/R/special-attributes.R +++ b/R/special-attributes.R @@ -17,7 +17,6 @@ #' @return Nothing, since the object is modified by reference. #' #' @examples -#' library(data.table) #' set_lb_attribute(mtcars, "source", "R built-in dataset") #' #' versicolor <- iris[iris$Species=="versicolor", ] @@ -45,7 +44,6 @@ set_lb_attribute <- function(x, type, value){ #' @return Nothing, since the object is modified by reference. #' #' @examples -#' library(data.table) #' set_lb_date(mtcars, "2021-05-08") #' attributes(mtcars)$lb.date #' # [1] "2021-05-08 @@ -76,7 +74,6 @@ set_lb_date <- function(x, value){ #' @return Nothing, since the object is modified by reference. #' #' @examples -#' library(data.table) #' #' tmp1 <- "a" #' set_lb_date(tmp1, "2021-05-08") @@ -177,7 +174,6 @@ fread_plus_helper <- function(fname){ #' @return A \code{data.table} with an attribute called \code{lb.date} set #' #' @examples -#' library(data.table) #' \dontrun{ #' # there's a file called "iris-2021-05-08.csv" on disk #' dat <- fread_plus_date("iris.csv") @@ -266,7 +262,6 @@ fread_plus_date <- function(fname, allow.fallback.date=TRUE, ...){ #' @param ... Arbitrary arguments to pass to \code{fwrite} #' #' @examples -#' library(data.table) #' \dontrun{ #' #' set_lb_date(iris, "2021-05-08") diff --git a/R/split-map-filter-reduce.R b/R/split-map-filter-reduce.R index 2b83601..772fa1c 100755 --- a/R/split-map-filter-reduce.R +++ b/R/split-map-filter-reduce.R @@ -42,7 +42,6 @@ car <- function(x){ #' @seealso \code{\link{split_map_filter_reduce}} #' #' @examples -#' library(data.table) #' #' remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) #' # 8 6 7 5 3 0 9 @@ -77,7 +76,6 @@ remove_duplicates_and_nas <- function(x){ #' @seealso \code{\link{paste}} #' #' @examples -#' library(data.table) #' #' lambda <- recombine_with_sep_closure() #' lambda(c(8, 6, 7)) # "8;6;7" @@ -153,7 +151,6 @@ recombine_with_sep_closure <- function(sep=";"){ #' @seealso \code{\link{recombine_with_sep_closure}} #' #' @examples -#' library(data.table) #' #' someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", #' "1861897952; 978-1-86189-795-4") diff --git a/R/utilities.R b/R/utilities.R index 8b3ba18..d761264 100755 --- a/R/utilities.R +++ b/R/utilities.R @@ -199,7 +199,6 @@ dt_counts_and_percents <- function(DT, group_by_this, percent.cutoff=0, #' @seealso \code{\link{make.unique}} #' #' @examples -#' library(data.table) #' ejemplo <- iris #' names(ejemplo) <- c("Sepal Length", "Sepal@Width", "Petal Length", #' "Petal\\nWidth", "SpĂȘcies") diff --git a/libbib.Rcheck/00_pkg_src/libbib/DESCRIPTION b/libbib.Rcheck/00_pkg_src/libbib/DESCRIPTION new file mode 100755 index 0000000..89efb07 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/DESCRIPTION @@ -0,0 +1,25 @@ +Package: libbib +Type: Package +Title: Various Utilities for Library Science/Assessment and Cataloging +Version: 1.6.4 +Authors@R: person("Tony", "Fischetti", + email="tony.fischetti@gmail.com", + role=c("aut", "cre")) +Maintainer: Tony Fischetti +Description: Provides functions for validating and normalizing bibliographic + codes such as ISBN, ISSN, and LCCN. Also includes functions to communicate + with the WorldCat API, translate Call numbers (Library of Congress and + Dewey Decimal) to their subject classifications or subclassifications, + and provides various loadable data files such call number / subject + crosswalks and code tables. +License: GPL-3 +Depends: R (>= 3.5.0), utils +Imports: curl, data.table, methods, pbapply, stringr, xml2 +Suggests: assertr, testthat, knitr, magrittr, rmarkdown +Encoding: UTF-8 +VignetteBuilder: knitr +NeedsCompilation: no +Packaged: 2026-08-18 23:47:57 UTC; chiricom +Author: Tony Fischetti [aut, cre] +URL: https://github.com/NYPL/libbib +Config/roxygen2/version: 8.0.0 diff --git a/libbib.Rcheck/00_pkg_src/libbib/Makefile b/libbib.Rcheck/00_pkg_src/libbib/Makefile new file mode 100644 index 0000000..19b36b6 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/Makefile @@ -0,0 +1,52 @@ + +.DELETE_ON_ERROR: + + +.PHONY: all clean mrproper dist check test install begin help done verify + +load_all: + Rscript -e 'devtools::load_all(".")' + +install: + cd ../ && R CMD INSTALL --preclean --no-multiarch --with-keep.source libbib + +test: + Rscript -e 'devtools::test()' + +check: + Rscript -e 'devtools::check(document = FALSE, args = c("--no-manual"))' + +check_doc: + Rscript -e 'devtools::check_man()' + +check_rhub: + Rscript -e 'devtools::check_rhub()' + +check_win_devel: + Rscript -e 'devtools::check_win_devel()' + +check_win_release: + Rscript -e 'devtools::check_win_release()' + +check_win_oldrelease: + Rscript -e 'devtools::check_win_oldrelease()' + +build_vignettes: + Rscript -e 'devtools::build_vignettes()' + +build_manual: + Rscript -e 'devtools::build_manual()' + +document: + Rscript -e 'devtools::document()' + +build_src: + Rscript -e 'devtools::build()' + +build_bin: + Rscript -e 'devtools::build(binary = TRUE, args = c("--preclean"))' + +# submit: +# Rscript -e 'devtools::submit_cran()' + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/NAMESPACE b/libbib.Rcheck/00_pkg_src/libbib/NAMESPACE new file mode 100644 index 0000000..97a156a --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/NAMESPACE @@ -0,0 +1,76 @@ +# Generated by roxygen2: do not edit by hand + +export(car) +export(check_isbn_10_check_digit) +export(check_isbn_13_check_digit) +export(check_issn_check_digit) +export(convert_to_isbn_13) +export(cp_lb_attributes) +export(dt_add_to_col_names) +export(dt_counts_and_percents) +export(dt_del_cols) +export(dt_keep_cols) +export(dt_na_breakdown) +export(dt_percent_not_na) +export(dt_set_clean_names) +export(fread_plus_date) +export(fwrite_plus_date) +export(get_all_lc_call_subject_letters) +export(get_clean_names) +export(get_country_from_code) +export(get_dewey_decimal_subject_class) +export(get_dewey_decimal_subject_division) +export(get_dewey_decimal_subject_section) +export(get_isbn_10_check_digit) +export(get_isbn_13_check_digit) +export(get_issn_check_digit) +export(get_language_from_code) +export(get_lc_call_first_letter) +export(get_lc_call_subject_classification) +export(is_valid_isbn_10) +export(is_valid_isbn_13) +export(is_valid_issn) +export(is_valid_lc_call) +export(loc_permalink_from_lccn) +export(marc_008_get_info) +export(marc_leader_get_info) +export(normalize_isbn) +export(normalize_isbn_10) +export(normalize_isbn_13) +export(normalize_issn) +export(normalize_lccn) +export(oclc_classify_link_from_standard_num) +export(recombine_with_sep_closure) +export(remove_duplicates_and_nas) +export(set_lb_attribute) +export(set_lb_date) +export(split_map_filter_reduce) +export(worldcat_api_bib_read_info_by_isbn) +export(worldcat_api_bib_read_info_by_issn) +export(worldcat_api_bib_read_info_by_oclc) +export(worldcat_api_classify_by_isbn) +export(worldcat_api_classify_by_issn) +export(worldcat_api_classify_by_oclc) +export(worldcat_api_locations_by_isbn) +export(worldcat_api_locations_by_issn) +export(worldcat_api_locations_by_oclc) +export(worldcat_api_search) +export(worldcat_permalink_from_isbn) +export(worldcat_permalink_from_issn) +export(worldcat_permalink_from_oclc_number) +import(pbapply) +import(utils) +importFrom(data.table,"%chin%") +importFrom(data.table,":=") +importFrom(data.table,.N) +importFrom(data.table,as.data.table) +importFrom(data.table,copy) +importFrom(data.table,data.table) +importFrom(data.table,fcase) +importFrom(data.table,fread) +importFrom(data.table,fwrite) +importFrom(data.table,rbindlist) +importFrom(data.table,setattr) +importFrom(data.table,setcolorder) +importFrom(data.table,setindex) +importFrom(data.table,setnames) diff --git a/libbib.Rcheck/00_pkg_src/libbib/NEWS.md b/libbib.Rcheck/00_pkg_src/libbib/NEWS.md new file mode 100644 index 0000000..e27301a --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/NEWS.md @@ -0,0 +1,149 @@ + +**If you are viewing this file on CRAN, please check +[latest news on GitHub](https://github.com/NYPL/libbib/blob/master/NEWS.md) +where the formatting is better.** + +# libbib 1.7 (in development) + +1. Nothing yet + +# libbib 1.6.4 + +1. Bug fix in `dt_counts_and_percents` wherein if the group by column + was not a character or a factor, the "TOTAL"", and "OTHER" rows would + be NA. + +2. Fixed a bug in `get_clean_names` (and, by extension, `dt_set_clean_names`) + where "0" was accidentally excluded from the whitelisted character set. + +# libbib 1.6.2 + +## new features + +1. Functions `fread_plus_date`, `fwrite_plus_date`, `set_lb_attribute`, + `set_lb_date`, and `cp_lb_attributes` to read/write files with + special date attribute and work with date and other special + attributes. + +## bug fixes + +1. LC call number functions now call str_trim before anything + + +# libbib 1.6 + +## new features + +1. Wrote a translation layer to translate more human-readable aliases + of every WorldCat SRU search index to their formal name. The + `worldcat_api_search` function now uses this by default. You can still use + the formal names, and even mix codes in the same query. The function + documentation has been updated to reflect these new aliases. + +2. A vignette on how to use the WorldCat search API is now available + with a ton of very useful information. + +3. Added `dt_na_breakdown` function. + +## bug fixes +1. `print.progress` conditional now works for Location and Search API functions + +2. Fixed a bug where if the number of search results was an exact multiple + of 100, the search api function wouldn't return anything + +## improvements + +1. WorldCat API functions will now error if no WSKEY is provided + (either with `options("libbib.wskey"=...)` or explicitly + in the formal parameters + +2. WorldCat Search function now tolerant of newlines and multiple + spaces. Now long queries can be look neat + +3. More of the diagnostic output now uses `message` instead of `print` or `cat` + +4. If no Search API results are returned, the function prints the any + diagnostic message returned from the Search API + (things like Query syntax operators and unsupported indexes) + +5. `get_clean_names` and `dt_set_clean_names` will now never produce + duplicate column names + +6. `dt_keep_cols` will warn user if a supplied column name doesn't + exist in the supplied data.table + +7. `dt_add_to_col_names` will, by default, error if any of the new + names create any duplicate column names (not setting the new + names). If `TRUE`, all the column names are made unique, + potentially renaming excluded column names that were not supposed + to be changed. + +8. Added option in `dt_counts_and_percents` (and `dt_na_breakdown`) + to specify a `big.mark` which will be used to separate every + three digits of the count. If `FALSE` (the default) the count + will remain and integer. + +## small breaking changes + +1. `marc_008_get_info` no longer returns the original publication + date by default + +2. excluding "questionable dates" in `marc_008_get_info` just NAs + character position 6="q", now + +3. The `print.api.responses` parameter in the Classify API functions has + been changed to `debug` to be more consistent with the other API functions. + +4. `num_total` column in search results has been renamed the (more descriptive) + `total_wc_results` + +5. By default, `get_clean_names` and `dt_set_clean_names` will convert + all upper case characters to lower case. This can be overidden with + by setting the `lower` parameter (in both) to `FALSE`. + +----- + +# libbib 1.5 (on CRAN 2021-04-24) + +## new features + +1. Implemented Dewey Decimal Code to subject translation + +2. Added various helpful utility functions + +3. Added split_map_filter_reduce and related utilities + +4. Added functions to get language and country names from + corresponding Marc codes + +5. Added function to get links to OCLC's classify service + +6. Added ability to link directly to MARCXML, MODS, MADS, or + Dublin Core metadata formats in `loc_permalink_from_lccn` + +7. Added functions to use the WorldCat Bib Read API, + read/parse the returned MARCXml, and return a `data.table` + containing the most pertinent information. + +8. Added functions to use the WorldCat Classify API and return a + `data.table` containing the most popular Dewey and LC call numbers. + +9. Added functions to use the WorldCat Location API and return a + `data.table` containing (optionally, all) of the holding libraries + for that standard number. + +10. Added functions to extract info from MARC leaders and 008 fields + +11. Added functions to use the WorldCat SRU search API and return a + `data.table` containing (optionally, all) of the results. + +## bug fixes + +1. Expanded lc call <-> subject crosswalk (mainly for 'Law') + +2. Fixed bugs in lc call <-> subject translation mechanism + +## improvements + +1. performance of `is_valid_lc_call` improved + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/bibcodes.R b/libbib.Rcheck/00_pkg_src/libbib/R/bibcodes.R new file mode 100755 index 0000000..b54b919 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/bibcodes.R @@ -0,0 +1,899 @@ + + +# regular expression patterns +REGEX.ISBN.10.9 <- "^(\\d{9,10}|\\d{9}[xX])$" +REGEX.ISBN.10.flex <- "^\\d{9}(x|X|\\d)$" +REGEX.ISBN.10 <- "^\\d{9}(X|\\d)$" + +REGEX.ISBN.13.12 <- "^\\d{12,13}$" +REGEX.ISBN.13 <- "^\\d{13}$" + +REGEX.ISSN.8.7 <- "^(\\d{7,8}|\\d{7}[xX])$" +REGEX.ISSN.flex <- "^\\d{7}(x|X|\\d)$" +REGEX.ISSN <- "^\\d{7}(X|\\d)$" + + + +############################################## +### ISBN 10 ### +############################################## + +#' Get ISBN 10 check digit +#' +#' Takes a string representation of an ISBN 10 +#' and returns the check digit that satisfies the necessary condition. +#' It can take a 10 digit string (and ignore the already extant check digit) +#' or a 9 digit string (without the last digit) +#' +#' @param x A string of 9 or 10 digits +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{FALSE}) +#' @param errors.as.nas return NA if error instead of throwing error +#' (default is \code{FALSE}) +#' +#' @return Returns the character check digit that satifies the +#' mod 11 condition. Returns "X" if 10. Returns NA if input is NA +#' @examples +#' +#' get_isbn_10_check_digit("012491540X") +#' get_isbn_10_check_digit("0-124-91540-X", allow.hyphens=TRUE) +#' +#' # nine digit string +#' get_isbn_10_check_digit("900403781") +#' +#' get_isbn_10_check_digit("onetwothre", errors.as.nas=TRUE) # NA +#' +#' # vectorized +#' get_isbn_10_check_digit(c("012491540X", "9004037810", "900403781")) +#' +#' @export +get_isbn_10_check_digit <- function(x, allow.hyphens=FALSE, errors.as.nas=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + if(any(!(nchar(x[!is.na(x)]) %in% c(9, 10))>0)) + if(!errors.as.nas) stop("Input must be either 9 or 10 characters") + where.bad <- !grepl(REGEX.ISBN.10.9, x, perl=TRUE) & !is.na(x) + if(any(where.bad)){ + if(!errors.as.nas) stop("Illegal input") + x[where.bad] <- NA + } + if(any(!where.bad)){ + first9 <- stringr::str_split(substr(x[!where.bad], 1, 9), "", simplify=TRUE) + class(first9) <- "numeric" + first9 <- as.numeric(first9 %*% matrix(10:2)) + should.be <- (11 - (first9 %% 11)) %% 11 + ret <- ifelse(should.be==10, "X", as.character(should.be)) + x[!where.bad] <- ret + } + x +} + + +#' Check the check digit of an ISBN 10 +#' +#' Takes a string representation of an ISBN 10 and verifies that check digit +#' checks out +#' +#' @param x A string of 10 digits or 9 digits with terminal "X" +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{FALSE}) +#' @param errors.as.false return false if error instead of throwing error +#' (default is \code{TRUE}) +#' +#' @return Returns TRUE if check passes, FALSE if not, and NA if NA +#' +#' @examples +#' +#' check_isbn_10_check_digit("012491540X") # TRUE +#' check_isbn_10_check_digit("0-124-91540-X") # TRUE +#' +#' # vectorized +#' check_isbn_10_check_digit(c("012491540X", "9004037812")) # TRUE FALSE +#' +#' @export +check_isbn_10_check_digit <- function(x, allow.hyphens=TRUE, errors.as.false=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + if(errors.as.false) + return(rep(FALSE, length(x))) + stop("Input must be a character string") + } + x <- toupper(x) + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + where.bad <- !grepl(REGEX.ISBN.10, x, perl=TRUE) & !is.na(x) + if(any(where.bad)){ + if(!errors.as.false) stop("Illegal input") + } + check.digit <- stringr::str_sub(x, -1) + should.be <- get_isbn_10_check_digit(x, errors.as.nas = errors.as.false) + ret <- ifelse(should.be==check.digit, TRUE, FALSE) + ret[where.bad] <- FALSE + return(ret) +} + + +#' Return TRUE if valid ISBN 10 +#' +#' Takes a string representation of an ISBN 10 verifies that it is valid. +#' An ISBN 10 is valid if it is a 10 digit string or a 9 digit string +#' with a terminal "X" AND the check digit matches +#' +#' @param x A string of 10 digits or 9 digits with terminal "X" +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{TRUE}) +#' @param lower.x.allowed A logical indicating whether ISBN 10s with +#' a check digit with a lower-case "x" should +#' be treated as valid +#' (default is \code{TRUE}) +#' +#' @return Returns TRUE if checks pass, FALSE if not, and NA if NA +#' @examples +#' +#' is_valid_isbn_10("012491540X") # TRUE +#' is_valid_isbn_10("0-124-91540-X") # TRUE +#' +#' # vectorized +#' is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +#' is_valid_isbn_10(c("012491540X", "hubo un tiempo")) # TRUE FALSE +#' +#' @export +is_valid_isbn_10 <- function(x, allow.hyphens=TRUE, lower.x.allowed=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + stop("Input must be a character string") + } + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + CHECKREGEX <- REGEX.ISBN.10 + if(lower.x.allowed) + CHECKREGEX <- REGEX.ISBN.10.flex + where.bad <- !grepl(CHECKREGEX, x, perl=TRUE) & !is.na(x) + x[where.bad] <- NA + ret <- ifelse(check_isbn_10_check_digit(x, errors.as.false=TRUE), TRUE, FALSE) + ret[is.na(x)] <- NA + ret[where.bad] <- FALSE + return(ret) +} +attr(is_valid_isbn_10, "assertr_vectorized") <- TRUE + + + +#' Attempt to enforce validity and canonical form to ISBN 10 +#' +#' Takes a string representation of an ISBN 10. Strips all non-digit +#' and non-"X" characters and checks if it is valid (whether the +#' check digit works out, etc). User can specify whether "aggressive" +#' measures should be taken to salvage the malformed ISBN 10 string. +#' +#' @param x A string +#' @param aggressive A logical indicating whether aggressive measures +#' should be taken to try to get the "ISBN 10" +#' into a valid form. See "Details" for more info +#' (default is \code{TRUE}) +#' @param convert.to.isbn.13 A logical indicating whether the ISBN 10 +#' should be converted into an ISBN 13 +#' (default is \code{FALSE}) +#' +#' @details If \code{aggressive} is TRUE, aggressive measures are taken to +#' try to salvage the malformed ISBN 10 string. If the ISBN 10, for example, +#' is 9 digits, and either adding an "X" to the end, or leading "0"s fix it, +#' this function will return the salvaged ISBN 10. If the ISBN 10 has +#' garbage digits/characters in the front and has an "X" check digit, +#' it will return the salvaged ISBN 10. +#' +#' @return Returns valid ISBN 10 if possible, NA if not +#' @examples +#' +#' normalize_isbn_10("012491540x") # "012491540X" +#' normalize_isbn_10("012491540x xe32ea") # "012491540X" +#' normalize_isbn_10("012491540x", convert.to.isbn.13=TRUE) +#' # "9780124915404" +#' normalize_isbn_10("513213012491540x") # "012491540X" +#' +#' @seealso \code{\link{normalize_isbn}} \code{\link{normalize_isbn_13}} +#' +#' @export +normalize_isbn_10 <- function(x, aggressive=TRUE, convert.to.isbn.13=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + x <- as.character(x) + x <- toupper(x) + x <- gsub("[^\\d|X]", "", x, perl=TRUE) + y <- x + x <- gsub("X(.+$)", "\\1", x, perl=TRUE) + is.all.valid <- all(is_valid_isbn_10(x), na.rm=TRUE) + if(aggressive && !is.all.valid){ + will_padding_zeros_fix_it <- function(x){ + nchar(x)==9 & is_valid_isbn_10(stringr::str_pad(x, 10, "left", "0"), lower.x.allowed=FALSE) + } + will_adding_an_X_fix_it <- function(x){ + nchar(x)==9 & get_isbn_10_check_digit(x, errors.as.nas=TRUE)=="X" + } + will_the_first_10_do <- function(x){ + nchar(x)>10 & is_valid_isbn_10(substr(x, 1, 10), lower.x.allowed=FALSE) + } + will_the_hiddens_do <- function(x){ + nchar(x)>10 & is_valid_isbn_10(gsub("^.*?(\\d{9}X).*$", "\\1", x, perl=TRUE), + lower.x.allowed=FALSE) + } + thenines <- x[nchar(x)==9 & !is.na(x)] + if(length(thenines)>0){ + x[nchar(x)==9 & !is.na(x)] <- ifelse(will_padding_zeros_fix_it(thenines), + stringr::str_pad(thenines, 10, "left", "0"), + thenines) + } + thenines <- x[nchar(x)==9 & !is.na(x)] + if(length(thenines)>0){ + x[nchar(x)==9 & !is.na(x)] <- ifelse(will_adding_an_X_fix_it(thenines), + sprintf("%sX", thenines), + thenines) + } + thebig <- x[nchar(x)>10 & !is.na(x)] + if(length(thebig)){ + x[nchar(x)>10 & !is.na(x)] <- ifelse(will_the_first_10_do(thebig), + substr(thebig, 1, 10), + thebig) + } + loghidden <- grepl("\\d{9}X", y, perl=TRUE) & !is.na(x) + if(any(loghidden)){ + loghidden[loghidden] <- will_the_hiddens_do(y[loghidden]) + thehiddens <- y[loghidden] + x[loghidden] <- gsub("^.*?(\\d{9}X).*$", "\\1", thehiddens, perl=TRUE) + } + + } + # maybe shouldn't return NA if couldn't be salvaged? + ret <- ifelse(is_valid_isbn_10(x), x, NA) + if(convert.to.isbn.13) + return(convert_to_isbn_13(ret, skip.validity.check=TRUE)) + return(ret) +} + +# ------------------------------------------ # + + +############################################## +### ISBN 13 ### +############################################## + +#' Get ISBN 13 check digit +#' +#' Takes a string representation of an ISBN 13 +#' and returns the check digit that satisfies the necessary condition. +#' It can take a 13 digit string (and ignore the already extant check digit) +#' or a 12 digit string (without the last digit) +#' +#' @param x A string of 12 or 13 digits +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{FALSE}) +#' @param errors.as.nas return NA if error instead of throwing error +#' (default is \code{FALSE}) +#' +#' @return Returns the character check digit that satifies the +#' mod 10 condition. Returns NA if input is NA +#' +#' @examples +#' +#' get_isbn_13_check_digit("9780306406157") +#' +#' # 12 digit string +#' get_isbn_13_check_digit("978030640615") +#' +#' get_isbn_13_check_digit("onetwothreefo", errors.as.nas=TRUE) # NA +#' +#' # vectorized +#' get_isbn_13_check_digit(c("9780306406157", "9783161484100")) +#' +#' @export +get_isbn_13_check_digit <- function(x, allow.hyphens=FALSE, errors.as.nas=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + if(any(!(nchar(x[!is.na(x)]) %in% c(12, 13))>0)) + if(!errors.as.nas) stop("Input must be either 12 or 13 characters") + where.bad <- !grepl(REGEX.ISBN.13.12, x, perl=TRUE) & !is.na(x) + if(any(where.bad)){ + if(!errors.as.nas) stop("Illegal input") + x[where.bad] <- NA + } + if(any(!where.bad)){ + first12 <- stringr::str_split(substr(x[!where.bad], 1, 12), "", simplify=TRUE) + class(first12) <- "numeric" + first12 <- as.numeric(first12 %*% matrix(rep(c(1,3), 6))) + should.be <- (10 - (first12 %% 10)) %% 10 + x[!where.bad] <- as.character(should.be) + } + return(x) +} + + + +#' Check the check digit of an ISBN 13 +#' +#' Takes a string representation of an ISBN 13 and verifies that check digit +#' checks out +#' +#' @param x A string of 13 digits +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{TRUE}) +#' @param errors.as.false return false if error instead of throwing error +#' (default is \code{TRUE}) +#' +#' @return Returns TRUE if check passes, FALSE if not, and NA if NA +#' @examples +#' +#' check_isbn_13_check_digit("9780306406157") # TRUE +#' check_isbn_13_check_digit("978-0-306-40615-7") # TRUE +#' +#' # vectorized +#' check_isbn_13_check_digit(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE +#' +#' @export +check_isbn_13_check_digit <- function(x, allow.hyphens=TRUE, errors.as.false=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + if(errors.as.false) + return(rep(FALSE, length(x))) + stop("Input must be a character string") + } + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + where.bad <- !grepl(REGEX.ISBN.13, x, perl=TRUE) & !is.na(x) + if(any(where.bad)){ + if(!errors.as.false) stop("Illegal input") + } + check.digit <- stringr::str_sub(x, -1) + should.be <- get_isbn_13_check_digit(x, errors.as.nas = errors.as.false) + ret <- ifelse(should.be==check.digit, TRUE, FALSE) + ret[where.bad] <- FALSE + return(ret) +} + +#' Return TRUE if valid ISBN 13 +#' +#' Takes a string representation of an ISBN 13 verifies that it is valid. +#' An ISBN 13 is valid if it is a 13 digit string and the check digit matches +#' +#' @param x A string of 13 +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{TRUE}) +#' +#' @return Returns TRUE if checks pass, FALSE if not, and NA if NA +#' @examples +#' +#' is_valid_isbn_13("9780306406157") # TRUE +#' is_valid_isbn_13("978-0-306-40615-7") # TRUE +#' +#' # vectorized +#' is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +#' is_valid_isbn_13(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE +#' is_valid_isbn_13(c("978-0-306-40615-7", "hubo un tiempo")) # TRUE FALSE +#' +#' @export +is_valid_isbn_13 <- function(x, allow.hyphens=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + stop("Input must be a character string") + } + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + where.bad <- !grepl(REGEX.ISBN.13, x, perl=TRUE) & !is.na(x) + x[where.bad] <- NA + ret <- ifelse(check_isbn_13_check_digit(x, errors.as.false=TRUE), TRUE, FALSE) + ret[is.na(x)] <- NA + ret[where.bad] <- FALSE + return(ret) +} +attr(is_valid_isbn_13, "assertr_vectorized") <- TRUE + + +#' Convert ISBN 10 to ISBN 13 +#' +#' Takes a string representation of an ISBN 10 and converts it to an ISBN 13. +#' +#' @param x A string of 10 digits or 9 digits with terminal "X" +#' @param skip.validity.check Skip the checking for whether the ISBN 10 is valid +#' (default is \code{FALSE}) +#' @param errors.as.nas return NA if error instead of throwing error +#' (default is \code{FALSE}) +#' +#' @return Returns ISBN 13 as a string +#' +#' @examples +#' +#' convert_to_isbn_13("012491540X") # 9780124915404 +#' +#' # vectorized +#' convert_to_isbn_13(c("012491540X", "9004037810")) +#' # "9780124915404" "9789004037816" +#' +#' @export +convert_to_isbn_13 <- function(x, skip.validity.check=FALSE, + errors.as.nas=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + stop("Input must be a character string") + } + x <- toupper(x) + x <- gsub("[^\\d|X]", "", x, perl=TRUE) + x <- gsub("X(.+$)", "\\1", x, perl=TRUE) + if(!skip.validity.check){ + where.bad <- !is_valid_isbn_10(x) & !is.na(x) + if(any(where.bad) & !errors.as.nas) stop("Invalid ISBN 10 detected") + x[where.bad] <- NA + } + first9 <- substr(x, 1, 9) + first12 <- ifelse(!is.na(first9), sprintf("978%s", first9), NA) + newcheckdigit <- get_isbn_13_check_digit(as.character(first12)) + newisbn13 <- ifelse(!is.na(first12), sprintf("%s%s", first12, newcheckdigit), NA) + return(newisbn13) +} + + + +#' Attempt to enforce validity and canonical form to ISBN 13 +#' +#' Takes a string representation of an ISBN 13. Strips all non-digit +#' characters and checks if it is valid (whether the +#' check digit works out, etc). User can specify whether "aggressive" +#' measures should be taken to salvage the malformed ISBN 13 string. +#' +#' @param x A string +#' @param aggressive A logical indicating whether aggressive measures +#' should be taken to try to get the "ISBN 13" +#' into a valid form. See "Details" for more info +#' (default is \code{TRUE}) +#' +#' @details If \code{aggressive} is TRUE, aggressive measures are taken to +#' try to salvage the malformed ISBN 13 string. If the ISBN 13, for example, +#' is more than 13 characters, this function will attempt to make a valid +#' ISBN 13 from the first 13 digits. +#' +#' @return Returns valid ISBN 13 if possible, NA if not +#' @examples +#' +#' normalize_isbn_13("978966819^*!X7918") # "9789668197918" +#' +#' # vectorized +#' normalize_isbn_13(c("978-9-66-819791-8", "__9__781572411579")) +#' # "9789668197918" "9781572411579" +#' +#' @seealso \code{\link{normalize_isbn}} \code{\link{normalize_isbn_10}} +#' +#' @export +normalize_isbn_13 <- function(x, aggressive=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + x <- as.character(x) + x <- gsub("\\D", "", x, perl=TRUE) + is.all.valid <- all(is_valid_isbn_13(x), na.rm=TRUE) + if(aggressive && !is.all.valid){ + will_the_first_13_do <- function(x){ + nchar(x)>13 & is_valid_isbn_13(substr(x, 1, 13)) + } + wherebig <- nchar(x)>13 & !is.na(x) + thebig <- x[wherebig] + if(length(thebig)){ + x[wherebig] <- ifelse(will_the_first_13_do(thebig), + substr(thebig, 1, 13), + thebig) + } + } + # maybe shouldn't return NA if couldn't be salvaged? + ret <- ifelse(is_valid_isbn_13(x), x, NA) + return(ret) +} + + +# ------------------------------------------ # + + +#' Attempt to enforce validity and canonical form to an ISBN +#' +#' Takes a string representation of an ISBN (10 or 13). This function uses +#' tries to normalize the string as a ISBN 13, then an ISBN 10. If one of +#' those methods are able to salvage the ISBN, the canonicalized ISBN is +#' returned. User can specify whether "aggressive" +#' measures should be taken to salvage the malformed ISBN string. +#' +#' @param x A string +#' @param aggressive A logical indicating whether aggressive measures +#' should be taken to try to get the "ISBN 10" +#' into a valid form. See "Details" for more info +#' (default is \code{TRUE}) +#' @param convert.to.isbn.13 A logical indicating whether the ISBN 10 +#' should be converted into an ISBN 13 +#' (default is \code{FALSE}) +#' +#' @details If \code{aggressive} is TRUE, aggressive measures are taken to +#' try to salvage the malformed ISBN string. Since this function attempts +#' to salvage both an ISBN 10 and 13, to learn about examples of the +#' aggressive methods, see \code{\link{normalize_isbn_10}} and +#' \code{\link{normalize_isbn_13}} +#' +#' @return Returns valid ISBN if possible, NA if not +#' @examples +#' +#' normalize_isbn("012491540x") # "012491540X" +#' normalize_isbn("012491540x", convert.to.isbn.13=TRUE) +#' "9780124915404" +#' +#' # vectorized +#' normalize_isbn(c("513213012491540x245", +#' "978966819^*!X7918", +#' NA, +#' "97815724115799781572411579")) +#' # "012491540X", "9789668197918", NA, "9781572411579" +#' +#' @seealso \code{\link{normalize_isbn_10}} \code{\link{normalize_isbn_13}} +#' +#' @export +normalize_isbn <- function(x, aggressive=TRUE, convert.to.isbn.13=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + x <- as.character(x) + + x <- gsub("[^\\d|X|x]", "", x, perl=TRUE) + + tried <- normalize_isbn_13(x, aggressive=aggressive) + where.na <- is.na(tried) + tried[where.na] <- normalize_isbn_10(x[where.na], aggressive=aggressive, + convert.to.isbn.13=convert.to.isbn.13) + + return(tried) +} + + +# ------------------------------------------ # + + + +############################################## +### ISSN ### +############################################## + +#' Get ISSN check digit +#' +#' Takes a string representation of an ISSN +#' and returns the check digit that satisfies the necessary condition. +#' It can take a 8 digit string (and ignore the already extant check digit) +#' or a 7 digit string (without the last digit) +#' +#' @param x A string of 7 or 8 digits +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{FALSE}) +#' @param errors.as.nas return NA if error instead of throwing error +#' (default is \code{FALSE}) +#' +#' @return Returns the character check digit that satifies the +#' mod 11 condition. Returns "X" if 10. Returns NA if input is NA +#' @examples +#' +#' get_issn_check_digit("03785955") +#' +#' get_issn_check_digit("2434-561X", allow.hyphens=TRUE) +#' +#' # nine digit string +#' get_issn_check_digit("0378595") +#' +#' # vectorized +#' get_issn_check_digit(c("0378595", "2434561X", NA)) +#' +#' @export +get_issn_check_digit <- function(x, allow.hyphens=FALSE, errors.as.nas=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + if(any(!(nchar(x[!is.na(x)]) %in% c(7, 8))>0)){ + if(!errors.as.nas) stop("Input must be either 7 or 8 characters") + } + where.bad <- !grepl(REGEX.ISSN.8.7, x, perl=TRUE) & !is.na(x) + if(any(where.bad)){ + if(!errors.as.nas) stop("Illegal input") + x[where.bad] <- NA + } + + if(any(!where.bad)){ + first7 <- stringr::str_split(substr(x[!where.bad], 1, 7), "", simplify=TRUE) + class(first7) <- "numeric" + first7 <- as.numeric(first7 %*% matrix(8:2)) + should.be <- (11 - (first7 %% 11)) %% 11 + ret <- ifelse(should.be==10, "X", as.character(should.be)) + x[!where.bad] <- ret + } + x +} + + +#' Check the check digit of an ISSN +#' +#' Takes a string representation of an ISSN and verifies that check digit +#' checks out +#' +#' @param x A string of 8 digits or 7 digits with terminal "X" +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{TRUE}) +#' @param errors.as.false return false if error instead of throwing error +#' (default is \code{FALSE}) +#' +#' @return Returns TRUE if check passes, FALSE if not, and NA if NA +#' +#' @examples +#' +#' check_issn_check_digit("2434561X") # TRUE +#' check_issn_check_digit("2434-561X") # TRUE +#' +#' # vectorized +#' check_issn_check_digit(c("03785955", "2434561X", NA)) # TRUE TRUE NA +#' check_issn_check_digit(c("0378-5955", "2434-561X", NA)) +#' # TRUE TRUE NA +#' +#' @export +check_issn_check_digit <- function(x, allow.hyphens=TRUE, errors.as.false=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + if(errors.as.false) + return(rep(FALSE, length(x))) + stop("Input must be a character string") + } + x <- toupper(x) + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + where.bad <- !grepl(REGEX.ISSN, x, perl=TRUE) & !is.na(x) + if(any(where.bad>0)){ + if(!errors.as.false) stop("Illegal input") + } + check.digit <- stringr::str_sub(x, -1) + should.be <- get_issn_check_digit(x, allow.hyphens=allow.hyphens, errors.as.nas=errors.as.false) + ret <- ifelse(should.be==check.digit, TRUE, FALSE) + ret[where.bad] <- FALSE + return(ret) +} + + + +#' Return TRUE if valid ISSN +#' +#' Takes a string representation of an ISSN verifies that it is valid. +#' An ISSN is valid if it is a 8 digit string or a 7 digit string +#' with a terminal "X" AND the check digit matches +#' +#' @param x A string of 8 digits or 7 digits with terminal "X" +#' @param allow.hyphens A logical indicating whether the hyphen +#' separator should be allowed +#' (default is \code{TRUE}) +#' @param lower.x.allowed A logical indicating whether ISSNs with +#' a check digit with a lower-case "x" should +#' be treated as valid +#' (default is \code{TRUE}) +#' +#' @return Returns TRUE if checks pass, FALSE if not, and NA if NA +#' @examples +#' +#' is_valid_issn("2434561X") # TRUE +#' is_valid_issn("2434-561X") # TRUE +#' +#' # vectorized +#' +#' is_valid_issn(c("2434-561X", "2434-5611", "0378-5955", NA)) +#' # TRUE FALSE TRUE NA +#' +#' @export +is_valid_issn <- function(x, allow.hyphens=TRUE, lower.x.allowed=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")){ + stop("Input must be a character string") + } + if(allow.hyphens) + x <- gsub("-", "", x, fixed=TRUE) + if(lower.x.allowed) + x <- toupper(x) + where.bad <- !grepl(REGEX.ISSN, x, perl=TRUE) & !is.na(x) + x[where.bad] <- NA + ret <- ifelse(check_issn_check_digit(x, errors.as.false=TRUE), TRUE, FALSE) + ret[is.na(x)] <- NA + ret[where.bad] <- FALSE + return(ret) +} +attr(is_valid_issn, "assertr_vectorized") <- TRUE + + + +#' Attempt to enforce validity and canonical form to ISSN +#' +#' Takes a string representation of an ISSN. Strips all non-digit +#' and non-"X" characters and checks if it is valid (whether the +#' check digit works out, etc). User can specify whether "aggressive" +#' measures should be taken to salvage the malformed ISSN string. +#' +#' @param x A string +#' @param aggressive A logical indicating whether aggressive measures +#' should be taken to try to get the "ISSN" +#' into a valid form. See "Details" for more info +#' (default is \code{TRUE}) +#' @param pretty A logical indicating whether the ISSN should be +#' prettily hyphenated +#' (default is \code{FALSE}) +#' +#' @details If \code{aggressive} is TRUE, aggressive measures are taken to +#' try to salvage the malformed ISSN string. If the ISSN, for example, +#' is 7 digits, and either adding an "X" to the end, or leading "0"s fix it, +#' this function will return the salvaged ISSN. If the ISSN has +#' garbage digits/characters in the front and has an "X" check digit, +#' it will return the salvaged ISSN. +#' +#' @return Returns valid ISSN if possible, NA if not +#' @examples +#' +#' # adds leading zero +#' normalize_issn("3785955") # "03785955" +#' +#' # adds X to 7 digit ISSN if valid +#' normalize_issn("2434561") # "2434561X" +#' +#' normalize_issn("2434561", pretty=TRUE) # "2434-561X" +#' +#' # finds correct sequence +#' normalize_issn("21335212434561X") # "2434561X" +#' +#' # vectorized +#' normalize_issn(c("__2434__561X", "2434561", "21335212434561X")) +#' # "2434561X" "2434561X" "2434561X" +#' +#' @export +normalize_issn <- function(x, aggressive=TRUE, pretty=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + x <- as.character(x) + x <- toupper(x) + x <- gsub("[^\\d|X]", "", x, perl=TRUE) + y <- x + x <- gsub("X(.+$)", "\\1", x, perl=TRUE) + is.all.valid <- all(is_valid_issn(x), na.rm=TRUE) + if(aggressive && !is.all.valid){ + will_padding_zeros_fix_it <- function(x){ + ifelse(nchar(x)==7 & is_valid_issn(stringr::str_pad(x, 8, "left", "0")), TRUE, FALSE) + } + will_adding_an_X_fix_it <- function(x){ + ifelse(nchar(x)==7 & get_issn_check_digit(x, errors.as.nas=TRUE)=="X", TRUE, FALSE) + } + will_the_first_8_do <- function(x){ + ifelse(nchar(x)>8 & is_valid_issn(substr(x, 1, 8)), TRUE, FALSE) + } + will_the_hiddens_do <- function(x){ + ifelse(nchar(x)>8 & is_valid_issn(gsub("^.*?(\\d{7}X).*$", "\\1", x, perl=TRUE)), + TRUE, FALSE) + } + thesevens <- x[nchar(x)==7 & !is.na(x)] + if(length(thesevens)>0){ + x[nchar(x)==7 & !is.na(x)] <- ifelse(will_padding_zeros_fix_it(thesevens), + stringr::str_pad(thesevens, 8, "left", "0"), + thesevens) + } + thesevens <- x[nchar(x)==7 & !is.na(x)] + if(length(thesevens)>0){ + x[nchar(x)==7 & !is.na(x)] <- ifelse(will_adding_an_X_fix_it(thesevens), + sprintf("%sX", thesevens), + thesevens) + } + thebig <- x[nchar(x)>8 & !is.na(x)] + if(length(thebig)){ + x[nchar(x)>8 & !is.na(x)] <- ifelse(will_the_first_8_do(thebig), + substr(thebig, 1, 8), + thebig) + } + loghidden <- grepl("\\d{7}X", y, perl=TRUE) & !is.na(x) + if(any(loghidden)){ + loghidden[loghidden] <- will_the_hiddens_do(y[loghidden]) + thehiddens <- y[loghidden] + x[loghidden] <- gsub("^.*?(\\d{7}X).*$", "\\1", thehiddens, perl=TRUE) + } + + } + # maybe shouldn't return NA if couldn't be salvaged? + ret <- ifelse(is_valid_issn(x), x, NA) + if(pretty) + ret <- sprintf("%s-%s", substr(x, 1, 4), substr(x, 5, 8)) + return(ret) +} + +# ------------------------------------------ # + + + +############################################## +### LCCN ### +############################################## + +#' Attempt to enforce validity of LCCN and convert to normalized form +#' +#' Takes a string representation of an LCCN. Returns a normalized one +#' +#' @param userlccns A string (or vector of strings) of LCCNs +#' @param allow.hyphens a logical indicating whether hyphens separating +#' the year and serial should be handled. Adds +#' complexity and time to the function. +#' (default is \code{TRUE}) +#' +#' @details Normalization procedure is documented here: +#' https://www.loc.gov/marc/lccn-namespace.html +#' +#' This does not include revisions or use "#" as a padding character +#' The normalized LCCN is not always the same number of characters +#' +#' @return Returns valid LCCN if possible, NA if not +#' +#' @examples +#' +#' normalize_lccn("n 78890351 ") # "n78890351" +#' +#' normalize_lccn("###78890351#") # "78890351" +#' +#' normalize_lccn(" 79139101 /AC/r932") # "79139101" +#' +#' normalize_lccn("85-2 ") # "85000002" +#' normalize_lccn("85-2 ", allow.hyphens=FALSE) # NA +#' +#' # vectorized +#' normalize_lccn(c("85-2 ", " 79139101 /AC/r932", "n 78890351 ")) +#' # c("85000002", "79139101", "n78890351")) +#' +#' @export +normalize_lccn <- function(userlccns, allow.hyphens=TRUE){ + if(all(is.na(userlccns))) return(as.character(userlccns)) + if(!methods::is(userlccns, "character")) + stop("Input must be a character string") + + userlccns <- stringr::str_replace_all(userlccns, "\\s", "") + userlccns <- stringr::str_replace_all(userlccns, "#", "") + userlccns <- stringr::str_replace_all(userlccns, "\\^", "") + userlccns <- stringr::str_replace(userlccns, "/.+$", "") + + where.bad <- !stringr::str_detect(userlccns, "\\d") + userlccns[where.bad] <- NA + + where.bad <- stringr::str_detect(userlccns, "[a-z]{4,}") + userlccns[where.bad] <- NA + + if(allow.hyphens){ + where.bad <- stringr::str_detect(userlccns, "[^a-z\\d-]") + userlccns[where.bad] <- NA + + pieces <- stringr::str_split(userlccns, "-") + + process_pieces <- function(pieces){ + ifelse(length(pieces)>2, NA_character_, + ifelse(length(pieces)==1, pieces, + ifelse(nchar(pieces[2])>6, NA_character_, + sprintf("%s%s", pieces[1], + stringr::str_pad(pieces[2], width=6, pad="0"))))) + } + userlccns <- unlist(lapply(pieces, process_pieces)) + } else{ + where.bad <- stringr::str_detect(userlccns, "[^a-z\\d]") + userlccns[where.bad] <- NA + } + + where.bad <- nchar(userlccns)<8 | nchar(userlccns)>12 + userlccns[where.bad] <- NA + + return(userlccns) +} + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/books_serials_etc_sample_data.R b/libbib.Rcheck/00_pkg_src/libbib/R/books_serials_etc_sample_data.R new file mode 100644 index 0000000..94f22ff --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/books_serials_etc_sample_data.R @@ -0,0 +1,17 @@ +#' Small sample of books, monographs, and serials and their information +#' +#' A very small sample of books, serials, VHSs, CDs, and Computer files +#' and some information including title, control numbers, call numbers, and +#' call number subject classifications. Somewhat messy/inconsistent +#' (deliberately) and mainly for testing. +#' Will be expanded in future versions. +#' +#' @docType data +#' +#' @usage data(books_serials_etc_sample) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets +#' +"books_serials_etc_sample" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/call-numbers-and-subject.R b/libbib.Rcheck/00_pkg_src/libbib/R/call-numbers-and-subject.R new file mode 100755 index 0000000..fb63755 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/call-numbers-and-subject.R @@ -0,0 +1,414 @@ + + +make.valid.lccall.regex <- function(allow.bare=FALSE){ + thekey <- lc_subject_subclassification <- NULL + data("lc_subject_subclassification", envir = environment()) + tmp <- copy(lc_subject_subclassification) + tmp <- tmp[order(-nchar(thekey))] + if(allow.bare) + VALIDLCCALL <- sprintf("^(%s)$", paste(tmp[, thekey], collapse="|")) + else + VALIDLCCALL <- sprintf("^(%s)\\s*[0-9]", paste(tmp[, thekey], collapse="|")) + VALIDLCCALL +} + +REGEX.VALID.LCCALL <- make.valid.lccall.regex() +REGEX.VALID.LCCALL.BARE <- make.valid.lccall.regex(allow.bare=TRUE) + +################################################################## +### Conversion from LC Calls to subject classification ### +################################################################## + +#' Conversion from Library of Congress Call number to subject +#' classification +#' +#' Takes a string representation of a Library of Congress +#' call number and returns either the broad subject +#' classification description (default) based on the first +#' letter, or a second-level subclassification +#' description based on the all the letters +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Library of Congress call number (string) +#' @param subclassification A logical indicating whether the letters of +#' call number past the first should be used to match to +#' a subject subclassification (default is \code{FALSE}) +#' @param already.parsed Skips the extraction of the subject letters +#' and jumps to the subject matching (default is \code{FALSE}) +#' @param allow.bare A logical indicating whether an LC Call with only +#' the letters should be considered valid +#' (default is \code{TRUE}) +#' +#' @return Returns either the broad (top-level) subject classification +#' description or the second level subject subclassification +#' description. Returns "NA" if no subject could not be matched +#' or call number is invalid +#' @examples +#' +#' get_lc_call_subject_classification("ND 237.S18 $b S87 1997") +#' # Fine Arts +#' +#' get_lc_call_subject_classification("ND 237.S18 $b S87 1997", subclassification=TRUE) +#' # Painting +#' +#' get_lc_call_subject_classification("PQ2246.M3") +#' # Language and Literature +#' +#' get_lc_call_subject_classification("PQ2246.M3", +#' subclassification=TRUE) +#' # "French, Italian, Spanish, and Portuguese literature" +#' +#' get_lc_call_subject_classification("PQ2246.M3", already.parsed=TRUE) +#' # NA +#' +#' get_lc_call_subject_classification("PQ", already.parsed=TRUE, +#' subclassification=TRUE) +#' # "French, Italian, Spanish, and Portuguese literature" +#' +#' # vectorized +#' get_lc_call_subject_classification(c("ND 237", "\\\\$a ND 2", "PQ2246.M3"), +#' subclassification=TRUE) +#' # c("Painting", NA, "French, Italian, Spanish, and Portuguese literature") +#' +#' +#' @export +get_lc_call_subject_classification <- function(x, subclassification=FALSE, + already.parsed=FALSE, + allow.bare=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_to_upper(x) + x <- stringr::str_trim(x) + + thekey <- usersupplied <- description <- NULL + lc_subject_classification <- lc_subject_subclassification <- NULL + + theinput <- data.table::data.table(usersupplied=x) + + if(already.parsed){ + theinput[, thekey:=usersupplied] + } else{ + if(subclassification){ + theinput[, thekey:=get_all_lc_call_subject_letters(usersupplied, allow.bare=allow.bare)] + } else{ + theinput[, thekey:=get_lc_call_first_letter(usersupplied, allow.bare=allow.bare)] + } + } + + data.table::setindex(theinput, thekey) + + if(subclassification){ + data("lc_subject_subclassification", envir = environment()) + result <- lc_subject_subclassification[theinput, on="thekey"] + } else{ + data("lc_subject_classification", envir = environment()) + result <- lc_subject_classification[theinput, on="thekey"] + } + + return(result[, description]) +} + + +#' Check if LC Call Number is valid +#' +#' Takes a string representation of a Library of Congress +#' call number and returns either TRUE or FALSE based on +#' whether or not the input fits the canonical LC Call +#' Number pattern +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Library of Congress call number (string) +#' @param allow.bare A logical indicating whether an LC Call with only +#' the letters should be considered valid +#' (default is \code{FALSE}) +#' +#' @return Returns either TRUE or FALSE based on whether the +#' call number is valid +#' @examples +#' +#' is_valid_lc_call("Q172.5.E77") +#' # TRUE +#' is_valid_lc_call("AF172.5.E77") +#' # FALSE +#' +#' # vectorized +#' is_valid_lc_call(c("Q 172.5", "AF172", "PR6023.A93")) +#' # TRUE FALSE TRUE +#' +#' @export +is_valid_lc_call <- function(x, allow.bare=FALSE){ + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_to_upper(x) + x <- stringr::str_trim(x) + + if(allow.bare) + ret <- (stringr::str_detect(x, REGEX.VALID.LCCALL.BARE) | + stringr::str_detect(x, REGEX.VALID.LCCALL)) + else + ret <- stringr::str_detect(x, REGEX.VALID.LCCALL) + + return(ret) +} +attr(is_valid_lc_call, "assertr_vectorized") <- TRUE + + +#' Get the first letter of LC Call Number +#' +#' Takes a string representation of a Library of Congress +#' call number and returns the first letter if and only if +#' the LC Call Number is valid +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Library of Congress call number (string) +#' @param allow.bare A logical indicating whether an LC Call with only +#' the letters should be considered valid +#' (default is \code{FALSE}) +#' +#' @return Returns first letter or NA if invalid +#' @examples +#' +#' get_lc_call_first_letter("Q172.5.E77") +#' # Q +#' get_lc_call_first_letter("AF172.5.E77") +#' # NA +#' +#' # vectorized +#' get_lc_call_first_letter(c("Q 172.5", "AF172", "PR6023.A93")) +#' # Q NA P +#' +#' @export +get_lc_call_first_letter <- function(x, allow.bare=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_to_upper(x) + x <- stringr::str_trim(x) + + thekey <- usersupplied <- NULL + + theinput <- data.table::data.table(usersupplied=x) + + THESEAREVALID <- theinput[, is_valid_lc_call(usersupplied, allow.bare=allow.bare)] + theinput[THESEAREVALID, thekey:=stringr::str_sub(usersupplied, 1, 1)] + theinput[!THESEAREVALID, thekey:=NA] + return(theinput[, thekey]) +} + + +#' Get all subject letters of LC Call Number +#' +#' Takes a string representation of a Library of Congress +#' call number and returns all the subject letters if and only if +#' the LC Call Number is valid +#' +#' @importFrom data.table := data.table setindex +#' @import utils +#' +#' @param x A Library of Congress call number (string) +#' @param allow.bare A logical indicating whether an LC Call with only +#' the letters should be considered valid +#' (default is \code{FALSE}) +#' +#' @return Returns all the subject letters or NA if invalid +#' @examples +#' +#' get_all_lc_call_subject_letters("Q172.5.E77") +#' # Q +#' get_all_lc_call_subject_letters("AF172.5.E77") +#' # NA +#' +#' # vectorized +#' get_all_lc_call_subject_letters(c("Q 172.5", "AF172", "PR6023.A93")) +#' # Q NA PR +#' +#' @export +get_all_lc_call_subject_letters <- function(x, allow.bare=FALSE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_to_upper(x) + x <- stringr::str_trim(x) + + description <- usersupplied <- thekey <- lc_first_letter_subject <- NULL + + theinput <- data.table::data.table(usersupplied=x) + + THESEAREVALID <- theinput[, is_valid_lc_call(usersupplied, allow.bare=allow.bare)] + theinput[THESEAREVALID, thekey:=stringr::str_extract(usersupplied, "^[A-Z]+")] + theinput[!THESEAREVALID, thekey:=NA] + return(theinput[, thekey]) +} + + + +######################################################################### +### Conversion from Dewey Decimals to subject classifications ### +######################################################################### + +#' Conversion from Dewey Decimal call numbers to first-level subject description +#' +#' Takes a string representation of a Dewey Decimal +#' call number (DDC) and returns it's subject description. +#' This uses the hundreds place of the DDC number +#' and returns the most general subject classification. +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Dewey Decimal call number +#' +#' @return Returns the most general subject classification using the +#' hundreds places from the DDC. Returns NA if the DDC looks +#' invalid +#' +#' @examples +#' +#' get_dewey_decimal_subject_class("709.05") # Arts +#' +#' get_dewey_decimal_subject_class("823.912") +#' # Literature (Belles-lettres) and rhetoric +#' +#' # vectorized +#' get_dewey_decimal_subject_class(c("709.05", "invalid", NA, "823.912")) +#' # c("Arts", NA, NA, "Literature (Belles-lettres) and rhetoric") +#' +#' @export +get_dewey_decimal_subject_class <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_trim(x) + + where.bad <- !stringr::str_detect(x, "^\\d{3}") + x[where.bad] <- NA_character_ + + x <- stringr::str_pad(stringr::str_sub(x , 1, 1), width=3, pad="0", side="right") + + thekey <- description <- dewey_subject_crosswalk <- NULL + + theinput <- data.table::data.table(thekey=x) + data.table::setindex(theinput, thekey) + + data("dewey_subject_crosswalk", envir = environment()) + + result <- dewey_subject_crosswalk[theinput, on="thekey"] + + return(result[, description]) +} + + +#' Conversion from Dewey Decimal call numbers to second-level subject description +#' +#' Takes a string representation of a Dewey Decimal +#' call number (DDC) and returns it's subject description. +#' This uses the first two digits of the DDC number +#' and returns the second most general subject classification. +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Dewey Decimal call number +#' +#' @return Returns the most general subject classification using the +#' first two digits from the DDC. Returns NA if the DDC looks +#' invalid +#' +#' @examples +#' +#' get_dewey_decimal_subject_division("709.05") # Arts +#' +#' get_dewey_decimal_subject_division("823.912") +#' # "English and Old English literatures" +#' +#' # vectorized +#' get_dewey_decimal_subject_division(c("709.05", "invalid", NA, "823.912")) +#' # c("Arts", NA, NA, "English and Old English literatures") +#' +#' @export +get_dewey_decimal_subject_division <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_trim(x) + + where.bad <- !stringr::str_detect(x, "^\\d{3}") + x[where.bad] <- NA_character_ + + x <- stringr::str_pad(stringr::str_sub(x , 1, 2), width=3, pad="0", side="right") + + thekey <- description <- dewey_subject_crosswalk <- NULL + + theinput <- data.table::data.table(thekey=x) + data.table::setindex(theinput, thekey) + + data("dewey_subject_crosswalk", envir = environment()) + + result <- dewey_subject_crosswalk[theinput, on="thekey"] + + return(result[, description]) +} + + +#' Conversion from Dewey Decimal call numbers to third-level subject description +#' +#' Takes a string representation of a Dewey Decimal +#' call number (DDC) and returns it's subject description. +#' This uses the first three digits of the DDC number +#' and returns the third most general subject classification. +#' +#' @importFrom data.table := data.table setindex +#' +#' @param x A Dewey Decimal call number +#' +#' @return Returns the most general subject sectionification using the +#' first three digits from the DDC. Returns NA if the DDC looks +#' invalid +#' +#' @examples +#' +#' get_dewey_decimal_subject_section("709.05") +#' # "History, geographic treatment, biography" +#' +#' get_dewey_decimal_subject_section("823.912") +#' # "English fiction" +#' +#' # vectorized +#' get_dewey_decimal_subject_section(c("709.05", "invalid", NA, "823.912")) +#' # c("History, geographic treatment, biography", NA, NA, +#' # "English fiction") +#' +#' @export +get_dewey_decimal_subject_section <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + x <- stringr::str_trim(x) + + where.bad <- !stringr::str_detect(x, "^\\d{3}") + x[where.bad] <- NA_character_ + + x <- stringr::str_sub(x , 1, 3) + + thekey <- description <- dewey_subject_crosswalk <- NULL + + theinput <- data.table::data.table(thekey=x) + data.table::setindex(theinput, thekey) + + data("dewey_subject_crosswalk", envir = environment()) + + result <- dewey_subject_crosswalk[theinput, on="thekey"] + + return(result[, description]) +} + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/country_code_crosswalk-data.R b/libbib.Rcheck/00_pkg_src/libbib/R/country_code_crosswalk-data.R new file mode 100644 index 0000000..7cfb7b9 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/country_code_crosswalk-data.R @@ -0,0 +1,16 @@ +#' Country code / country crosswalk +#' +#' A cross-walk between the country code +#' and it's human readable version +#' +#' @docType data +#' +#' @usage data(country_code_crosswalk) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets +#' +#' @source \url{https://www.loc.gov/marc/countries/countries_code.html} +#' +"country_code_crosswalk" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/dewey_subject_crosswalk-data.R b/libbib.Rcheck/00_pkg_src/libbib/R/dewey_subject_crosswalk-data.R new file mode 100644 index 0000000..ddc129e --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/dewey_subject_crosswalk-data.R @@ -0,0 +1,16 @@ +#' Dewey Decimal Classification / Subject Description crosswalk +#' +#' A cross-walk between the Dewey Decimal Classification code +#' and it's human readable subject description +#' +#' @docType data +#' +#' @usage data(dewey_subject_crosswalk) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets +#' +#' @source Edited from \url{https://www.oclc.org/content/dam/oclc/dewey/ddc23-summaries.pdf} +#' +"dewey_subject_crosswalk" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/language_code_crosswalk-data.R b/libbib.Rcheck/00_pkg_src/libbib/R/language_code_crosswalk-data.R new file mode 100644 index 0000000..e8cc1d9 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/language_code_crosswalk-data.R @@ -0,0 +1,16 @@ +#' language code / language crosswalk +#' +#' A cross-walk between the language code +#' and it's human readable version +#' +#' @docType data +#' +#' @usage data(language_code_crosswalk) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets + +#' @source \url{https://www.loc.gov/marc/languages/language_code.html} +#' +"language_code_crosswalk" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_classification-data.R b/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_classification-data.R new file mode 100644 index 0000000..be52524 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_classification-data.R @@ -0,0 +1,16 @@ +#' LC Call Subject Code Classification / Classification name crosswalk +#' +#' A cross-walk between the LC Subject classification and +#' and it's human readable name (first letter of LC Call Number) +#' +#' @docType data +#' +#' @usage data(lc_subject_classification) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets +#' +#' @source \url{https://www.loc.gov/catdir/cpso/lcco/} +#' +"lc_subject_classification" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_subclassification-data.R b/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_subclassification-data.R new file mode 100644 index 0000000..f98a122 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/lc_subject_subclassification-data.R @@ -0,0 +1,16 @@ +#' LC Subject Subclassification / Subclassification name crosswalk +#' +#' A cross-walk between the LC Subject subclassification and +#' and it's human readable name (all letters in an LC Call Number) +#' +#' @docType data +#' +#' @usage data(lc_subject_subclassification) +#' +#' @format An object of class \code{"data.table"}; +#' +#' @keywords datasets +#' +#' @source \url{https://www.loc.gov/catdir/cpso/lcco/} +#' +"lc_subject_subclassification" diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/marc-field-deconstruction.R b/libbib.Rcheck/00_pkg_src/libbib/R/marc-field-deconstruction.R new file mode 100755 index 0000000..7eacf2f --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/marc-field-deconstruction.R @@ -0,0 +1,142 @@ + +#' Get info from MARC leader +#' +#' Takes one or more MARC leaders (string/strings) and returns a +#' \code{data.table} containing the record type and bib level +#' +#' @param x A string (or vector of strings) of MARC leaders +#' +#' @return A \code{data.table} +#' +#' @examples +#' +#' marc_leader_get_info("00000cam a22000008i 4500") +#' # record_type bib_level +#' # +#' # 1: Language Material Monograph/Item +#' +#' # vectorized +#' marc_leader_get_info(c("00000cam a2200000Ma 4500", NA, +#' "00000cem a2200000Ma 4500")) +#' # record_type bib_level +#' # +#' # 1: Language Material Monograph/Item +#' # 2: +#' # 3: Cartographic material Monograph/Item +#' +#' @export +#' @importFrom data.table fcase +marc_leader_get_info <- function(x){ + if(!methods::is(x, "character")) + stop("x must be a string or NA") + + record_type <- stringr::str_sub(x, 7, 7) + bib_level <- stringr::str_sub(x, 8, 8) + + record_type <- fcase(record_type=="a", "Language Material", + record_type=="c", "Notated music", + record_type=="d", "Manuscript notated music", + record_type=="e", "Cartographic material", + record_type=="f", "Manuscript cartographic material", + record_type=="g", "Projected medium", + record_type=="i", "Nonmusical sound recording", + record_type=="j", "Musical sound recording", + record_type=="k", "Two-dimensional nonprojectable graphic", + record_type=="m", "Computer file", + record_type=="o", "Kit", + record_type=="p", "Mixed materials", + record_type=="r", "Three-dimensional artifact or naturally occurring object", + record_type=="t", "Manuscript language material ", + default=NA) + + bib_level <- fcase(bib_level=="a", "Monographic component part", + bib_level=="b", "Serial component part", + bib_level=="c", "Collection", + bib_level=="d", "Subunit", + bib_level=="i", "Integrating resource", + bib_level=="m", "Monograph/Item", + bib_level=="s", "Serial", + default=NA) + + ret <- data.table(record_type=record_type, bib_level=bib_level) + ret[] +} + + + +#' Get info from MARC control field 008 +#' +#' Takes one or more MARC 008 fields (string/strings) and returns a +#' \code{data.table} containing the publication date, publication +#' place code, and language code. +#' +#' @details +#' If any date element is "unknown" (contains a "u"), the returned +#' date is NA. The returned date is always an integer. +#' +#' @param x A string (or vector of strings) of LCCNs +#' @param original.pub.date If \code{TRUE} and if applicable, +#' return the original publication date, not +#' the re-issue publication date. (Default +#' is \code{FALSE}) +#' @param include.questionable.dates A logical indicating whether "questionable" +#' dates should be replaced with \code{NA}. +#' Questionable dates are when the "type of +#' date" in character position 06 is "q". +#' (default is \code{FALSE}) +#' +#' @return A \code{data.table} +#' +#' @examples +#' +#' # reissue publication date +#' marc_008_get_info("950622r19701880ru 000 0 rus d") +#' # pub_date pub_place_code lang_code +#' # +#' # 1: 1970 ru rus +#' +#' # The Brothers Karamazov (1970 reissue but original publication date) +#' marc_008_get_info("950622r19701880ru 000 0 rus d", +#' original.pub.date=TRUE) +#' # pub_date pub_place_code lang_code +#' # +#' # 1: 1880 ru rus +#' +#' # vectorized +#' marc_008_get_info(c("101106s1992 gr 000 1 gre d", NA, +#' "180528s2017 ag 000 j spa d")) +#' # pub_date pub_place_code lang_code +#' # +#' # 1: 1992 gr gre +#' # 2: NA +#' # 3: 2017 ag spa +#' +#' @export +marc_008_get_info <- function(x, original.pub.date=FALSE, + include.questionable.dates=FALSE){ + if(!methods::is(x, "character")) + stop("x must be a string or NA") + + pub_date <- NULL + + status <- stringr::str_sub(x, 7, 7) + date1 <- stringr::str_sub(x, 8, 11) + date2 <- stringr::str_sub(x, 12, 15) + pub_place_code <- stringr::str_trim(stringr::str_sub(x, 16, 18)) + lang_code <- stringr::str_sub(x, 36, 38) + ret <- data.table(status=status, pub_date=date1, date2=date2, + pub_place_code=pub_place_code, lang_code=lang_code) + if(original.pub.date){ + ret[status=="r" & !is.na(date2), pub_date:=date2] + } + if(!include.questionable.dates) + ret[status=="q", pub_date:=NA] + ret[!stringr::str_detect(pub_date, "^\\d{3,4}$"), pub_date:=NA] + ret[,pub_date:=as.integer(pub_date)] + ret[,status:=NULL] + ret[,date2:=NULL] + ret[] +} + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/other-code-translations.R b/libbib.Rcheck/00_pkg_src/libbib/R/other-code-translations.R new file mode 100755 index 0000000..0e1db44 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/other-code-translations.R @@ -0,0 +1,85 @@ + + +#' Conversion from language code to language name +#' +#' Takes a language code (defined in the Marc standards) +#' and returns the language name. +#' +#' @importFrom data.table data.table setindex +#' +#' @param x A language code (defined in the Marc standards) or a vector +#' of language codes +#' +#' @return Returns the language name. NA if cannot be matched +#' to language in standard. +#' +#' @examples +#' +#' get_language_from_code("yor") +#' # Yoruba +#' +#' # tolerant of case and leading/trailing whitespace +#' get_language_from_code(c("yor", " SPA ", "not-a-language", "nah", NA)) +#' # c("Yoruba", "Spanish", NA, "Nahuatl", NA) +#' +#' @export +get_language_from_code <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + x <- stringr::str_trim(stringr::str_to_lower(x)) + thekey <- language <- language_code_crosswalk <- NULL + theinput <- data.table::data.table(thekey=x) + data.table::setindex(theinput, thekey) + data("language_code_crosswalk", envir = environment()) + result <- language_code_crosswalk[theinput, on="thekey"] + return(result[, language]) +} + + +#' Conversion from country code to country name +#' +#' Takes a country code (defined in the Marc standards) +#' and returns the country name. +#' +#' @details +#' Interestingly, although it's called 'country' in the Marc standard, +#' cities, states, and other non-countries also have codes +#' +#' @importFrom data.table data.table setindex +#' +#' @param x A country code (defined in the Marc standards) or a vector +#' of country codes +#' +#' @return Returns the country (place) name. NA if cannot be matched +#' to country in standard. +#' +#' @examples +#' +#' get_country_from_code("ck") +#' # Colombia +#' +#' # tolerant of case and leading/trailing whitespace +#' get_country_from_code(c(" PE", "not-a-country", "nyu")) +#' # c("Peru", NA, "New York (State)") +#' +#' @export +get_country_from_code <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + x <- stringr::str_trim(stringr::str_to_lower(x)) + thekey <- country <- country_code_crosswalk <- NULL + theinput <- data.table::data.table(thekey=x) + data.table::setindex(theinput, thekey) + data("country_code_crosswalk", envir = environment()) + result <- country_code_crosswalk[theinput, on="thekey"] + return(result[, country]) +} + + + + + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/special-attributes.R b/libbib.Rcheck/00_pkg_src/libbib/R/special-attributes.R new file mode 100755 index 0000000..682da92 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/special-attributes.R @@ -0,0 +1,295 @@ + + +#' Set special libbib attribute on object +#' +#' Takes an object, attribute name, and a value and sets a special +#' libbib attribute by reference +#' +#' @importFrom data.table fread fwrite setattr +#' +#' @param x An object to set the attribute on +#' @param type The name of the attribute to set. \code{lb.} will be appended +#' to this attribute name. For example, if this argument is +#' \code{source}, and attribute called \code{lb.source} will +#' be set on the object with the value specified +#' @param value The value of the attribute +#' +#' @return Nothing, since the object is modified by reference. +#' +#' @examples +#' set_lb_attribute(mtcars, "source", "R built-in dataset") +#' +#' versicolor <- iris[iris$Species=="versicolor", ] +#' set_lb_attribute(versicolor, "note", "modified built-in dataset") +#' attributes(versicolor)$lb.note +#' # [1] "modified built-in dataset" +#' +#' @export +set_lb_attribute <- function(x, type, value){ + setattr(x, sprintf("lb.%s", type), value) +} + + +#' Set special libbib date attribute on object +#' +#' Takes an object and a date and sets a special attribute, "lb.date" +#' by reference +#' +#' @importFrom data.table fread fwrite setattr +#' +#' @param x An object to set the attribute on +#' @param value Either a value of class \code{Date} or a string in ISO 8601 +#' date format (yyyy-mm-dd) which will be converted into a Date +#' +#' @return Nothing, since the object is modified by reference. +#' +#' @examples +#' set_lb_date(mtcars, "2021-05-08") +#' attributes(mtcars)$lb.date +#' # [1] "2021-05-08 +#' +#' set_lb_date(mtcars, Sys.Date()) +#' +#' @export +set_lb_date <- function(x, value){ + if(methods::is(value, "Date")) + set_lb_attribute(x, "date", value) + else + set_lb_attribute(x, "date", as.Date(value)) +} + + + +#' Copy special libbib attributes from one object to another +#' +#' Takes two objects and copies all special libbib attributes +#' (attributes beginning with \code{lb.}) from the first object +#' to the second, by reference. +#' +#' @importFrom data.table fread fwrite setattr +#' +#' @param a The first object (the one with the attributes to copy) +#' @param b The second object (the one to copy those attributes to) +#' +#' @return Nothing, since the object is modified by reference. +#' +#' @examples +#' +#' tmp1 <- "a" +#' set_lb_date(tmp1, "2021-05-08") +#' set_lb_attribute(tmp1, "note", "just an example") +#' +#' tmp2 <- "b" +#' cp_lb_attributes(tmp1, tmp2) +#' attributes(tmp2)$lb.date +#' # [1] "2021-05-08" +#' attributes(tmp2)$lb.note +#' # [1] "just an example" +#' +#' @export +cp_lb_attributes <- function(a, b){ + tmp <- names(attributes(a)) + tmp <- stringr::str_subset(tmp, "^lb\\.") + invisible(sapply(tmp, function(x) setattr(b, x, attr(a, x)))) +} + + + +# un-exported helper function +split_extension <- function(fname){ + if(length(fname)>1) stop("only takes one filename") + dirpart <- sprintf("%s/", dirname(fname)) + if(dirpart=="./") dirpart <- "" + basepart <- basename(fname) + pieces <- stringr::str_split(basepart, "\\.", n=2) + before_ext <- pieces[[1]][1] + after_ext <- pieces[[1]][2] + if(!is.na(after_ext)) after_ext <- sprintf(".%s", after_ext) + if(is.na(before_ext) & is.na(after_ext)) stop("couldn't split extension") + c(sprintf("%s%s", dirpart, before_ext), after_ext) +} + + + +# un-exported helper function +fread_plus_helper <- function(fname){ + pieces <- split_extension(fname) + file.match <- Sys.glob(sprintf("%s*%s", pieces[1], pieces[2])) + if(length(file.match)==0) stop("no matching filename") + if(length(file.match)>1){ + tmp <- sprintf("\n %s", paste(file.match, collapse=", ")) + stop("more than one matching file: ", tmp) + } + # will use the native pipe operator when everone uses > R v4.1 + plus.part <- stringr::str_replace(file.match, sprintf("^%s\\D*", pieces[1]), "") + plus.part <- stringr::str_replace(plus.part, sprintf("\\D*%s$", pieces[2]), "") + + list(matching_filename=file.match, + given_filename=fname, + plus_part=plus.part, + before_ext=pieces[1], + after_ext=pieces[2]) +} + + + + +#' Read a file and set a special libbib date attribute +#' +#' Takes a file name, reads it with \code{data.table::fread}, and +#' sets an attribute called \code{lb.date} with a date extracted +#' from the file name. +#' +#' The file name can be one with a valid ISO 8601 date (yyyy-mm-dd) +#' already in it, or it can be a file name with the date elided. +#' +#' For example, if there is a file you'd like to read on your disk +#' called "iris-2021-05-08.csv", you can call this function with +#' either "iris.csv" or "iris-2021-05-08.csv" as the file name. +#' +#' When you call this function with a file name without an ISO 8601 +#' date (e.g. "iris.csv.gz"), the file name extension ".csv.gz" is +#' removed and the function looks for a file name beginning with +#' "iris", a date, and the file extension. The file extension is +#' considered to be anything after the first period in the base name. +#' For example, if the file name given is "./my.data/iris.csv.gz", the +#' extension is ".csv.gz". This means no period can be present in +#' the base file name (after any directories) with the exception of +#' the file extension. +#' +#' If you call this function with "iris.csv" and there is no file name +#' with an ISO 8601 date appended to that file name on your disk, and +#' \code{allow.fallback.date} is \code{TRUE}, then the \code{lb.date} +#' attribute is set to the current date. +#' +#' @importFrom data.table fread fwrite setattr +#' +#' @param fname The file name to read +#' @param allow.fallback.date A logical indicating whether, if no +#' matching file name with a date is found, +#' to use today's date as the date attribute. +#' Default is \code{TRUE}. +#' @param ... Arbitrary arguments to use with \code{fread} +#' +#' @return A \code{data.table} with an attribute called \code{lb.date} set +#' +#' @examples +#' \dontrun{ +#' # there's a file called "iris-2021-05-08.csv" on disk +#' dat <- fread_plus_date("iris.csv") +#' attribute(dat)$lb.date +#' # [1] "2021-05-08 +#' +#' # can also read the full file name +#' dat <- fread_plus_date("iris-2021-05-08.csv") +#' attribute(dat)$lb.date +#' # [1] "2021-05-08 +#' } +#' +#' @export +fread_plus_date <- function(fname, allow.fallback.date=TRUE, ...){ + dat <- NULL + helper.ret <- fread_plus_helper(fname) + already.date <- stringr::str_extract(helper.ret$before_ext, + "\\d{4}-\\d{2}-\\d{2}$") + if(!is.na(already.date)){ + # already has the date in the filename + fname.to.use <- fname + thedate <- as.Date(already.date) + } else{ + # doesn't already have the date in the filename + fname.to.use <- helper.ret$matching_filename + plus_part <- helper.ret$plus_part + if(plus_part==""){ + if(!allow.fallback.date) + stop("no date in filename found") + message("no date in filename found... using today's date") + thedate <- Sys.Date() + } else { + thedate <- as.Date(plus_part) + } + } + dat <- fread(fname.to.use, ...) + set_lb_attribute(dat, "date", thedate) + dat +} + + + + +#' Write a file with a date appended to the file name. +#' +#' Takes a \code{data.table}, a file name, and writes it with +#' \code{data.table::fwrite}. +#' +#' The supplied file name will be modified to include an ISO 8601 date +#' (yyyy-mm-dd) between the file name and the file extension. Under the +#' default settings, the date used will be from the \code{lb.date} +#' attribute of the supplied \code{data.table}. If there is no \code{lb.date} +#' attribute, the current date will be used, instead. +#' +#' For example, if there is a \code{data.table} with an \code{lb.date} +#' attribute of "2021-05-08", and you supply this function with the file +#' name "iris.csv", the file name actually written to disk will be +#' "iris-2021-05-08.csv". Under the default settings, if there is no +#' \code{lb.date} attribute, but today's date is "2038-01-19", the file +#' name written to disk will be "iris-2038-01-19.csv". +#' +#' The ISO 8601 date is sandwiched between the file name and the file +#' extension. The file extension is considered to be anything after the +#' first period in the base name. +#' For example, if the file name given is "./my.data/iris.csv.gz", the +#' extension is ".csv.gz". This means no period can be present in +#' the base file name (after any directories) with the exception of +#' the file extension. +#' +#' @importFrom data.table fread fwrite setattr +#' +#' @param DT a \code{data.table} to write to disk +#' @param fname The file name to write the \code{data.table} to. The +#' date will be appended between the file name and its +#' file extension +#' @param from.attribute A logical indicating whether the date should +#' be taken from the \code{lb.date} attribute of +#' the \code{data.table}, or whether it should be +#' today's date. Default (\code{TRUE}) takes it +#' from the \code{lb.date} attribute. +#' @param allow.fallback.date A logical indicating, if there is no +#' \code{lb.date} attribute in the supplied +#' \code{data.table}, whether it is permissible +#' to use today's date, instead. +#' Default is \code{TRUE}. +#' @param ... Arbitrary arguments to pass to \code{fwrite} +#' +#' @examples +#' \dontrun{ +#' +#' set_lb_date(iris, "2021-05-08") +#' fwrite_plus_date(iris, "iris.csv.gz") +#' # "iris-2021-05-08.csv.gz" is now written to disk +#' +#' } +#' +#' @export +fwrite_plus_date <- function(DT, fname, from.attribute=TRUE, + allow.fallback.date=TRUE, ...){ + pieces <- split_extension(fname) + if(from.attribute){ + tmp <- attr(DT, "lb.date") + if(is.null(tmp) || is.na(tmp)){ + if(allow.fallback.date){ + message("DT has no usable date attribute... using today's date") + thedate <- Sys.Date() + } else { + stop("DT has no usable date attribute") + } + } else{ + thedate <- tmp + } + } else { + thedate <- Sys.Date() + } + newfname <- sprintf("%s-%s%s", pieces[1], thedate, pieces[2]) + fwrite(DT, newfname, ...) +} + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/split-map-filter-reduce.R b/libbib.Rcheck/00_pkg_src/libbib/R/split-map-filter-reduce.R new file mode 100755 index 0000000..772fa1c --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/split-map-filter-reduce.R @@ -0,0 +1,216 @@ + + +# --------------------------------------------------------------- # + +#' Return first element of vector +#' +#' Takes a vector and returns the first element +#' Equivalent to Lisp's \code{car} function +#' +#' Originally for use as a reduction function in \code{split_map_filter_reduce} +#' +#' @param x A vector +#' +#' @return Returns first element of vector +#' +#' @seealso \code{\link{split_map_filter_reduce}} +#' +#' @examples +#' library(data.table) +#' car(c(8, 6, 7, 5, 3, 0, 9)) # 8 +#' mt <- as.data.table(mtcars) +#' dt_del_cols(mt, "cyl", "disp", "hp") +#' +#' @export +car <- function(x){ + return(x[[1]]) +} + +# --------------------------------------------------------------- # + +#' Remove duplicate elements and NAs from a vector +#' +#' Takes a vector and returns the same vector without duplicate +#' elements and without NA values +#' +#' Can be used as a filtering function in \code{split_map_filter_reduce} +#' +#' @param x A vector +#' +#' @return Returns vector with duplicates and NAs removed +#' +#' @seealso \code{\link{split_map_filter_reduce}} +#' +#' @examples +#' +#' remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) +#' # 8 6 7 5 3 0 9 +#' +#' remove_duplicates_and_nas(c(NA, NA)) +#' # NA +#' +#' @export +remove_duplicates_and_nas <- function(x){ + x <- x[!is.na(x) & !duplicated(x)] + if(!length(x)) + return(NA) + return(x) +} + +# --------------------------------------------------------------- # + +#' Return a function that will combine/contatenate a vector +#' +#' This function takes and optional separator, and returns +#' a function that takes a vector and \code{paste}s the +#' elements of that vector together +#' +#' Can be used as a reduction function in \code{split_map_filter_reduce} +#' +#' @param sep A character to use in between the elements +#' (default is a semicolon character) +#' +#' @return Returns a closure/function +#' +#' @seealso \code{\link{split_map_filter_reduce}} +#' @seealso \code{\link{paste}} +#' +#' @examples +#' +#' lambda <- recombine_with_sep_closure() +#' lambda(c(8, 6, 7)) # "8;6;7" +#' +#' # directly +#' recombine_with_sep_closure()(c(8,6,7)) # "8;6;7" +# +#' lambda <- recombine_with_sep_closure(" ") +#' lambda(c("this", "that", NA,"the-other")) # "this that NA the-other" +#' +#' @export +recombine_with_sep_closure <- function(sep=";"){ + function(x){ + if(length(x)==1 && is.na(x)) + return(NA) + paste(x, collapse=sep, sep=sep) + } +} + +# --------------------------------------------------------------- # + +#' Split, Map, Filter, and Reduce a string vector +#' +#' This function takes a vector of strings, splits those strings +#' on a particular character; string; or regex pattern, applies a +#' user-specified function to each sub-element of the now split element, +#' filters those sub-elements using a user-specified function, and, finally, +#' recombines each element's sub-elements using a user specified reduction +#' function. +#' +#' Since this operation cannot be vectorized, if the user specifies +#' a non-zero \code{cl} argument, the workload will be parallelized +#' and \code{cl} many child processes will be spawned to do the work. +#' The package \code{pbapply} will be used to do this. +#' +#' See \code{examples} for more information and ideas on why this +#' might be useful for, as an example, batch normalizing ISBNs that, +#' for each bibliographic record, is separated by a semicolon +#' +#' @import pbapply +#' +#' @param x A vector of strings +#' @param sep A character to use containing a character, string, or +#' regular expression pattern to split each element by. +#' If \code{fixed=TRUE}, the separator will be used exactly; +#' If not, a Perl-compatible regular expression can be used +#' (default is ";") +#' @param fixed Should it be split by a fixed string/character or +#' a regular expression (default is \code{TRUE}) +#' @param mapfun A vectorized function that will be applied to the +#' sub-elements (after splitting) of each element in x +#' (default is \code{identity} which would leave the +#' sub-elements unchanged) +#' @param filterfun A vectorized function that, when given a vector +#' returns the same vector with un-wanted elements +#' removed +#' (default is \code{identity} which would not remove +#' any sub-elements) +#' @param reduxfun A vectorized function that, when given a vector, +#' will combine all of it's elements into one value +#' (default is \code{car}, which would return the first +#' element only) +#' @param cl An integer to indicate the number of child processes +#' should be used to parallelize the work-load. If 0, +#' the workload will not be parallelized. Can also +#' take a cluster object created by 'makeCluster' +#' (default is 0) +#' +#' @return Returns a vector +#' +#' @seealso \code{\link{car}} +#' @seealso \code{\link{remove_duplicates_and_nas}} +#' @seealso \code{\link{recombine_with_sep_closure}} +#' +#' @examples +#' +#' someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", +#' "1861897952; 978-1-86189-795-4") +#' +#' # will return only the first ISBN for each record +#' split_map_filter_reduce(someisbns) +#' # "9782711875177" "1861897952" +#' +#' # will return only the first ISBN for each record, after normalizing +#' # each ISBN +#' split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}) +#' # "9782711875177" "9781861897954" +#' +#' # will return all ISBNs, for each record, separated by a semicolon +#' # after applying normalize_isbn to each ISBN +#' # note the duplicates introduced after normalization occurs +#' split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, +#' reduxfun=recombine_with_sep_closure()) +#' # "9782711875177;NA;9782711875177;9782844268907" "9781861897954;9781861897954" +#' +#' # After splitting each items ISBN list by semicolon, this runs +#' # normalize_isbn in each of them. Duplicates are produced when +#' # an ISBN 10 converts to an ISBN 13 that is already in the ISBN +#' # list for the item. NAs are produced when an ISBN fails to normalize. +#' # Then, all duplicates and NAs are removed. Finally, the remaining +#' # ISBNs, for each record, are pasted together using a space as a separator +#' split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, +#' filterfun=remove_duplicates_and_nas, +#' reduxfun=recombine_with_sep_closure(" ")) +#' # "9782711875177 9782844268907" "9781861897954" +#' +#' @export +split_map_filter_reduce <- function(x, sep=";", fixed=TRUE, + mapfun=identity, filterfun=identity, + reduxfun=car, cl=0){ + # function to process just one element of x + do_just_one <- function(astring, sep=";", fixed=FALSE, + mapfun=identity, filterfun=identity, + reduxfun=car){ + thesplit <- unlist(strsplit(astring, sep, fixed=fixed, perl=!fixed)) + thesplit <- mapfun(thesplit) + thesplit <- filterfun(thesplit) + thesplit <- reduxfun(thesplit) + thesplit + } + if(cl==0){ + ret <- sapply(x, function(y) do_just_one(y, sep=sep, fixed=fixed, + mapfun=mapfun, filterfun=filterfun, + reduxfun=reduxfun)) + } else { + ret <- pbapply::pbsapply(x, function(y) do_just_one(y, sep=sep, fixed=fixed, + mapfun=mapfun, + filterfun=filterfun, + reduxfun=reduxfun), + USE.NAMES=FALSE, cl=cl) + } + ret <- unlist(ret) + names(ret) <- NULL + ret +} + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/the-web.R b/libbib.Rcheck/00_pkg_src/libbib/R/the-web.R new file mode 100755 index 0000000..3af825b --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/the-web.R @@ -0,0 +1,217 @@ + +#' Get Library of Congress catalog permalinks from LCCNs +#' +#' Takes a string representation of an LCCNs. Returns permalinks +#' to the Library of Congress catalog entries using those LCCNs. +#' +#' @param x A string (or vector of strings) of LCCNs +#' @param normalize a logical indicating whether the LCCN should be +#' normalized prior to creating the permalink +#' (default is \code{TRUE}) +#' @param format One of "", "marcxml", "mods", "mads", or "dublin" to return +#' the link to the main permalink page, or the link directly +#' to the record's MARCXml, MODS, MADS, or Dublin Core +#' representation, respectively. +#' +#' @details +#' If normalize=TRUE and the LCCN is invalid, the permalink is NA. +#' If normalize=FALSE, the permalink may be invalid. No validity +#' check on the URL is performed +#' +#' @return Library of Congress permalinks using LCCNs. +#' +#' @examples +#' loc_permalink_from_lccn("n78-890351") # "https://lccn.loc.gov/n78890351" +#' loc_permalink_from_lccn("85-2 ") # "https://lccn.loc.gov/85000002" +#' loc_permalink_from_lccn("75-425165//r75") # "https://lccn.loc.gov/75425165" +#' +#' # vectorized +#' loc_permalink_from_lccn(c("###78890351#", NA, "n78-890351")) +#' +#' # MARCXML metadata format +#' loc_permalink_from_lccn("73167510", format="marcxml") +#' # "https://lccn.loc.gov/73167510/marcxml" +#' +#' @export +#' @importFrom data.table fcase +loc_permalink_from_lccn <- function(x, normalize=TRUE, format=""){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + + postfix <- fcase(format=="", "", + format=="marcxml", "/marcxml", + format=="mods", "/mods", + format=="mads", "/mads", + format=="dublin", "/dc", + (!(format %in% c("marcxml", "mods", "mads", "dublin"))), + stop('format must be one of "", "marcxml", "mods", "mads", or "dublin"')) + + if(normalize) + x <- normalize_lccn(x) + + ifelse(is.na(x), NA_character_, + sprintf("https://lccn.loc.gov/%s%s", x, postfix)) +} + + +#' Get WorldCat catalog permalinks from ISSNs +#' +#' Takes a string representation of ISSNs. Returns permalinks +#' to the WorldCat catalog entries using those ISSNs. +#' +#' @param x A string (or vector of strings) of ISSNs +#' @param normalize a logical indicating whether the ISSNs should be +#' normalized prior to creating the permalink +#' (default is \code{TRUE}) +#' +#' @details +#' If normalize=TRUE and the ISSN is invalid, the permalink is NA. +#' If normalize=FALSE, the permalink may be invalid. No validity +#' check on the URL is performed +#' +#' @return Worldcat permalinks using ISSNs. +#' +#' @examples +#' worldcat_permalink_from_issn("0968-1221") # http://www.worldcat.org/issn/0968-1221 +#' +#' worldcat_permalink_from_issn("2434-561X") # http://www.worldcat.org/issn/2434561X +#' +#' # vectorized +#' worldcat_permalink_from_issn(c("0968-1221", NA, "2434-561X")) +#' +#' @export +worldcat_permalink_from_issn <- function(x, normalize=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + if(normalize) + x <- normalize_issn(x) + + ifelse(is.na(x), NA_character_, + sprintf("http://www.worldcat.org/issn/%s", x)) +} + + +#' Get WorldCat catalog permalinks from ISBNs +#' +#' Takes a string representation of ISBNs. Returns permalinks +#' to the WorldCat catalog entries using those ISBNs. +#' +#' @param x A string (or vector of strings) of ISBNs +#' @param normalize a logical indicating whether the ISBNs should be +#' normalized prior to creating the permalink +#' (default is \code{TRUE}) +#' +#' @details +#' If normalize=TRUE and the ISBN is invalid, the permalink is NA. +#' If normalize=FALSE, the permalink may be invalid. No validity +#' check on the URL is performed +#' +#' @return Worldcat permalinks using ISBNs. +#' +#' @examples +#' +#' worldcat_permalink_from_isbn("1788393724") +#' # http://www.worldcat.org/isbn/1788393724 +#' +#' worldcat_permalink_from_isbn("0-124-91540-X") +#' # http://www.worldcat.org/isbn/012491540X +#' +#' worldcat_permalink_from_isbn("0-124-91540-X", normalize=FALSE) +#' # http://www.worldcat.org/isbn/0-124-91540-X +#' +#' # vectorized +#' worldcat_permalink_from_isbn(c("1788393724", NA, "0-124-91540-X")) +#' +#' @export +worldcat_permalink_from_isbn <- function(x, normalize=TRUE){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + if(normalize) + x <- normalize_isbn(x) + + ifelse(is.na(x), NA_character_, + sprintf("http://www.worldcat.org/isbn/%s", x)) +} + + +#' Get WorldCat catalog permalinks from OCLC numbers +#' +#' Takes a string representation of OCLC numbers. Returns permalinks +#' to the WorldCat catalog entries using those OCLC numbers +#' +#' @param x A string (or vector of strings) of OCLC numbers +#' +#' @details +#' No validity check on the URL is performed +#' +#' @return Worldcat permalinks using the OCLC numbers +#' +#' @examples +#' +#' worldcat_permalink_from_oclc_number("1005106045") +#' # http://www.worldcat.org/oclc/1005106045 +#' +#' # vectorized +#' worldcat_permalink_from_oclc_number(c("1049727704", NA, +#' "1005106045")) +#' +#' @export +worldcat_permalink_from_oclc_number <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + x <- stringr::str_replace_all(x, "\\s", "") + ifelse(is.na(x), NA_character_, + sprintf("http://www.worldcat.org/oclc/%s", x)) +} + + + +#' Get OCLC Classify link from a standard number +#' +#' Takes a string representation of ISSNs, ISBNs, UPC, +#' or OCLC numbers. +#' Returns a link to the OCLC's experimental classify +#' service which provides the most frequent call numbers, +#' FAST subject headings, etc... +#' +#' @param x A string (or vector of strings) of a standard number. +#' Must be an ISSN, ISBN, UPC, and/or OCLC numbers. +#' +#' @details +#' Since this can take a variety of standard numbers, no +#' normalization can be performed. The numbers much be normalized +#' before the call to this function. +#' No validity check on the URL is performed +#' +#' @return Links to OCLC's Classify web service +#' +#' @examples +#' +#' oclc_classify_link_from_standard_num("629725006") +#' # "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" +#' +#' oclc_classify_link_from_standard_num(c("039333712X", NA, "629725006")) +#' # [1] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=039333712X&startRec=0" +#' # [2] NA +#' # [3] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" +#' +#' @export +oclc_classify_link_from_standard_num <- function(x){ + if(all(is.na(x))) return(as.character(x)) + if(!methods::is(x, "character")) + stop("Input must be a character string") + x <- stringr::str_replace_all(x, "\\s", "") + part1 <- "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=" + part2 <- "&startRec=0" + ret <- sprintf("%s%s%s", part1, x, part2) + ret[is.na(x)] <- NA_character_ + return(ret) +} + + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/R/utilities.R b/libbib.Rcheck/00_pkg_src/libbib/R/utilities.R new file mode 100755 index 0000000..d761264 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/R/utilities.R @@ -0,0 +1,502 @@ + +## various utility functions + + +# --------------------------------------------------------------- # + +#' Delete columns in a data.table +#' +#' Takes a data.table and a quoted sequence of column names +#' and removes the specified column names from the data.table +#' +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames +#' +#' @param DT A data.table +#' @param ... arbitrary number of column names in quotes +#' +#' @return Returns data.table with those columns removed +#' +#' @examples +#' library(data.table) +#' mt <- as.data.table(mtcars) +#' dt_del_cols(mt, "cyl", "disp", "hp") +#' +#' @export +dt_del_cols <- function(DT, ...){ + if(!methods::is(DT, "data.table")) + stop("DT must be a data.table object") + cols <- c(...) + DT[, (cols):=NULL] +} + + +# --------------------------------------------------------------- # + +#' Keep columns in a data.table +#' +#' Takes a data.table and a quoted sequence of column names +#' and removes all columns but the ones specified +#' +#' @importFrom data.table := %chin% .N as.data.table copy data.table setnames +#' +#' @param DT A data.table +#' @param ... arbitrary number of column names in quotes +#' +#' @return Returns data.table with only those columns +#' +#' @examples +#' library(data.table) +#' mt <- as.data.table(mtcars) +#' dt_keep_cols(mt, "mpg", "am", "gear", "carb") +#' +#' @export +dt_keep_cols <- function(DT, ...){ + if(!methods::is(DT, "data.table")) + stop("DT must be a data.table object") + cols <- c(...) + badp <- setdiff(cols, names(DT)) + if(length(badp)){ + missingnames <- paste(sprintf('"%s"', badp), collapse=', ') + warning(sprintf("Columns (%s) are missing from supplied data.table", + missingnames)) + } + these <- setdiff(names(DT), cols) + dt_del_cols(DT, these) +} + + +# --------------------------------------------------------------- # + +### INTERNAL FUNCTION +## examples: +# iris_dt <- as.data.table(iris) +# dt_pivot(iris_dt, "Species", mean(Petal.Length), value.name="mean_petal_length") +# dt_pivot(iris_dt, "Species", sum(Petal.Length), value.name="mean_petal_length", +# percent.cutoff=20) +# +# # breaks +# dt_pivot(iris_dt, "Species", .N, percent.name="tmp", value.name="tmp") +# dt_pivot(iris_dt, "Sp", .N) +# dt_pivot(iris_dt, "Species", sum(nothing)) +dt_pivot <- function(DT, theby, theexp, percent.cutoff=0, value.name="value", + percent.name="percent_count"){ + if(value.name == percent.name) + stop("value name and percent name cannot be the same") + + val <- percent <- . <- NULL + + inexp <- substitute(theexp) + strexp <- as.character(deparse(inexp)) + template <- sprintf("DT[, .(val=%s), theby][order(-val)]", strexp) + tmp <- eval(parse(text=template)) + thetotal <- tmp[, sum(val)] + tmp[, percent:=round(val/thetotal*100, 2)] + tmp[percent0){ + missingnames <- check[is.na(here), old_names] + missingnames <- paste(sprintf('"%s"', missingnames), collapse=', ') + warning(sprintf("Columns (%s) are missing from supplied data.table", + missingnames)) + } + } + + if(prefix) + tmp[,new_names:=sprintf("%s%s", astring, old_names)] + else + tmp[,new_names:=sprintf("%s%s", old_names, astring)] + + if(!is.null(exclude)) + tmp[old_names %chin% exclude, new_names:=old_names] + if(!is.null(include)) + tmp[!(old_names %chin% include), new_names:=old_names] + + if(tmp[,sum(duplicated(new_names))]){ + if(fix.duplicates){ + message("cleaned names contain duplicates... correcting") + tmp[, new_names:=make.unique(new_names, sep="_")] + } + else + stop("not resetting column names... new names contain duplicates") + } + + setnames(DT, tmp[,new_names]) +} + + +# --------------------------------------------------------------- # + +# unexported function to assist with WorldCat Search API SRU queries +sru_syntax_translate_worldcat <- function(x){ + index.xlation.table <- list( + c("srw.kw", "\\$keyword"), + c("srw.ti", "\\$title"), + c("srw.ln", "\\$language"), + c("srw.au", "\\$author"), + c("srw.yr", "\\$year"), + c("srw.su", "\\$subject"), + c("srw.li", "\\$holding_library"), + c("srw.mt", "\\$material_type"), + c("srw.no", "\\$oclc"), + c("srw.lc", "\\$lc_call"), + c("srw.dd", "\\$dewey"), + c("srw.dn", "\\$lccn"), + c("srw.bn", "\\$isbn"), + c("srw.in", "\\$issn"), + c("srw.cg", "\\$library_holdings_group"), + c("srw.la", "\\$language_code"), + c("srw.pl", "\\$place_of_publication"), + c("srw.pb", "\\$publisher"), + c("srw.am", "\\$access_method"), + c("srw.cn", "\\$corporate_conference_name"), + c("srw.pc", "\\$dlc_limit"), + c("srw.dt", "\\$document_type"), + c("srw.gn", "\\$government_document_number"), + c("srw.mn", "\\$music_publisher_number"), + c("srw.nt", "\\$notes"), + c("srw.on", "\\$open_digital_limit"), + c("srw.pn", "\\$personal_name"), + c("srw.se", "\\$series"), + c("srw.sn", "\\$standard_number") + ) + + xlate.each.index.one <- function(y){ + x <<- stringr::str_replace_all(x, + # negative lookbehind assertion + sprintf('(?1) stop("only accepts one standard number at a time") + if(is.na(thenumber)) return(NULL) + if(!methods::is(thenumber, "character")) + stop("ISBN, ISSN, or OCLC number must be a string") + + template <- "http://classify.oclc.org/classify2/Classify?%s=%s&summary=true" + api_response <- worldcat_api_get_http_response(sprintf(template, thetype, thenumber), + print.api.responses=debug) + content <- api_response$content + + if(debug){ + message("\nClassify API response:") + message(content, appendLF=FALSE) + message("End of Classify API response\n") + } + + http_status_code <- api_response$http_status_code + exemel <- xml2::read_xml(content, options=NULL) + xml2::xml_ns_strip(exemel) + + resp_code <- as.integer(xml2::xml_attr(xml2::xml_find_first(exemel, + "//classify/response"), + "code")) + + # work title, author, holdings, etc.. + work <- xml2::xml_find_first(exemel, "//classify/work") + work_title <- xml2::xml_attr(work, "title") + work_author <- xml2::xml_attr(work, "author") + work_holdings <- xml2::xml_attr(work, "holdings") + work_eholdings <- xml2::xml_attr(work, "eholdings") + + # dcc + dcc <- xml2::xml_find_first(exemel, + "//classify/recommendations/ddc/mostPopular") + dcc_holdings <- xml2::xml_attr(dcc, "holdings") + dcc_sfa <- xml2::xml_attr(dcc, "sfa") + dcc_frame <- data.table(standard_number=thenumber, + call_type="DDC", + holdings=dcc_holdings, + recommendation=dcc_sfa) + + # lcc + lcc <- xml2::xml_find_first(exemel, + "//classify/recommendations/lcc/mostPopular") + lcc_holdings <- xml2::xml_attr(lcc, "holdings") + lcc_sfa <- xml2::xml_attr(lcc, "sfa") + lcc_frame <- data.table(standard_number=thenumber, + call_type="LCC", + holdings=lcc_holdings, + recommendation=lcc_sfa) + + retframe <- rbindlist(list(dcc_frame, lcc_frame)) + setnames(retframe, "standard_number", thetype) + retframe[, `:=`(classify_response_code=resp_code, + http_status_code=http_status_code, + title=work_title, author=work_author, + total_holdings=as.integer(work_holdings), + total_eholdings=as.integer(work_eholdings))] + setcolorder(retframe, c(thetype, "title", "author", + "total_holdings", "total_eholdings", "call_type", + "recommendation", "holdings", "http_status_code", + "classify_response_code")) + return(retframe[]) +} + + + +#' Search WorldCat classify API by ISBN, ISSN, or OCLC number +#' +#' Access the results of a WorldCat classify API search by ISBN, ISSN, +#' or OCLC number to get the most frequent call numbers (DDC and LCC) +#' associated with a work. Returns a \code{data.table} with those call +#' numbers and various other metadata. See "Details" for more information. +#' +#' @details +#' The returned \code{data.table} contains fields for various pieces of +#' metadata returned by the API request. These fields include the +#' ISBN/ISSN/OCLC number used, title of work, author, total number of +#' holdings, total number of electronic holdings, call number type, +#' call number recommendation (by most popular), number of holdings +#' using that call number, the HTTP status code, and the Classify +#' API response code. +#' +#' For each ISBN/ISSN/OCLC number used, two rows will be returned; one for +#' the DDC and one for the LCC. Common information (work metadata) +#' will the the same in both rows. If one of the call numbers is missing, +#' the recommendation and holdings fields will be NA. +#' +#' The API can be persnickety, and there are many things that can go +#' wrong. For example, the API can respond with multiple works for a +#' single standard number (ISBN 9780900565748, for example). If this happens, +#' no attempt is made to follow one of the results, and the returned +#' \code{data.table} will return no useful information. +#' +#' If the \code{http_status_code} is 200 and the \code{classify_response_code} +#' is 0, you've received good results.If the \code{classify_response_code} is +#' 4, the standard number may have returned multiple works. +#' +#' The \code{http_status_code} should never not be 200. +#' +#' If something went wrong (for example, the status/response codes are not +#' 200 and 0, respectively), you may want to re-run the function call with +#' \code{print.api.responses} set to \code{TRUE}. This will print the +#' HTTP status code and the raw XML text response from the API. +#' +#' As with all API access functions in this package, it's up to the +#' user to limit their API usage so as to not get blocked. These +#' functions are deliberately not vectorized for this reason; they +#' only accept one standard number at a time. +#' +#' Final note: all of these API functions seem to work better with +#' OCLC numbers than any other standard number. If multiple standard +#' numbers are available, using the OCLC number is always preferred. +#' +#' @param x A string representation of the standard number that the function +#' chosen accepts. +#' @param debug A logical indicating whether the HTTP and classify API +#' responses should be printed (for debugging) +#' (default is \code{FALSE}) +#' +#' @return A \code{data.table} with most popular DDC and LCC call numbers +#' and various other metadata. See "Details" for more information. +#' +#' @examples +#' +#' \dontrun{ +#' worldcat_api_classify_by_oclc("93976650") +#' # oclc title author total_holdings total_eholdings call_type +#' # +#' # 1: 939766505 Lobster King, Richard J. 244 534 DDC +#' # 2: 939766505 Lobster King, Richard J. 244 534 LCC +#' # recommendation holdings http_status_code classify_response_code +#' # +#' # 1: 641.395 767 200 0 +#' # 2: QL444.M33 318 200 0 +#' +#' } +#' +#' @name worldcat_api_classify_by + + +#' @rdname worldcat_api_classify_by +#' @export +worldcat_api_classify_by_oclc <- function(x, debug=FALSE){ + worldcat_api_classify("oclc", x, debug=debug) +} + +#' @rdname worldcat_api_classify_by +#' @export +worldcat_api_classify_by_isbn <- function(x, debug=FALSE){ + worldcat_api_classify("isbn", x, debug=debug) +} + +#' @rdname worldcat_api_classify_by +#' @export +worldcat_api_classify_by_issn <- function(x, debug=FALSE){ + worldcat_api_classify("issn", x, debug=debug) +} + + + +# --------------------------------------------------------------- # + +#################################### +### BIB READ API ### +#################################### + +read_a_marcxml_record <- function(exemel, more=FALSE){ + + if(is.na(exemel)) + return(NULL) + if(is.null(exemel)) + return(NULL) + + leader <- oh08 <- publisher <- NULL + + xml2::xml_ns_strip(exemel) + + TITLEXPATH <- "datafield[@tag='245']/subfield[@code='a']" + AUTHORXPATH <- "datafield[@tag='100']/subfield[@code='a']" + OCLCXPATH <- "controlfield[@tag='001']" + ISBNXPATH <- "datafield[@tag='020']/subfield[@code='a']" + ISSNXPATH <- "datafield[@tag='022']/subfield[@code='a']" + LEADERXPATH <- "leader" + OH08XPATH <- "controlfield[@tag='008']" + + # more + PUBLISHXPATH <- "datafield[@tag='260']/subfield[@code='b']" + # TOPICALXPATH <- "datafield[@tag='650']/subfield[@code='b']/[contains(. 'fast')]" + + the_title <- xml2::xml_text(xml2::xml_find_first(exemel, TITLEXPATH)) + the_author <- xml2::xml_text(xml2::xml_find_first(exemel, AUTHORXPATH)) + the_oclc <- xml2::xml_text(xml2::xml_find_first(exemel, OCLCXPATH)) + the_isbn <- xml2::xml_text(xml2::xml_find_first(exemel, ISBNXPATH)) + the_issn <- xml2::xml_text(xml2::xml_find_first(exemel, ISSNXPATH)) + the_leader <- xml2::xml_text(xml2::xml_find_first(exemel, LEADERXPATH)) + the_oh08 <- xml2::xml_text(xml2::xml_find_first(exemel, OH08XPATH)) + the_isbn <- normalize_isbn(the_isbn, convert.to.isbn.13=TRUE) + the_issn <- normalize_issn(the_issn) + + final <- data.table(oclc=the_oclc, isbn=the_isbn, issn=the_issn, + title=the_title, author=the_author, leader=the_leader, + oh08=the_oh08) + + if(more){ + final[, publisher:=xml2::xml_text(xml2::xml_find_first(exemel, PUBLISHXPATH))] + li <- marc_leader_get_info(final[1, leader]) + oi <- marc_008_get_info(final[1, oh08]) + final <- cbind(final, li, oi) + # all_fast_topical_terms <- xml2::xml_text(xml2::xml_find_all(exemel, TOPICALXPATH)) + # print(all_fast_topical_terms) + setcolorder(final, c("oclc", "isbn", "issn", "title", "author", "pub_date", + "lang_code", "bib_level", "record_type", + "pub_place_code", "publisher", "leader", "oh08")) + } + + final[] +} + + +worldcat_api_bib_read_info_by_something <- function(x, + type_std_num="oclc", + wskey=getOption("libbib.wskey", NULL), + more=FALSE, + debug=FALSE){ + # error checking + if(length(x)>1) stop("only accepts one standard number at a time") + if(is.na(x)) return(NULL) + if(!methods::is(x, "character")) + stop("x must be a string or NULL") + if(!(type_std_num %chin% c("oclc", "isbn", "issn"))) + stop('type of standard number must be "oclc", "isbn", or "issn"') + if(is.null(wskey)) + stop("a WSKEY (WorldCat API key) must be specified") + + + template <- "http://www.worldcat.org/webservices/catalog/content/%s%s?wskey=%s" + fullurl <- sprintf(template, + fcase(type_std_num=="oclc", "", + type_std_num=="isbn", "isbn/", + type_std_num=="issn", "issn/"), + x, wskey) + + if(debug) + message("\nFull Bib Read API call url:\n", fullurl) + + resp <- worldcat_api_get_http_response(fullurl, print.api.responses=debug) + content <- resp$content + + if(debug){ + message("\nBib Read API response:") + message(content, appendLF=FALSE) + message("End of Bib Read API response\n") + } + + exemel <- xml2::read_xml(content, options=NULL) + xml2::xml_ns_strip(exemel) + + final <- read_a_marcxml_record(exemel, more=more) + + return(final[]) +} + + +#' Get bibliographic info from a standard number +#' +#' Access the results of a WorldCat bib read API search by ISBN, ISSN, +#' or OCLC number. The MARCXML returned by the API is parsed and the +#' function returns a \code{data.table} containing the oclc number, +#' ISBN, ISSN, title, author, MARC leader, and the 008 control field, +#' respectively. +#' +#' @details +#' Though this function gets all standard numbers (OCLC, ISBN, ISSN) +#' from the MARCXML, the standard number that was supplied to the function +#' will be the one in the returned \code{data.table}. For example, if +#' you use \code{worldcat_api_bib_read_info_by_isbn}, the returned +#' \code{data.table} will have that ISBN in the ISBN column, not the +#' ISBN in the MARC record. +#' +#' If something went wrong, all columns (except the one corresponding to +#' the supplied standard number) will be NA. +#' +#' This function is helpful to call before attempting to use +#' the Location and Classify API functions as it will ensure that +#' the supplied standard number actually resolves to a OCLC work. +#' +#' As with all API access functions in this package, it's up to the +#' user to limit their API usage so as to not get blocked. These +#' functions are deliberately not vectorized for this reason; they +#' only accept one standard number at a time. +#' +#' This (and other) WorldCat API communication functions require a +#' WorldCat API key. The easiest way to use these functions is to +#' set a global options with your key: +#' \code{options("libbib.wskey"="YOUR KEY HERE")} +#' +#' Final note: all of these API functions seem to work better with +#' OCLC numbers than any other standard number. If multiple standard +#' numbers are available, using the OCLC number is always preferred. +#' +#' @param x A string representation of the standard number that the function +#' chosen accepts. +#' @param wskey A WorldCat API key (default is \code{getOption("libbib.wskey")}) +#' @param more A logical indicating whether more infomation from the MARCXML +#' should be returned (publisher, bib level etc....) In the +#' interest of memory consumption, the default is \code{FALSE} +#' @param debug A logical indicating whether the HTTP and bib read API +#' responses should be printed (for debugging) +#' (default is \code{FALSE}) +#' +#' @return A \code{data.table} containing the OCLC number, ISBN, ISSN, +#' title, author, MARC leader, and the 008 control field, +#' respectively, +#' +#' @examples +#' +#' \dontrun{ +#' worldcat_api_bib_read_info_by_isbn("9780984201006") +#' # oclc isbn issn title +#' # +#' # 1: 462894360 9780984201006 The Great Debate about Art / +#' # author leader +#' # +#' # 1: Harris, Roy, 00000cam a2200000 a 4500 +#' # oh08 +#' # +#' # 1: 091031s2010 ilua b 000 0 eng c +#' +#' worldcat_api_bib_read_info_by_issn("13602365") +#' # oclc isbn issn title author +#' # +#' # 1: 37787277 14664410 The journal of architecture. +#' # leader oh08 +#' # +#' # 1: 00000cas a2200000 a 4500 971015c19969999enkbx pso 0 a0eng c +#' +#' } +#' +#' @name worldcat_api_bib_read_info_by + +#' @rdname worldcat_api_bib_read_info_by +#' @export +worldcat_api_bib_read_info_by_oclc <- function(x, + wskey=getOption("libbib.wskey", NULL), + more=FALSE, + debug=FALSE){ + # error checking + if(length(x)>1) stop("only accepts one standard number at a time") + if(is.na(x)) return(NULL) + if(!methods::is(x, "character")) + stop("x must be a string or NULL") + + oclc <- NULL + ret <- worldcat_api_bib_read_info_by_something(x, type_std_num="oclc", + wskey=wskey, more=more, + debug=debug) + ret[, oclc:=x] + return(ret[]) +} + +#' @rdname worldcat_api_bib_read_info_by +#' @export +worldcat_api_bib_read_info_by_isbn <- function(x, + wskey=getOption("libbib.wskey", NULL), + more=FALSE, + debug=FALSE){ + # error checking + if(length(x)>1) stop("only accepts one standard number at a time") + if(is.na(x)) return(NULL) + if(!methods::is(x, "character")) + stop("x must be a string or NULL") + + isbn <- NULL + ret <- worldcat_api_bib_read_info_by_something(x, type_std_num="isbn", + wskey=wskey, more=more, + debug=debug) + ret[, isbn:=x] + return(ret[]) +} + +#' @rdname worldcat_api_bib_read_info_by +#' @export +worldcat_api_bib_read_info_by_issn <- function(x, + wskey=getOption("libbib.wskey", NULL), + more=FALSE, + debug=FALSE){ + # error checking + if(length(x)>1) stop("only accepts one standard number at a time") + if(is.na(x)) return(NULL) + if(!methods::is(x, "character")) + stop("x must be a string or NULL") + + issn <- NULL + ret <- worldcat_api_bib_read_info_by_something(x, type_std_num="issn", + wskey=wskey, + more=more, debug=debug) + ret[, issn:=x] + return(ret[]) +} + + + + +# --------------------------------------------------------------- # + +#################################### +### LOCATION API ### +#################################### + +# un-exported (but tested) helper function +construct_wcapiloc_url <- function(stdnum, + type_std_num="oclc", + location="10032", + max_libraries=100, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + start_at=1, + wskey=getOption("libbib.wskey", NULL)){ + + # error checking + if(!methods::is(stdnum, "character")) + stop("standard number must be a string") + if(!methods::is(max_libraries, "numeric")) + stop("max_libraries must be a number between 1 and 100") + if(max_libraries < 1 || max_libraries > 100) + stop("max_libraries must be a number between 1 and 100") + if(!is.null(location) && !methods::is(location, "character")) + stop("location must be a string or NULL") + if(!(type_std_num %chin% c("oclc", "isbn", "issn"))) + stop('type of standard number must be "oclc", "isbn", or "issn"') + if(!(servicelevel %chin% c("full", "default"))) + stop('service level must be "full" or "default"') + if(!(frbrGrouping %chin% c("on", "off"))) + stop('frfbGrouping must be "on" or "off"') + if(!is.null(libtype) && !(libtype %chin% c("academic", "public", "government", "other"))) + stop('libtype must be either NULL, "academic", "public", "government", or "other"') + if(!methods::is(start_at, "numeric")) + stop("start_at must be a number") + if(is.null(wskey)) + stop("a WSKEY (WorldCat API key) must be specified") + + building <- "http://www.worldcat.org/webservices/catalog/content/libraries/" + + # standard number + building <- sprintf("%s%s%s?", building, fcase(type_std_num=="isbn", "isbn/", + type_std_num=="issn", "issn/", + default=""), stdnum) + + # location + building <- sprintf("%s%s", building, + ifelse(!is.null(location), + sprintf("location=%s&", location), "")) + + # max libraries + building <- sprintf("%s%s", building, + sprintf("maximumLibraries=%s&", max_libraries)) + + # service level + building <- sprintf("%s%s", building, + sprintf("servicelevel=%s&", servicelevel)) + + # frbr grouping + building <- sprintf("%s%s", building, + sprintf("frbrGrouping=%s&", frbrGrouping)) + + # lib type + building <- sprintf("%s%s", building, + ifelse(!is.null(libtype), + sprintf("libtype=%s&", + fcase(libtype=="academic", "1", + libtype=="public", "2", + libtype=="government", "3", + libtype=="other", "4")), "")) + + # start at + building <- sprintf("%s%s&", building, sprintf("startLibrary=%s", start_at)) + + # wskey + building <- sprintf("%swskey=%s", building, wskey) + + return(building) +} + + +worldcat_api_locations_helper <- function(x, + type_std_num="oclc", + location="10032", + max_libraries=100, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + start_at=1, + wskey=getOption("libbib.wskey", NULL), + debug=FALSE){ + fullurl <- construct_wcapiloc_url(x, type_std_num=type_std_num, + location=location, + max_libraries=max_libraries, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, + libtype=libtype, start_at=start_at, + wskey=wskey) + if(debug) + message("\nFull Location API call url:\n", fullurl) + + resp <- worldcat_api_get_http_response(fullurl, print.api.responses=debug) + content <- resp$content + + if(debug){ + message("\nLocation API response:") + message(content, appendLF=FALSE) + message("End of Location API response\n") + } + + exemel <- xml2::read_xml(content, options=NULL) + xml2::xml_ns_strip(exemel) + + all_holdings <- xml2::xml_find_all(exemel, "//holdings/holding") + all_ident <- xml2::xml_text(xml2::xml_find_first(all_holdings, "institutionIdentifier/value")) + all_locs <- xml2::xml_text(xml2::xml_find_first(all_holdings, "physicalLocation")) + all_hold <- xml2::xml_text(xml2::xml_find_first(all_holdings, "holdingSimple/copiesSummary/copiesCount")) + + if(length(all_holdings)==0) + return(NULL) + + final <- data.table(standard_num=x, + institution_identifier=all_ident, + institution_name=all_locs, + copies=all_hold) + setnames(final, "standard_num", type_std_num) + return(final[]) +} + + +worldcat_api_locations_by_something <- function(x, + type_std_num="oclc", + include.bib.info=TRUE, + location="10032", + max_libraries=Inf, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + wskey=getOption("libbib.wskey", NULL), + print.progress=TRUE, + debug=FALSE){ + # error checking + if(length(x)>1) stop("only accepts one standard number at a time") + if(is.na(x)) return(NULL) + if(!methods::is(x, "character")) + stop("x must be a string or NULL") + + # debug implies print progress + if(debug) print.progress=TRUE + + all_the_way_p <- FALSE + if(is.infinite(max_libraries)){ + all_the_way_p <- TRUE + max_libraries <- 100 + } + + runninglist <- list() + counter <- 1 + starting_at <- 1 + + ret <- worldcat_api_locations_helper(x, type_std_num=type_std_num, + location=location, + max_libraries=max_libraries, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, libtype=libtype, + start_at=1, wskey=wskey, debug=debug) + if(is.null(ret)) + return(NULL) + + bibinfo <- NULL + if(include.bib.info){ + if(debug) + message("Bib info requested; also hitting the Bib Read Info API") + bibinfo <- worldcat_api_bib_read_info_by_something(x, + type_std_num=type_std_num, + wskey=wskey, + debug=debug) + } + + if(!all_the_way_p || ret[,.N]<100){ + if(include.bib.info){ + dt_del_cols(bibinfo, type_std_num) + ret <- cbind(ret, bibinfo) + } + return(ret[]) + } + + runninglist[[counter]] <- ret + last_pull_n_count <- 100 + + while(last_pull_n_count==100){ + starting_at <- 1+(100*counter) + if(print.progress) + message("request ", counter, " pulled ", last_pull_n_count, + " rows... repeating, starting at library number ", starting_at) + + ret <- worldcat_api_locations_helper(x, type_std_num=type_std_num, + max_libraries=max_libraries, + location=location, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, + libtype=libtype, + start_at=starting_at, + wskey=wskey, debug=debug) + if(is.null(ret)){ + last_pull_n_count <- 0 + } else{ + counter <- counter + 1 + runninglist[[counter]] <- ret + last_pull_n_count <- ret[,.N] + } + } + + final <- rbindlist(runninglist) + + if(print.progress) + message("request ", counter, " pulled ", last_pull_n_count, + " rows. Returning data.table with ", final[,.N], " rows in total.\n") + + if(include.bib.info){ + dt_del_cols(bibinfo, type_std_num) + final <- cbind(final, bibinfo) + } + + return(final[]) +} + + +#' Get holding libraries by standard number +#' +#' Access the results of a WorldCat location API search by ISBN, ISSN, +#' or OCLC number. Returns a \code{data.table} with rows corresponding to +#' each holding institution. The columns contain the standard number +#' provided, the institution identifier, the institution name, number +#' of copies held by that insitution, and, by default, the bibliographic +#' information provided by \code{worldcat_api_bib_read_info_by_...}. +#' This information is helpful to ensure thaat the standard number +#' provided successfully resolved to a single OCLC work. +#' +#' Numerous parameters are provided that change the API url +#' parameters. See parameter section for details on each. +#' +#' @details +#' If something went wrong, most columns (especially the bibliographic +#' info columns) will be NA. You should always check the output. +#' +#' As with all API access functions in this package, it's up to the +#' user to limit their API usage so as to not get blocked. These +#' functions are deliberately not vectorized for this reason; they +#' only accept one standard number at a time. +#' +#' This (and other) WorldCat API communication functions require a +#' WorldCat API key. The easiest way to use these functions is to +#' set a global options with your key: +#' \code{options("libbib.wskey"="YOUR KEY HERE")} +#' +#' Final note: all of these API functions seem to work better with +#' OCLC numbers than any other standard number. If multiple standard +#' numbers are available, using the OCLC number is always preferred. +#' In this function, for example, searching for ISSN: 14664410 +#' (Journal of Architecture) will (at time of writing) return only one +#' insitution, whereas searching by it's OCLC number (958283020) will +#' yield many more (660, at time of writing, with default parameters). +#' +#' @param x The standard number to search using. Must be a string. +#' @param include.bib.info A logical indicating whether to include +#' bibliographic metadata associated with the +#' work (provided by +#' \code{worldcat_api_bib_read_info_by_...}). +#' This is very useful for error checking so +#' default is \code{TRUE}. +#' @param location The holding institutions are sorted roughly by geographic +#' proximity to this zip-code, country code, etc... +#' If \code{max_libraries} is \code{Inf} (the default), the +#' starting location doesn't matter since all holding +#' institutions are returned. Defaults to the zip code +#' of Washington Heights, NYC. +#' @param max_libraries The maximum number of libraries to return. +#' Must be a number between 0 and 100 or \code{Inf}. +#' If \code{Inf} (default), the function will +#' automatically make all follow-up requests to retrieve +#' all holding institutions. Beware that each page of +#' 100 institutions counts as one API request. If the +#' bib searched for is popular, set this to non-\code{Inf}. +#' @param servicelevel Either "full" (the default) or "default". If "full", +#' the number of holding libraries returned is the same +#' as if a user logged in to an institution when making +#' a WorldCat search. If "default", the results are +#' a subset of WorldCat libraries, namely those that +#' participate in worldcat.org. In this way, the number +#' of holding libraries is tantamount to if a non-logged-in +#' user searched WorldCat. The number of results with "full" +#' is always at least as high as with "default", so the +#' default is "full". If this package is being used in +#' an application where a user is not logged in to an +#' institution, set this to "default". It is up to you +#' to respect the WorldCat API's conditions. +#' @param frbrGrouping With this parameter set to "on" (default), +#' an attempt is made by the WorldCat API to group +#' together similar editions and present only the top +#' held record as the representative record for that group. +#' If not, only institutions holding the exact standard +#' number specified will be returned. +#' @param libtype One of \code{NULL} (default), "academic", "public", +#' "government", or "other". \code{NULL} will return all +#' library subsets. The others will only search for holdings +#' from insitutions of that library type. +#' @param wskey A WorldCat API key (default is \code{getOption("libbib.wskey")}) +#' @param print.progress A logical indicating whether a message should be +#' displayed for each API request. If \code{max_libraries} +#' is \code{TRUE} a message will be displayed for every +#' group of 100 institutions the function fetches. +#' (default is \code{TRUE}) +#' @param debug A logical indicating whether the HTTP and API +#' responses should be printed (for debugging) +#' (default is \code{FALSE}) +#' +#' @return A \code{data.table} with each row corresponding to a holding library. +#' +#' @examples +#' +#' \dontrun{ +#' # worldcat_api_locations_by_oclc("877749545", max_libraries=10, +#' # include.bib.info=FALSE) +#' # oclc institution_identifier +#' # +#' # 1: 877749545 NLE +#' # 2: 877749545 NLW +#' # 3: 877749545 EUM +#' # 4: 877749545 LTU +#' # 5: 877749545 ELU +#' # 6: 877749545 UKUAL +#' # institution_name copies +#' # +#' # 1: National Library of Scotland 1 +#' # 2: National Library of Wales 1 +#' # 3: University of Manchester Library 1 +#' # 4: University of Leicester, David Wilson Library 1 +#' # 5: University of London Senate House Library 1 +#' # 6: University of the Arts London 1 +#' +#' } +#' +#' @name worldcat_api_locations_by + +#' @rdname worldcat_api_locations_by +#' @export +worldcat_api_locations_by_oclc <- function(x, + location="10032", + include.bib.info=TRUE, + max_libraries=Inf, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + wskey=getOption("libbib.wskey", NULL), + print.progress=TRUE, + debug=FALSE){ + ret <- worldcat_api_locations_by_something(x, type_std_num="oclc", + include.bib.info=include.bib.info, + location=location, + max_libraries=max_libraries, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, + libtype=libtype, + wskey=wskey, + print.progress=print.progress, + debug=debug) + if(is.null(ret)) + return(NULL) + + return(ret[]) +} + + +#' @rdname worldcat_api_locations_by +#' @export +worldcat_api_locations_by_isbn <- function(x, + location="10032", + include.bib.info=TRUE, + max_libraries=Inf, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + wskey=getOption("libbib.wskey", NULL), + print.progress=TRUE, + debug=FALSE){ + ret <- worldcat_api_locations_by_something(x, type_std_num="isbn", + include.bib.info=include.bib.info, + location=location, + max_libraries=max_libraries, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, + libtype=libtype, + wskey=wskey, + print.progress=print.progress, + debug=debug) + if(is.null(ret)) + return(NULL) + + return(ret[]) +} + +#' @rdname worldcat_api_locations_by +#' @export +worldcat_api_locations_by_issn <- function(x, + location="10032", + include.bib.info=TRUE, + max_libraries=Inf, + servicelevel="full", + frbrGrouping="on", + libtype=NULL, + wskey=getOption("libbib.wskey", NULL), + print.progress=TRUE, + debug=FALSE){ + ret <- worldcat_api_locations_by_something(x, type_std_num="issn", + include.bib.info=include.bib.info, + location=location, + max_libraries=max_libraries, + servicelevel=servicelevel, + frbrGrouping=frbrGrouping, + libtype=libtype, + wskey=wskey, + print.progress=print.progress, + debug=debug) + if(is.null(ret)) + return(NULL) + + return(ret[]) +} + + + +# --------------------------------------------------------------- # + +#################################### +### SEARCH API ### +#################################### + +# un-exported helper function +construct_wcapi_search_url <- function(sru, max_records=100, + frbrGrouping="on", start_at=1, + wskey=getOption("libbib.wskey", NULL)){ + # error checking + if(!methods::is(sru, "character")) + stop("SRU search must be a string") + if(!methods::is(max_records, "numeric")) + stop("max_records must be a number between 1 and 100") + if(max_records < 1 || max_records > 100) + stop("max_records must be a number between 1 and 100") + if(!(frbrGrouping %chin% c("on", "off"))) + stop('frfbGrouping must be "on" or "off"') + if(!methods::is(start_at, "numeric")) + stop("start_at must be a number") + if(is.null(wskey)) + stop("a WSKEY (WorldCat API key) must be specified") + + building <- "http://www.worldcat.org/webservices/catalog/search/worldcat/sru" + + # wskey + building <- sprintf("%s?wskey=%s", building, wskey) + + # sru query + building <- sprintf("%s&query=%s", building, URLencode(sru)) + + # max records + building <- sprintf("%s&maximumRecords=%s", building, max_records) + + # frbr grouping + building <- sprintf("%s&frbrGrouping=%s", building, frbrGrouping) + + # start at + building <- sprintf("%s&startRecord=%s", building, start_at) + + # lib type appears not to matter + + # Turns out that service level matters a great deal + building <- sprintf("%s&servicelevel=full", building) + + building +} + + +worldcat_api_search_helper <- function(sru, max_records=100, + frbrGrouping="on", start_at=1, + wskey=getOption("libbib.wskey", NULL), + more=TRUE, + debug=FALSE){ + + query <- result_number <- NULL + + fullurl <- construct_wcapi_search_url(sru, + max_records=max_records, + frbrGrouping=frbrGrouping, + start_at=start_at, + wskey=wskey) + if(debug) + message("\nFull Search API call url:\n", fullurl) + + resp <- worldcat_api_get_http_response(fullurl, print.api.responses=debug) + content <- resp$content + + if(debug){ + message("\nSearch API response:") + message(content, appendLF=FALSE) + message("End of Search API response\n") + } + + exemel <- xml2::read_xml(content, options=NULL) + xml2::xml_ns_strip(exemel) + + total_wc_results <- xml2::xml_text(xml2::xml_find_first(exemel, "//searchRetrieveResponse/numberOfRecords")) + all_records <- xml2::xml_find_all(exemel, "//searchRetrieveResponse/records/record/recordData/record") + num_records <- length(all_records) + if(num_records==0){ + diag.message <- xml2::xml_find_first(exemel, "//searchRetrieveResponse/diagnostics/diagnostic/message") + diag.details <- xml2::xml_find_first(exemel, "//searchRetrieveResponse/diagnostics/diagnostic/details") + if(length(diag.message)>0){ + message("Received diagnostic message: ", xml2::xml_text(diag.message), + " (", xml2::xml_text(diag.details), ")") + } + return(NULL) + } + + tmp <- lapply(all_records, function(x){read_a_marcxml_record(x, more=more)}) + ret <- rbindlist(tmp) + + ret[, total_wc_results:=total_wc_results] + ret[, result_number:=seq(start_at, start_at+num_records-1)] + ret[, query:=sru] + setcolorder(ret, c("total_wc_results", "result_number")) + ret[] +} + + + + +#' Use the WorldCat Search API +#' +#' Searches WorldCat using a CQL query. Returns a \code{data.table} +#' containing the bibliographic metadata of the results, along +#' with the total number of results. +#' +#' There is an entire vignette dedicated to this function; to view it, +#' execute \code{vignette("using-the-worldcat-search-api")} +#' +#' @param sru The search query (in CQL syntax). See \code{examples} section +#' for some examples. +#' @param max_records The maximum number of search results to return. +#' Must be a number between 0 and 100 or \code{Inf}. +#' If \code{Inf}, the function will +#' automatically make all follow-up requests to retrieve +#' all search results. For safety, the default is 10. +#' @param sru_query_assist A logical indicating whether translation from +#' more human-readable aliases to the SRU search +#' index codes should be allowed. See details for +#' more information. (default is \code{TRUE}). You +#' can control this parameter globally by setting +#' \code{options("libbib.sru_query_assist")}. +#' @param frbrGrouping With this parameter set to "on" (default), +#' an attempt is made by the WorldCat API to group +#' together similar editions and present only the top +#' held record as the representative record for that group. +#' @param start_at The search result to start at (default is 1) +#' @param wskey A WorldCat API key (default is \code{getOption("libbib.wskey")}) +#' @param more A logical indicating whether more information from the MARCXML +#' search results should be returned (publisher, bib level, etc....). +#' (Default is \code{TRUE}) +#' @param print.progress A logical indicating whether a message should be +#' displayed for each API request. If \code{max_records} +#' is \code{Inf} a message will be displayed for every +#' group of 100 search results the function fetches. +#' (default is \code{TRUE}) +#' @param debug A logical indicating whether the HTTP and API +#' responses should be printed (for debugging) +#' (default is \code{FALSE}) +#' +#' @details +#' +#' By default, this function allows for the usage of more human-readable +#' aliases to the arcane SRU search index codes. This allows you, for +#' example, to search using "$title" instead of "srw.ti". This behavior is +#' controlled using the `sru_query_assist` parameter. If it is \code{TRUE} +#' (the default) you can still use the formal search index codes. See +#' \code{vignette("using-the-worldcat-search-api")} for more information. +#' +#' As with all API access functions in this package, it's up to the +#' user to limit their API usage so as to not get blocked. These +#' functions are deliberately not vectorized for this reason; they +#' only accept one standard number at a time. +#' +#' This (and other) WorldCat API communication functions require a +#' WorldCat API key. The easiest way to use these functions is to +#' set a global options with your key: +#' \code{options("libbib.wskey"="YOUR KEY HERE")} +#' +#' @return A \code{data.table} containing the bibliographic metadata of the +#' results, along with the total number of results. +#' +#' @examples +#' +#' \dontrun{ +#' +#' # A title search for "The Brothers Karamazov" +#' worldcat_api_search('$title = "Brothers Karamazov"') +#' +#' # An exact title search for "The Brothers Karamazov" +#' worldcat_api_search('$title exact "Brothers Karamazov"') +#' +#' # Search for title "Madame Bovary" by author "Gustave Flaubert" +#' # in language Greek (all results) +#' # (queries may span multiple lines) +#' sru <- '$author = "Gustave Flaubert" and $title="Madame Bovary" +#' and $language=greek' +#' worldcat_api_search(sru, max_records=Inf) +#' +#' # Hip Hop (subject) materials on Cassette, CD, or wax from years 1987 to 1990 +#' sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) +#' and $subject="Rap") and $year="1987-1990"' +#' worldcat_api_search(sru) +#' +#' # all materials with keyword "Common Lisp" at The New York Public Library +#' sru <- '$keyword="common lisp" and $holding_library=NYP' +#' worldcat_api_search(sru, max_records=Inf) +#' +#' # 19th century materials on ethics (Dewey code 170s / LC Call prefix BJ) +#' sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*"' +#' worldcat_api_search(sru, max_records=Inf) +#' +#' # Music (Dewey 780s) materials that are only held by The New York Public +#' # Library (a "cg" code of 11 means there is only one holding) +#' # [searching with debugging] +#' sru <- '$dewey="78*" and $holding_library=NYP +#' and $library_holdings_group=11' +#' worldcat_api_search(sru, debug=TRUE) +#' +#' Keyword search for "danger music" from year 2010 to present +#' worldcat_api_search('$keyword="danger music" and $year="2010-"') +#' +#' } +#' @export +#' @importFrom data.table fcase rbindlist setcolorder +worldcat_api_search <- function(sru, max_records=10, + sru_query_assist=getOption("libbib.sru_query_assist", TRUE), + frbrGrouping="on", start_at=1, + wskey=getOption("libbib.wskey", NULL), + more=TRUE, print.progress=TRUE, + debug=FALSE){ + # debug implies print progress + if(debug) print.progress=TRUE + + # clean SRU query + sru <- stringr::str_replace_all(sru, "[\r\n]" , "") + sru <- stringr::str_replace_all(sru, " *" , " ") + + # sru_query_assist (translate helpful names to worldcat SRU indexes) + if(sru_query_assist){ + sru <- sru_syntax_translate_worldcat(sru) + if(debug) message("final (possibly translated) sru is: '", sru, "'") + } + + all_the_way_p <- FALSE + if(is.infinite(max_records)){ + all_the_way_p <- TRUE + max_records <- 100 + } + + runninglist <- list() + counter <- 1 + starting_at <- 1 + + ret <- worldcat_api_search_helper(sru, max_records=max_records, + frbrGrouping=frbrGrouping, + start_at=start_at, + wskey=wskey, + more=more, debug=debug) + + if(is.null(ret)){ + message("no results found") + return(NULL) + } + + if(!all_the_way_p || ret[,.N]<100){ + return(ret[]) + } + + runninglist[[counter]] <- ret + last_pull_n_count <- 100 + + while(last_pull_n_count==100){ + starting_at <- 1+(100*counter) + if(print.progress) + message("request ", counter, " pulled ", last_pull_n_count, + " rows... repeating, starting at library number ", starting_at) + + ret <- worldcat_api_search_helper(sru, max_records=max_records, + frbrGrouping=frbrGrouping, + start_at=starting_at, + wskey=wskey, + more=more, debug=debug) + + if(is.null(ret)){ + last_pull_n_count <- 0 + } else{ + counter <- counter + 1 + runninglist[[counter]] <- ret + last_pull_n_count <- ret[,.N] + } + } + + final <- rbindlist(runninglist) + + if(print.progress) + message("request ", counter, " pulled ", last_pull_n_count, + " rows. Returning data.table with ", final[,.N], " rows in total.\n") + + return(final[]) +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/README.md b/libbib.Rcheck/00_pkg_src/libbib/README.md new file mode 100755 index 0000000..ea6292c --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/README.md @@ -0,0 +1,284 @@ +libbib +=== + + +[![Cran Version](http://www.r-pkg.org/badges/version/libbib)](https://cran.r-project.org/package=libbib) +[![](https://cranlogs.r-pkg.org/badges/libbib)](https://cran.r-project.org/package=libbib) + + + +## Description +An R package providing WorldCat API communication, functions for validating +and normalizing bibliographic codes such as ISBN; ISSN; and LCCN, translation +from call numbers (Library of Congress and Dewey Decimal) to their subject +classifications or subclassifications, and other related utilities helpful +for assessment librarians. Also provides various loadable data files such +call number / subject crosswalks and code tables. + +Speed of execution and robustness are priorities in this package. +To the end of optimizing speed and efficiency, careful consideration +is taken to exploit vectorized functions and efficient data.table joins +in the code. + +On a (real life) example of **3 million** very messy ISBN 10s and 13s, +aggressive ISBN normalization took _less than 1 minute_ (commodity hardware). +It salvaged almost half a million previously unusable ISBNs, bringing +the number of usable ISBNs (for matching, cataloging, etc...) from +less than 90% to 99.6%! + +As for robustness, this package is well tested, with over 300 +automated tests, at time of writing. + +`data.table` is a hard dependency of this package. Using `data.table` +internally makes, for example, the call number -> subject conversions +very fast. Additionally, loading this package also automatically +loads `data.table`. If you don't use `data.table` in your own code, +everything will work just fine! But you might want to look into it! + +## Some examples + +```r +> get_dewey_decimal_subject_class("823.912") +[1] "Literature (Belles-lettres) and rhetoric" + +> get_lc_call_subject_classification(c("ND 237", "PQ2246.M3"), ++ subclassification=TRUE) +[1] "Painting" +[2] "French, Italian, Spanish, and Portuguese literature" + +> convert_to_isbn_13(c("012491540X", "9004037810")) +[1] "9780124915404" "9789004037816" + +> normalize_isbn_13(c("978-9-66-819791-8", "__9__781572411579")) +[1] "9789668197918" "9781572411579" + +> normalize_lccn(" 79139101 /AC/r932") +[1] "79139101" + +> # Do a WorldCat APU search on 19th century materials on ethics +> # (Dewey code 170s / LC Call prefix BJ) +> results <- worldcat_api_search('($dewey="17*" or $lc_call="bj*") ++ and srw.yr="18*"') +> results[,.(oclc, title, result_number, num_results)][1:5] + oclc title result_number num_results + +1: 8665856 The principles of moral and political ph... 1 1716 +2: 191264919 The economy of human life. / 2 1716 +3: 22571399 Solitude: 3 1716 +4: 65250134 The theory of moral sentiments, or, An e... 4 1716 +5: 13106952 Letters on the improvement of the mind : 5 1716 + +> worldcat_api_bib_read_info_by_isbn("9780984201006") + oclc isbn issn title + +1: 462894360 9780984201006 The Great Debate about Art / + author leader + +1: Harris, Roy, 00000cam a2200000 a 4500 + oh08 + +1: 091031s2010 ilua b 000 0 eng c + +> worldcat_api_classify_by_oclc("877749545") + oclc title author total_holdings total_eholdings + +1: 877749545 Max Ernst's 'Celebes' Penrose, Roland, Sir 8 0 +2: 877749545 Max Ernst's 'Celebes' Penrose, Roland, Sir 8 0 + call_type recommendation holdings http_status_code classify_response_code + +1: DDC 759.4 6 200 0 +2: LCC ND588.E7 6 200 0 + +> worldcat_api_locations_by_oclc("877749545", max_libraries=10, ++ include.bib.info=FALSE) + oclc institution_identifier + +1: 877749545 NLE +2: 877749545 NLW +3: 877749545 EUM +4: 877749545 LTU +5: 877749545 ELU +6: 877749545 UKUAL + institution_name copies + +1: National Library of Scotland 1 +2: National Library of Wales 1 +3: University of Manchester Library 1 +4: University of Leicester, David Wilson Library 1 +5: University of London Senate House Library 1 +6: University of the Arts London 1 + +> loc_permalink_from_lccn("73167510", format="marcxml") +[1] https://lccn.loc.gov/73167510/marcxml + +> loc_permalink_from_lccn(c("2010292065", "2012451004") +[1] "https://lccn.loc.gov/2010292065" "https://lccn.loc.gov/2012451004" + +> worldcat_permalink_from_oclc_number("1005106045") +[1] "http://www.worldcat.org/oclc/1005106045" + +> get_isbn_10_check_digit("0-124-91540-X", allow.hyphens=TRUE) +[1] "X" + +> is_valid_isbn_10(c("012491540X", "9004037812")) +[1] TRUE FALSE + +> marc_leader_get_info("00000cam a22000008i 4500") + record_type bib_level + +1: Language Material Monograph/Item + +# The Brothers Karamazov (1970 reissue but original publication date) +> marc_008_get_info("950622r19701880ru 000 0 rus d", ++ original.pub.date=TRUE) + pub_date pub_place_code lang_code + + 1: 1880 ru rus + +# reissue publication date +> marc_008_get_info("950622r19701880ru 000 0 rus d") + pub_date pub_place_code lang_code + + 1: 1970 ru rus + +> data("dewey_subject_crosswalk") +> dewey_subject_crosswalk +Key: + thekey description + + 1: 000 Computer science, knowledge and systems + 2: 001 Knowledge + ... +990: 998 Arctic islands and Antarctica +991: 999 Extraterrestrial worlds + +> data("lc_subject_subclassification") +> lc_subject_subclassification +Key: + thekey description + + 1: AC Collections. Series. Collected works + 2: AE Encyclopedias + ... +227: Z Books (General). Writing. Paleography. Book indust... +228: ZA Information resources/materials + +> get_language_from_code(c("yor", "spa")) +[1] "Yoruba" "Spanish" + +> get_country_from_code(c("ck", " NYA")) +[1] "Colombia" "New York (State)" + +> someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", ++ "1861897952; 978-1-86189-795-4") +> split_map_filter_reduce(someisbns, ++ mapfun= ++ function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, ++ filterfun=remove_duplicates_and_nas, ++ reduxfun=recombine_with_sep_closure()) +[1] "9782711875177;9782844268907" "9781861897954" + +``` + + +## Functions + +### ISBNs +- `get_isbn_10_check_digit` +- `check_isbn_10_check_digit` +- `is_valid_isbn_10` +- `normalize_isbn_10` +- `get_isbn_13_check_digit` +- `check_isbn_13_check_digit` +- `is_valid_isbn_13` +- `convert_to_isbn_13` +- `normalize_isbn_13` +- `normalize_isbn` + +### ISSN +- `get_issn_check_digit` +- `check_issn_check_digit` +- `is_valid_issn` +- `normalize_issn` + +### LCCN +- `normalize_lccn` + +### Library of Congress Call Numbers +- `get_lc_call_subject_classification` +- `is_valid_lc_call` +- `get_lc_call_first_letter` +- `get_all_lc_call_subject_letters` + +### Dewey Decimal (DDC) Call Numbers +- `get_dewey_decimal_subject_class` +- `get_dewey_decimal_subject_division` +- `get_dewey_decimal_subject_section` + +### WorldCat API +- `worldcat_api_search` +- `worldcat_api_bib_read_info_by_oclc` +- `worldcat_api_bib_read_info_by_isbn` +- `worldcat_api_bib_read_info_by_issn` +- `worldcat_api_locations_by_oclc` +- `worldcat_api_locations_by_isbn` +- `worldcat_api_locations_by_issn` +- `worldcat_api_classify_by_oclc` +- `worldcat_api_classify_by_isbn` +- `worldcat_api_classify_by_issn` + +### Interfacing with the web +- `loc_permalink_from_lccn` +- `worldcat_permalink_from_issn` +- `worldcat_permalink_from_isbn` +- `worldcat_permalink_from_oclc_number` +- `oclc_classify_link_from_standard_num` + +## Included data files (loadable with `data(datafile)`) +- `language_code_crosswalk` + (from https://www.loc.gov/marc/languages/language_code.html) +- `country_code_crosswalk` + (from https://www.loc.gov/marc/countries/countries_code.html) +- `lc_subject_classification` + (from https://www.loc.gov/catdir/cpso/lcco/) +- `lc_subject_subclassification` + (from https://www.loc.gov/catdir/cpso/lcco/) +- `dewey_subject_crosswalk` + (from https://www.oclc.org/content/dam/oclc/dewey/ddc23-summaries.pdf) +- `books_serials_etc_sample` - A very small sample of books, serials, VHSs, + CDs, and Computer files and some information including title, control + numbers, call numbers, and call number subject classifications. Somewhat + messy/inconsistent (deliberately) and mainly for testing. + Will be expanded in future versions. + +### Marc field deconstruction +- `marc_leader_get_info` +- `marc_008_get_info` + +### other Marc code translations +- `get_language_from_code` +- `get_country_from_code` + +### split / map / filter / reduce and related utilies +- `car` +- `remove_duplicates_and_nas` +- `recombine_with_sep_closure` +- `split_map_filter_reduce` + +### miscellaneous utilities +- `dt_del_cols` +- `dt_keep_cols` +- `dt_counts_and_percents` +- `get_clean_names` +- `dt_set_clean_names` +- `dt_percent_not_na` +- `dt_na_breakdown` +- `dt_add_to_col_names` + +### working with special attributes +- `fread_plus_date` +- `fwrite_plus_date` +- `set_lb_attribute` +- `set_lb_date` +- `cp_lb_attributes` + diff --git a/libbib.Rcheck/00_pkg_src/libbib/build/vignette.rds b/libbib.Rcheck/00_pkg_src/libbib/build/vignette.rds new file mode 100644 index 0000000000000000000000000000000000000000..52d5ac0966aa48a0f330c3dd555360443aba4c55 GIT binary patch literal 234 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 Ws9z=5GfZ@e4E+zPL2oxKC;$LW$aeAo literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/data/country_code_crosswalk.rda b/libbib.Rcheck/00_pkg_src/libbib/data/country_code_crosswalk.rda new file mode 100644 index 0000000000000000000000000000000000000000..2cee616d1fbb868d2524caaa93448242daf44622 GIT binary patch literal 4285 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 literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/data/dewey_subject_crosswalk.rda b/libbib.Rcheck/00_pkg_src/libbib/data/dewey_subject_crosswalk.rda new file mode 100644 index 0000000000000000000000000000000000000000..edbb790163f14e8947275668c5b84b1905b734d9 GIT binary patch literal 13418 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 CFzxC9 literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/data/language_code_crosswalk.rda b/libbib.Rcheck/00_pkg_src/libbib/data/language_code_crosswalk.rda new file mode 100644 index 0000000000000000000000000000000000000000..dd034e4cd0f0df41538e6dbcb1097fe5c35ba9cd GIT binary patch literal 5077 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 literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_classification.rda b/libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_classification.rda new file mode 100644 index 0000000000000000000000000000000000000000..c4eea8f2552f7bf6fa4f8ef23993bfdf224c7d93 GIT binary patch literal 545 zcmV++0^a=}iwFP!000001D%siZxb;PhBr-9NUDlf2oQ%#mN)=X$%RX=8`7kLO%<91 zDlV1do$Q*rc4T{LbL0Q=9|)7IrzFdbgV)c_$2%T>Tz0SCx2{@I6xE|$9Q6ib)R>HW z?@ps=cL#rJ=xE~nQi*Fvgj!6{A^1ShB{(DK z5%dYp2|f~hB1i}Z1Q!HDg3kn(1S5hm!Gz!o!M92i2Yt|Bxnf_9y>Y?FhPhP6nR&iA zVMDhNxltxVz62$+)sB>L$8m8lmE?B8MnZxX;Fy`QbLqUXixBi0l~qbc_6F_+%sq>5 z!Q%dEa=Z=UhgCy&k@^wQ-gtXp`2Q_teMa9;Tm zJWfrOgYK(7n9TBZtFiXEHS>pNg@y70l%Y>XMo3%(^%~4aL!+>!`0ELddcyAlHqX*R zY-%+Ig_DB3J*k1k)|2FmgzK!}8I;S$9xeBUCE-Wgbsi5Ol>#Ng|9+fdgN542XpKSS zdfgc9^8ioIZyX(6hztJXpH7ZDa;oIRJ|%K$H#4^%QbY4w+??{B?F8c zuyS6$uC45*HFs@NI9MtC#LsfM{8cTpex#K$t(1G-_I#>f%QCa5SP?jCON|?=xoSI5 jGYc~`J`dw}82{D7o--D&Wk|18(u4RP9}8e6n*;y=CZh&F literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_subclassification.rda b/libbib.Rcheck/00_pkg_src/libbib/data/lc_subject_subclassification.rda new file mode 100644 index 0000000000000000000000000000000000000000..9f19b2d687dc8795cccd4c62fa0e802a52ed264c GIT binary patch literal 7537 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 HCRG3cy1z%U literal 0 HcmV?d00001 diff --git a/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.R b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.R new file mode 100644 index 0000000..7b73b37 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.R @@ -0,0 +1,272 @@ +## ----include = FALSE---------------------------------------------------------- +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) + +## ----setup-------------------------------------------------------------------- +# let's load this package before getting started +library(libbib) + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# library(libbib) # load this package +# +# result <- worldcat_api_search('$title="Madame Bovary" and +# $author="Gustave Flaubert"') +# +# # get the column names +# names(result) +# #> [1] "total_wc_results" "result_number" "oclc" "isbn" +# #> [5] "issn" "title" "author" "pub_date" +# #> [9] "lang_code" "bib_level" "record_type" "pub_place_code" +# #> [13] "publisher" "leader" "oh08" "query" +# +# # show the first three results +# result[1:3,] +# #> total_wc_results result_number oclc isbn issn +# #> +# #> 1: 986 1 1125170419 9782253183464 +# #> 2: 986 2 1049849403 9788415618843 +# #> 3: 986 3 1203070641 9781664921993 +# #> title author pub_date lang_code bib_level +# #> +# #> 1: Madame Bovary : Flaubert, Gustave, 2019 fre Monograph/Item +# #> 2: Madame Bovary / Flaubert, Gustave, 2019 spa Monograph/Item +# #> 3: Madame Bovary / Flaubert, Gustave, 2021 eng Monograph/Item +# #> record_type pub_place_code publisher +# #> +# #> 1: Language Material fr le Livre de poche, +# #> 2: Language Material sp +# #> 3: Nonmusical sound recording ohu +# #> leader oh08 +# #> +# #> 1: 00000cam a2200000Mi 4500 190619s2019 fr a g 000 1 fre d +# #> 2: 00000cam a2200000Ii 4500 180827t20192018sp a 000 1 spa d +# #> 3: 00000cim a2200000Mi 4500 201104s2021 ohunnnneq f n eng d +# #> query +# #> +# #> 1: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +# #> 2: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +# #> 3: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# # missing ending double quotes +# worldcat_api_search('$title="Madame Bovary and $langauge=greek') +# #> Received diagnostic message: Query syntax error (org.z3950.zing.cql.CQLParseException: expected index or term, got EOF) +# #> no results found +# #> NULL +# +# # "$titley" is not a valid search index +# worldcat_api_search('$titley="Madame Bovary" and $langauge=greek') +# #> Received diagnostic message: Unsupported index (srw.tiy) +# #> no results found +# #> NULL +# +# worldcat_api_search("$holding_library=NYP") +# #> Received diagnostic message: Limit index, can only be used to narrow a result +# #> for a non-limit index (srw.li) +# #> no results found +# #> NULL + +## ----eval=FALSE--------------------------------------------------------------- +# library(libbib) +# +# # title search for "The Brothers Karamazov" +# results <- worldcat_api_search('$title="Brothers Karamazov"') +# +# # Madame Bovary by Gustave Flaubert in Greek +# sru <- '$author="Gustave Flaubert" and +# $title="Madame Bovary" and +# $language=greek' +# results <- worldcat_api_search(sru) +# +# # Hip Hop materials on wax, cassette, or CD published from +# # 1987 to 1990 +# sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) +# and $subject="Rap") and $year="1987-1990"' +# results <- worldcat_api_search(sru) +# +# # keyword search for "Common Lisp" for materials held +# # at The New York Public Library +# sru <- '$keyword="common lisp" and $holding_library=NYP' +# results <- worldcat_api_search(sru) +# +# # keyword search for "Common Lisp" for materials held +# # by any of the members of the "Manhattan Research +# # Library Initiative" (MaRLI) joint borrowing program +# # (New York Public Library, Columbia University, and +# # New York University) +# sru <- '($keyword="common lisp" and $holding_library=NYP) +# or ($keyword="common lisp" and $holding_library=ZYU) +# or ($keyword="common lisp" and $holding_library=ZCU)' +# results <- worldcat_api_search(sru) +# +# # Books (only books) about Ethics (by dewey division 170s or +# # LC call number subject class "BJ") published in the 19th +# # century +# sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*" and +# $material_type=bks' +# results <- worldcat_api_search(sru) +# +# # Materials on Musicology (by Dewey division 780s) at +# # the New York Public Library and not held by any +# # other insitution +# sru <- '$dewey="78*" and $holding_library=NYP and +# $library_holdings_group=11' +# results <- worldcat_api_search(sru) +# +# # Search for materials on "Danger Music" published since 2010 +# results <- worldcat_api_search('$keyword="danger music" and $year="2010-"') + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# sru <- '$title+=+"Common Lisp"' +# results <- worldcat_api_search(sru) +# results[1:3, .(total_wc_results, title)] +# #> total_wc_results title +# #> +# #> 1: 367 Common Lisp / +# #> 2: 367 Practical Common Lisp / +# #> 3: 367 Common LISP / + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# sru <- '$title = "Common Lisp"' +# results <- worldcat_api_search(sru) +# results[1:3, .(total_wc_results, title)] +# #> total_wc_results title +# #> +# #> 1: 367 Common Lisp / +# #> 2: 367 Practical Common Lisp / +# #> 3: 367 Common LISP / + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# results <- worldcat_api_search('$title exact "Common Lisp"') +# results[1:3, .(total_wc_results, title)] +# #> total_wc_results title +# #> +# #> 1: 37 Common Lisp / +# #> 2: 37 Common LISP / +# #> 3: 37 Common LISP / + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# results <- worldcat_api_search('$title any "Common Lisp"') +# results[1:3, .(total_wc_results, title)] +# #> total_wc_results title +# #> +# #> 1: 351777 An Inquiry into the Human Mind on the Principles o... +# #> 2: 351777 The book of common prayer. +# #> 3: 351777 Dictionary of Phrase and Fable + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# results <- worldcat_api_search('$title = Common or $title = "Lisp"') +# results[1:3, .(total_wc_results, title)] +# #> total_wc_results title +# #> +# #> 1: 351777 An Inquiry into the Human Mind on the Principles o... +# #> 2: 351777 The book of common prayer. +# #> 3: 351777 Dictionary of Phrase and Fable + +## ----echo=FALSE--------------------------------------------------------------- +# Sys.sleep(1) + +## ----eval=FALSE--------------------------------------------------------------- +# results <- worldcat_api_search('$title exact "Finnegans Wake"') +# results[1:3, .(total_wc_results, title, query)] +# #> total_wc_results title query +# #> +# #> 1: 761 Finnegans wake / srw.ti exact "Finnegans Wake" +# #> 2: 761 Finnegans Wake srw.ti exact "Finnegans Wake" +# #> 3: 761 Finnegans wake srw.ti exact "Finnegans Wake" +# +# # yields the same results as +# +# results <- worldcat_api_search('$title exact "Finnegan\'s Wake"') +# results[1:3, .(total_wc_results, title, query)] +# #> total_wc_results title query +# #> +# #> 1: 761 Finnegans wake / srw.ti exact "Finnegan's Wake" +# #> 2: 761 Finnegans Wake srw.ti exact "Finnegan's Wake" +# #> 3: 761 Finnegans wake srw.ti exact "Finnegan's Wake" +# + +## ----eval=FALSE--------------------------------------------------------------- +# results <- worldcat_api_search('srw.ti="Data Analysis with r" +# and srw.au=fischetti', +# max_records=Inf) +# +# # inspect some of the columns in the first 5 results +# results[1:5, .(total_wc_results, result_number, oclc, +# title, author, pub_date) +# #> total_wc_results result_number oclc title +# #> +# #> 1: 11 1 1005106045 DATA ANALYSIS WITH R -. +# #> 2: 11 2 1089176194 Data analysis with R : +# #> 3: 11 3 949229431 Data analysis with R : +# #> 4: 11 4 1242682069 Data Analysis with R +# #> 5: 11 5 1242707288 Data Analysis with R +# #> author pub_date +# #> +# #> 1: FISCHETTI, TONY. 2018 +# #> 2: Fischetti, Tony. 2018 +# #> 3: Fischetti, Tony. 2015 +# #> 4: Fischetti, Tony 2015 +# #> 5: Fischetti, Tony 2015 + +## ----eval=FALSE--------------------------------------------------------------- +# all_the_oclcs <- results[, unique(oclc)] +# all_the_oclcs +# #> [1] "1005106045" "1089176194" "949229431" "1242682069" "1242707288" +# #> [6] "1244405806" "1104264768" "1242685020" "1242707684" "1244406814" +# #> [11] "1104846312" + +## ----eval=FALSE--------------------------------------------------------------- +# holds <- pblapply(all_the_oclcs, +# function(x){ +# worldcat_api_locations_by_oclc(x, +# include.bib.info=FALSE) +# }) + +## ----eval=FALSE--------------------------------------------------------------- +# all_holdings_dt <- rbindlist(holds) +# all_holdings_dt[1:3] +# #> oclc institution_identifier institution_name copies +# #> +# #> 1: 1005106045 FEM The Ferguson Library 1 +# #> 2: 1005106045 YDX YBP Library Services 1 +# #> 3: 1005106045 DUQ Duquesne University Library 1 +# +# all_holdings_dt[, .(institution_name)] +# #> institution_name +# #> +# #> 1: The Ferguson Library +# #> 2: YBP Library Services +# #> 3: Duquesne University Library +# #> 4: Centennial College +# #> 5: George Brown College +# #> --- +# #> 1029: Hochschule Mittweida (FH), Hochschulbibliothek +# #> 1030: Cyberlibris +# #> 1031: Cyberlibris +# #> 1032: Cyberlibris +# #> 1033: BibliothĂšque de l'UniversitĂ© du QuĂ©bec Ă  Trois-Riv... + diff --git a/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.Rmd b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.Rmd new file mode 100644 index 0000000..500f093 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.Rmd @@ -0,0 +1,991 @@ +--- +title: "Using the WorldCat Search API" +# title: "using-the-worldcat-search-api" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Using the WorldCat Search API} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +# let's load this package before getting started +library(libbib) +``` + +_Intermediate knowledge of R is required to follow the examples here._ + +_Basic knowledge of how to manipulate `data.table`s if helpful but_ +_following the examples should be possible without it._ + +## Introduction + +`libbib`'s ability to communicate to the WorldCat Search API is probably +the most helpful capability of the package. As such, an entire vignette +dedicated to this powerful tool is warranted. + +Also of note is that documentation on how to use this API +is scattered throughout the web, in different places, and +sometimes even no longer available and only accessible through the +internet archive. Because of this, the goal of this vignette is not +only to document `libbib`'s `worldcat_api_search` function, but to +provide a single location for compiling this archived documentation +and providing information/examples of what the WorldCat Search API is +capable, in general. + +The terminology/nomenclature of the different WorldCat API offerings +is fuzzy and inconsistent. The specific kind of Search API that this package +offers usage of can, more specifically, be described as the +'WorldCat SRU Search API version 1'. + +There is a version 2 of this API, but version 1 hasn't been sunsetted as +of yet. + +First, let's speak of what this API is and what it is not. + +## What the WorldCat SRU Search API is + +This API is allows a developer to search for bibliographic records that +are cataloged in WorldCat. + +The queries are made using [the SRU standard search protocol](https://en.wikipedia.org/wiki/Search/Retrieve_via_URL) +(Search/Retrieve via URL) using a standard query syntax called [CQL](https://en.wikipedia.org/wiki/Contextual_Query_Language) +(Contextual Query Language). The WorldCat Search API doesn't implement +all features of CQL; this vignette will illustrate SRU/CQL only +insofar as it is supported by this API. + +This API is open to libraries that maintain both WorldCat Discovery and +OCLC Cataloging subscriptions and needs an API key (called a `WSKey`) to work. +A request can be made for a key (if your institution doesn't already have one) +via [this link.](https://help.oclc.org/Discovery_and_Reference/WorldCat_Discovery/Troubleshooting/How_do_I_request_a_WSKey_for_the_WorldCat_Search_API) + +## What the WorldCat SRU Search API is not + +This API is not the OpenSearch/Basic API, which doesn't allow field-specific +searches and only supports keyword-anywhere searches. + +This is also not the same as using the +[advanced search option on worldcat.org](https://www.worldcat.org/advancedsearch). +That option only provides a subset of the bibliographic records in WorldCat and +is a far less powerful tool. + +This API is most akin to using the "expert search" option in OCLC's +FirstSearch, using the WorldCat database, but differs in that (a) searching +the API is programmatically automate-able, and (b) the API allows for, still, +more powerful search queries. + +## What `libbib`'s `worldcat_api_search` function provides + +At its most basic, this function takes a SRU query and returns a +`data.table` with most of the bibliographic metadata from the MARCXml +that the API returns. We'll see how the behavior of this function can +be controlled by specifying certain function parameters. + +This function also offers assistance with the SRU query syntax. +Mainly, the function allows you to substitute the arcane search index +codes for more human-readable equivalents, prefixed be a (US) dollar-sign. +Examples of these aids will be explained later in the vignette. + +## An example of usage and what the function returns + +Let's look at an example of a simple query and what the returned +`data.table` looks like. + +Specifically, we'll search for "Madame Bovary" by "Gustave Flaubert" +and we'll only show the first three results + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +library(libbib) # load this package + +result <- worldcat_api_search('$title="Madame Bovary" and + $author="Gustave Flaubert"') + +# get the column names +names(result) +#> [1] "total_wc_results" "result_number" "oclc" "isbn" +#> [5] "issn" "title" "author" "pub_date" +#> [9] "lang_code" "bib_level" "record_type" "pub_place_code" +#> [13] "publisher" "leader" "oh08" "query" + +# show the first three results +result[1:3,] +#> total_wc_results result_number oclc isbn issn +#> +#> 1: 986 1 1125170419 9782253183464 +#> 2: 986 2 1049849403 9788415618843 +#> 3: 986 3 1203070641 9781664921993 +#> title author pub_date lang_code bib_level +#> +#> 1: Madame Bovary : Flaubert, Gustave, 2019 fre Monograph/Item +#> 2: Madame Bovary / Flaubert, Gustave, 2019 spa Monograph/Item +#> 3: Madame Bovary / Flaubert, Gustave, 2021 eng Monograph/Item +#> record_type pub_place_code publisher +#> +#> 1: Language Material fr le Livre de poche, +#> 2: Language Material sp +#> 3: Nonmusical sound recording ohu +#> leader oh08 +#> +#> 1: 00000cam a2200000Mi 4500 190619s2019 fr a g 000 1 fre d +#> 2: 00000cam a2200000Ii 4500 180827t20192018sp a 000 1 spa d +#> 3: 00000cim a2200000Mi 4500 201104s2021 ohunnnneq f n eng d +#> query +#> +#> 1: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +#> 2: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +#> 3: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +``` + +This should give you an idea of the rich information returned by the results +`data.table`. All of the information returned is from (or derived from) +the MARCXml that the API returns, save for + + - `total_wc_results` + Which returns the number of the results the query yields in WorldCat even + if the number of records/results requested is lower than this number. + + - `result_number` + This number of the result, which is helpful if you're using a starting + position other than `1` (the default) + + - `query` + The final SRU query (after any of the SRU query assistance routines step + in) that is sent to the API. This can be useful for debugging. + +Hereafter, the output of the example queries will be abbreviated, truncated, +elided, or only show a subset of columns in order to save space and +aid in following the guide. + +## What does an error look like + +If you craft a query that yields no results, a message telling you such +will be displayed, and the return value is `NULL`. + +If you make an error in the query syntax, no results will be returned, but +a diagnostic message returned from the server may tell you what went wrong. +Here are two examples... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +# missing ending double quotes +worldcat_api_search('$title="Madame Bovary and $langauge=greek') +#> Received diagnostic message: Query syntax error (org.z3950.zing.cql.CQLParseException: expected index or term, got EOF) +#> no results found +#> NULL + +# "$titley" is not a valid search index +worldcat_api_search('$titley="Madame Bovary" and $langauge=greek') +#> Received diagnostic message: Unsupported index (srw.tiy) +#> no results found +#> NULL + +worldcat_api_search("$holding_library=NYP") +#> Received diagnostic message: Limit index, can only be used to narrow a result +#> for a non-limit index (srw.li) +#> no results found +#> NULL +``` + +This last one failed because `$holding_library` is considered +a _limit index_. This means that you can't use it to search directly, +you can only combine with search facet with other non-limiting +indexes to filter the results. +Hopefully this will make more sense as you go through this vignette. + +## `worldcat_api_search` by example / quick start + +In guides like this, there is frequently tension between wanting to +be a complete reference, and wanting to show cool/helpful examples +at a glance. + +In service of easing this tension, we'll first look at some examples +illustrating things this function can do and _then_ turn our attention +to an adequate explanation of boolean operators, relations operators, +search indexes, etc... + +These examples are largely taken from the `examples` section of the +R documentation for this function. + +These examples (and the ones further along in this vignette) will also +use `data.table` syntax to limit number of rows and columns returned +to aid reading. + +We'll be focusing on the types of queries you can use in this section; +controlling the behavior of the function via changing parameters will +come later. + +```{r, eval=FALSE} +library(libbib) + +# title search for "The Brothers Karamazov" +results <- worldcat_api_search('$title="Brothers Karamazov"') + +# Madame Bovary by Gustave Flaubert in Greek +sru <- '$author="Gustave Flaubert" and + $title="Madame Bovary" and + $language=greek' +results <- worldcat_api_search(sru) + +# Hip Hop materials on wax, cassette, or CD published from +# 1987 to 1990 +sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) + and $subject="Rap") and $year="1987-1990"' +results <- worldcat_api_search(sru) + +# keyword search for "Common Lisp" for materials held +# at The New York Public Library +sru <- '$keyword="common lisp" and $holding_library=NYP' +results <- worldcat_api_search(sru) + +# keyword search for "Common Lisp" for materials held +# by any of the members of the "Manhattan Research +# Library Initiative" (MaRLI) joint borrowing program +# (New York Public Library, Columbia University, and +# New York University) +sru <- '($keyword="common lisp" and $holding_library=NYP) + or ($keyword="common lisp" and $holding_library=ZYU) + or ($keyword="common lisp" and $holding_library=ZCU)' +results <- worldcat_api_search(sru) + +# Books (only books) about Ethics (by dewey division 170s or +# LC call number subject class "BJ") published in the 19th +# century +sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*" and + $material_type=bks' +results <- worldcat_api_search(sru) + +# Materials on Musicology (by Dewey division 780s) at +# the New York Public Library and not held by any +# other insitution +sru <- '$dewey="78*" and $holding_library=NYP and + $library_holdings_group=11' +results <- worldcat_api_search(sru) + +# Search for materials on "Danger Music" published since 2010 +results <- worldcat_api_search('$keyword="danger music" and $year="2010-"') +``` + + +Now that we've seen these examples, sans explanation, we can now +have a closer look into the components of a query. +Broadly speaking, there are four concepts to be aware of... + + - relations operators + + - boolean operators + + - wildcards + + - search indexes + +We'll be looking at each in this order, because I think that makes +the most sense. To illustrate the first three concepts, though, +we have to use search indexes, before a formal explanation of what +they are. + +Briefly, a search index is a facet along which to search. In all of +the examples above, the search indexes were prefixed by a `$` +character (e.g. `$title`, `author`, `$keyword`, etc...) + + +## Relations operators + +There are four relations operators available for use... + + - `=` + + - `exact` + + - `any` + + - `all` + +It should be noted that not every relations operator is available +for use with every search index. + +### `=` + +This was the most common operator used in the quick-start examples above. +Though this operator can be most fully understood via contrast with the +next operator, `exact`, suffice it to say, for now, that using `=` means +that all of your search terms must match, without intervening words. +This is sometimes referred to as an "un-anchored" search. + +If the phrase you're search for has spaces in it, you have to surround +it with double quotes. Since the SRU query to the `worldcat_api_search` +function must be a string, and strings can be made with single quotes +and double quotes, we need to surround the entire query with single +quotes. + +We can get around this by "escaping" the quotes, but using only single +quotes to surround the whole query is the most elegant approach. + +You can use both spaces and `+` to separate the search index and the +search term on both sides of the relations operator... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +sru <- '$title+=+"Common Lisp"' +results <- worldcat_api_search(sru) +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 367 Common Lisp / +#> 2: 367 Practical Common Lisp / +#> 3: 367 Common LISP / +``` + +is the same as... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +sru <- '$title = "Common Lisp"' +results <- worldcat_api_search(sru) +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 367 Common Lisp / +#> 2: 367 Practical Common Lisp / +#> 3: 367 Common LISP / +``` + +But we'll be using spaces here. + +The `=` relations operator is the only one that doesn't require any +space or `+` on either side of the operator, and we'll be using both +the spaced version and non-spaced version in these examples for this +operator, only. + + +### `exact` (anchored search) + +The `exact` operator, in contrast with the `=` operator, signals to +the API that your search must match as an exact phrase, without +any other terms in the matching string. For this reason, this operator +is sometimes referred to as an "anchored search". + +Here's an example using the same title search as above... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title exact "Common Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 37 Common Lisp / +#> 2: 37 Common LISP / +#> 3: 37 Common LISP / +``` + +Note that the title "Practical Common Lisp" was returned by the +`=` operator query. The `exact` operator will not match this title +since it has another word/phrase in it besides "Common Lisp". + +Using an `exact` search is probably a better fit than `=` for some +indexes and in some situations. For example, if you know the exact +title of a book (e.g. `$title exact "Brothers Karamazov")`, using +`exact` will ensure that books with a title like _"A Guide to The_ +_Brothers Karamazov"_ or _"The Brothers Karamazov in Pictures"_ are +not returned by the search. + +That being said, we'll be using the `=` most heavily, and it's easier +to read. + +### any + +Using `any` means that any of your search terms (inside the double quotes) +can match. For example... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title any "Common Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 351777 An Inquiry into the Human Mind on the Principles o... +#> 2: 351777 The book of common prayer. +#> 3: 351777 Dictionary of Phrase and Fable +``` + +matches the title "The book of common prayer" (decidedly _not_ a book +of the subject of Common Lisp) since it has the word +"common" in it. (Note that capitalization doesn't matter). + +Using `any` in this context is tantamount to using an `or` boolean operator, +which we'll look at in the next section... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title = Common or $title = "Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 351777 An Inquiry into the Human Mind on the Principles o... +#> 2: 351777 The book of common prayer. +#> 3: 351777 Dictionary of Phrase and Fable +``` + +(Note the same number and order of results) + +### `all` + +Using the `all` operator means that _all_ of the search terms must match but +the search terms can be in any order and have intervening terms in between. +For example, search like `$title all "Common Lisp"` can match a (fictional) +book named _"Speaking with a lisp is common"_. + +### A quick note before continuing + +If your search term is one word, you do not have to use double quotes +to surround the term. For example, `$title = Ethics` and +`$title exact Ethics` work perfectly well. + +If your search term as a single quote in it, it must be escaped so +that R doesn't interpret it as the end of the search string. That +being said, it appears as if you can just drop the single quote +and the search will carry on perfectly fine... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title exact "Finnegans Wake"') +results[1:3, .(total_wc_results, title, query)] +#> total_wc_results title query +#> +#> 1: 761 Finnegans wake / srw.ti exact "Finnegans Wake" +#> 2: 761 Finnegans Wake srw.ti exact "Finnegans Wake" +#> 3: 761 Finnegans wake srw.ti exact "Finnegans Wake" + +# yields the same results as + +results <- worldcat_api_search('$title exact "Finnegan\'s Wake"') +results[1:3, .(total_wc_results, title, query)] +#> total_wc_results title query +#> +#> 1: 761 Finnegans wake / srw.ti exact "Finnegan's Wake" +#> 2: 761 Finnegans Wake srw.ti exact "Finnegan's Wake" +#> 3: 761 Finnegans wake srw.ti exact "Finnegan's Wake" + +``` + +I suspect single quotes are automatically elided by the API. + + +## Boolean operators (and operator precedence) + +As evinced in the examples shown earlier in this vignette, you can +use the boolean operators __and__, __or__, and __not__ to refine your +search. + +As you mix different boolean operators in a single query, care must be +taken to ensure that the order/precedence of these operators matches +your intention. + +For example, in one of the examples above, we searched for Hip Hop materials +on wax, cassette, or CD published from 1987 to 1990 with the following +SRU query + +``` +'(($material_type=cas or $material_type=cda or $material_type=lps) + and $subject="Rap") and $year="1987-1990"' +``` + +It's important to note that if we wrote the query like shown below + +``` +$material_type=cas or $material_type=cda or $material_type=lps + and $subject="Rap" and $year="1987-1990"' +``` + +without any parentheses, the meaning of the query would be ambiguous. +Make sure you use parentheses around distinct sections of your search +incantation to disambiguate the query. + +## Wildcards + +_taken verbatim from the archived documentation_ + +For right truncation use an asterisk - * There must be at least three +characters before the * for the query to work. There is no left truncation. + +To wildcard a single character wildcard use a number sign - #. So a query +for wom#n provides results that include both woman and women in the results. + +For a 0-9 number of characters as wildcard characters use ?n. So a query +for colo?1r provides results of color and colour. + +To wildcard characters within (or at the end) a term use the question +mark - ?. So a query for colo?r provides results of color, colour, colonizer, +and colorimeter. + +## Table of all available search indexes + + | Formal search index code | libbib alias | + |--------------------------|--------------| + | srw.kw | $keyword | + | srw.ti | $title | + | srw.ln | $language | + | srw.au | $author | + | srw.yr | $year | + | srw.su | $subject | + | srw.li | $holding_library | + | srw.mt | $material_type | + | srw.no | $oclc | + | srw.lc | $lc_call | + | srw.dd | $dewey | + | srw.dn | $lccn | + | srw.bn | $isbn | + | srw.in | $issn | + | srw.cg | $library_holdings_group | + | srw.la | $language_code | + | srw.pl | $place_of_publication | + | srw.pb | $publisher | + | srw.am | $access_method | + | srw.cn | $corporate_conference_name | + | srw.pc | $dlc_limit | + | srw.dt | $document_type | + | srw.gn | $government_document_number | + | srw.mn | $music_publisher_number | + | srw.nt | $notes | + | srw.on | $open_digital_limit | + | srw.pn | $personal_name | + | srw.se | $series | + | srw.sn | $standard_number | + + +## Selected Search Indexes in focus + +### $title / srw.ti + +According to the archived Search API documentation, (I have strong doubts) +the title search phrase will automatically elide certain common and +"un-important" words. In the field of Natural Language Processing, +we call these "stop words". + +The archive docs indicates that the following words will be removed +from the search phase: + +a, als, am, an, are, as, at, auf, aus, be, but, by, das, dass, de, der, +des, dich, dir, du, er, es, for, from, had, have, he, her, his, how, ihr, +ihre, ihres, im, in, is, ist, it, kein, la, le, les, mein, mich, mir, mit, +of, on, sein, sie, that, the, this, to, un, une, von, was, wer, which, wie, +wird, with, yousie, that, the, this, to, un, une, von, was, wer, which, wie, +wird, with, you. + +This means that title searches for _The Brothers Karamazov_, +_La Noche Boca Arriba_, _Das Spiel ist aus_, or _Das Kapital_ will, +alledgely, internally use the seach phrases _Brothers Karamazov_, +_Noche Boca Arriba_, _Spiel_, and _Kapital_, respectively. + +When searching the title index, though, I'd leave these words in the +SRU search query for two reasons... + + - It makes the title search phrase more readable, _especially_ with + non-english phrases. + + - I have strong doubts that all of these words are elided. For example, + a search for _Das Spiel ist aus_, yields results as if the search phrase + were indeed _Das Spiel ist aus_, and not as if it were simply _Spiel_. + +### $holding_library / srw.li + +As shown in one of the examples above, the holding library search term +is the official OCLC designator. You can search for an institution's +code by the institutions name [using this link.](https://www.oclc.org/en/contacts/libraries.html) + +### $material_type / srw.mt + +An exhaustive crosswalk of all material types and their (normally 3-letter) +codes would be too large to include here, but you can access the crosswalk +in the documentation that is archived [at this link](https://web.archive.org/web/20210426232556/https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en%3E) + +### $library_holdings_group / srw.cg + +The "library holdings group" search term is, perhaps, a confusing one. +The table below is a crosswalk between the search codes to use in the +SRU query, and what they mean. + + | Search code | Meaning | + |-------------|---------| + | 05 | 5 or more holdings | + | 06 | 10 or more holdings | + | 07 | 50 or more holdings | + | 08 | 100 or more holdings | + | 09 | 500 or more holdings | + | 10 | No holdings | + | 11 | 1 holding only | + | 12 | 2 – 4 holdings | + | 13 | 5 – 9 holdings | + | 14 | 10 – 24 holdings | + | 15 | 25 – 49 holdings | + | 16 | 50 - 74 holdings | + | 17 | 75 – 99 holdings | + | 18 | 100 - 149 holdings | + | 19 | 150 - 199 holdings | + | 20 | 200 - 299 holdings | + | 21 | 300 - 399 holdings | + | 22 | 400 - 499 holdings | + | 23 | 500 - 599 holdings | + | 24 | 600 - 699 holdings | + | 25 | 700 - 799 holdings | + | 26 | 800 - 899 holdings | + | 27 | 900 - 999 holdings | + | 28 | 1,000 - 1,499 holdings | + | 29 | 1,500 - 1,999 holdings | + | 30 | 2,000 - 2,499 holdings | + | 31 | 2,500 or more holdings | + +So, for example, if you wanted to limit your search to +items that are held by between 100 to 149 institutions, +you would have to add `$library_holdings_group=18` to +your SRU query. + +### others + +For all the available search indexes, it is very helpful to know which +exact MARC fields are searched in each one. +[This archived documentation link](https://web.archive.org/web/20130915101232/http://oclc.org/developer/documentation/worldcat-search-api/complete-list-indexes) contains that information. + +On that page, the SRU index codes have a prefix of `sru`, but it's really +`srw`. +Consult the _Table of all available search indexes_ above to find the libbib +aliases for the indexes of interest (though, of course, you can use the +un-translated index codes if you'd like, too). + +----- + +## Options in the `worldcat_api_search` function + +Besides for, of course, the SRU query, the `worldcat_api_search` function +takes a number of optional parameters that can be used to alter its semantics. +Below is a list and explanation of each of those parameters. +(This information is also available by running +`help("worldcat_api_search")` in an R console after loading the `libbib` +package.) + + - __max_records__ + The maximum number of search results to return. This must be a number + between 0 and 100 or `Inf`. If `Inf`, the function will automatically + make all follow-up requests to retrieve all search results. + To limit the number of times the API is hit, the default is 10 search + results. + + - __sru_query_assist__ + A logical (boolean) indicating whether translation from more human-readable + aliases to the SRU search index codes should be allowed. The default + is `TRUE`. It can also be set to `FALSE`. + You can control this parameter globally by setting + `options("libbib.sru_query_assist")`. + + - __frbrGrouping__ + FRBR (_Functional Requirements for Bibliographic Records_) is a conceptual + framework for understanding the relationships between a "work" (e.g. a + novel as planned by an author), its "expression" (e.g. the manuscript of + that novel), it's "manifestation" (e.g. the first published version of + the novel), and, finally, an "item" (e.g an actual physical book + [or microform; audio file; etc...] of the work). + With the `frbrGrouping` parameter set to `on` (default), an attempt is + made by the WorldCat API to group together similar editions and present + only the top held record as the representative record for that group. + This, conceptually, can be viewed as an attempt to return search results for + any expression of the "work" (or works) referred to in the search query. + + - __start_at__ + The search result to start at (default is 1) + + - __wskey__ + A WorldCat API key. This function is easiest to use by setting the + wskey globally, with the following incantation: + `options(libbib.wskey="YOUR WSKEY GOES HERE")` + + - __more__ + A logical indicating whether more information from the MARCXML + search results should be returned (publisher, bib level, etc....). + The default is `TRUE`. + + - __print.progress__ + A logical indicating whether a message should be displayed for each + API request. If `max_records` is `Inf` a message will be displayed for + every group of 100 search results the function fetches. The default is + `TRUE`. + + - __debug__ + A logical indicating whether the HTTP and API responses should be printed + (for debugging). The default is `FALSE`. + + +## Combining this with the other API search functions in `libbib` + +There are numerous ways to combine the `worldcat_api_search` with the +other functions that `libbib` provides to do some really useful +investigations. In the example below, will be using the +`worldcat_api_search` and `worldcat_api_locations_by_oclc` functions to +get a list of institutions that hold any edition of my textbook. (This +example uses some `data.table` specific syntax for brevity, but it will +work with base R [or "tidyverse"] translations just fine.) + +First, let's use the search function to get a list of all search results +for the book... + +```{r, eval=FALSE} +results <- worldcat_api_search('srw.ti="Data Analysis with r" + and srw.au=fischetti', + max_records=Inf) + +# inspect some of the columns in the first 5 results +results[1:5, .(total_wc_results, result_number, oclc, + title, author, pub_date) +#> total_wc_results result_number oclc title +#> +#> 1: 11 1 1005106045 DATA ANALYSIS WITH R -. +#> 2: 11 2 1089176194 Data analysis with R : +#> 3: 11 3 949229431 Data analysis with R : +#> 4: 11 4 1242682069 Data Analysis with R +#> 5: 11 5 1242707288 Data Analysis with R +#> author pub_date +#> +#> 1: FISCHETTI, TONY. 2018 +#> 2: Fischetti, Tony. 2018 +#> 3: Fischetti, Tony. 2015 +#> 4: Fischetti, Tony 2015 +#> 5: Fischetti, Tony 2015 +``` + +Now let's get all the unique OCLC numbers from all the search results. + +```{r, eval=FALSE} +all_the_oclcs <- results[, unique(oclc)] +all_the_oclcs +#> [1] "1005106045" "1089176194" "949229431" "1242682069" "1242707288" +#> [6] "1244405806" "1104264768" "1242685020" "1242707684" "1244406814" +#> [11] "1104846312" +``` + +On to the `worldcat_api_locations_by_oclc` function! +Since this function takes one OCLC number at a time, we need to use +a looping-construct to run the function with _all_ the OCLC numbers +in `all_the_oclcs`. +We'll be using the `pblapply` function (from the great `pbapply` package) +to do this because we get a useful progress bar with no extra effort. + +```{r, eval=FALSE} +holds <- pblapply(all_the_oclcs, + function(x){ + worldcat_api_locations_by_oclc(x, + include.bib.info=FALSE) + }) +``` + +Since the `pblapply` function returns a list of `data.tables` (on for each +OCLC), we'll use `data.table`'s `rbindlist` function to one `data.table` +containing all the results. + +```{r, eval=FALSE} +all_holdings_dt <- rbindlist(holds) +all_holdings_dt[1:3] +#> oclc institution_identifier institution_name copies +#> +#> 1: 1005106045 FEM The Ferguson Library 1 +#> 2: 1005106045 YDX YBP Library Services 1 +#> 3: 1005106045 DUQ Duquesne University Library 1 + +all_holdings_dt[, .(institution_name)] +#> institution_name +#> +#> 1: The Ferguson Library +#> 2: YBP Library Services +#> 3: Duquesne University Library +#> 4: Centennial College +#> 5: George Brown College +#> --- +#> 1029: Hochschule Mittweida (FH), Hochschulbibliothek +#> 1030: Cyberlibris +#> 1031: Cyberlibris +#> 1032: Cyberlibris +#> 1033: BibliothĂšque de l'UniversitĂ© du QuĂ©bec Ă  Trois-Riv... +``` + +There you have it! My textbook is held by 1033 distinct OCLC institutions! + +Although the example above only searches the holding institutions of one +specific book, the idiom is most helpful/interesting/cool when used for +finding the holding institution of a entire class of materials. + +For example, in a recent project for a curator at my institution, I used +the Search API to find all search results for materials on a very specific +topic, got all the holding institutions for each of the search results, and +then aggregated the institutions (with this package's `dt_counts_and_percents` +function) to find the institutions holding the most items on this particular +(very specific) topic. + +----- + +## Sundry external / archived documentation links + + +- __WorldCat Search API current documentation__ + + _scroll to SRU_ + + Current documentation on the (SRU) WorldCat Search API call. Contains all + index names and codes, parameters available, and the meaning of API + status code return numbers + + + + +- __WorldCat Search API > Using the API > Request Types > SRU__ + + _(archived OCLC documentation link from 2013)_ + + Examples of simple SRU requests and explanation of `frbrGrouping` + and `servicelevel` parameters + + + + +- __WorldCat Search API > Indexes__ + + _(archived OCLC documentation link from 2013)_ + + Explation of relations operators, boolean operators, title index + stop-words (removed words), the MARC subfields search by (only) the subject + index, and explation of the wildcard characters `*`; `#`; and `?`. + + + + +- __WorldCat Search API > Indexes > Complete List of Indexes__ + + _(archived OCLC documentation link from 2013)_ + + Explation of relations operators and a complete list of all indexes, their + respective SRU index code, the relations available for use with each, and + the MARC fields search for each index. Here, the SRU index codes have a + prefix of `sru`, but it's really `srw`. + + + + +- __Material Types Names and Codes__ + + A complete list of Material Types you can search for, their codes + + For use with the `srw.mt`/`$material_type` index. + + [Material Type names and codes - OCLC Support](https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en) + + [Archived from original for posterity](https://web.archive.org/web/20210425140401/https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en>) + + +- __WorldCat Search API > Indexes > Tips for specific indexes__ + + _(archived OCLC documentation link from 2013)_ + + Contains a lot of very helpful information about some of the different + search indexes, the stop words they use, normalization rules, and + a very helpful cross-walk on the "Number of Holding Libraries" index. + + + + +- __WorldCat Search API > Using the API > Parameters__ + + _(archived OCLC documentation link from 2013)_ + + Helpful information about what the different SRU search parameters mean. + Remember that the parameters of the `worldcat_api_search` function (a) only + contain a subset of these, and (b) may have slightly different names + + + +- __Finding Institution Codes__ + + A search box for searching institution names and returning instituion + codes suitable for use in the holding institution search index. + + + + +- __Searching WorldCat Indexes__ + + _(archived OCLC documentation link from 2012)_ + + Information about search indexes that are largely available in the above + links. Not related to the (SRU) Search API but could be helpful, anyway. + + + + +- __CQL specification__ + + Helpful information about CQL query syntax. Not all is applicable to + the WorldCat Search API that is discussed here. + + + + +- __Searching WorldCat Indexes__ + + Current page with links containing a lot of information about + wielding WorldCat searches. Not all information is application to + the WorldCat Search API that is discussed here, and most of the + most helpful information is already covered in the links above. + + + + + +## Similar projects / code + +- __A Ruby Gem to communicate with the WorldCat Search API__ + + + + +- __Python scripts using the WorldCat search API__ + + + + +## Papers/Articles + +- __Using the WorldCat API to Develop Data-Driven Decision-Making for Gifts-in-Kind__ + + + + +- __Destroyer and Preserver, Hear, Oh Hear! Not All Uncirculated Books Must Chariotest to a Dark Wintry Bed: How We Used the Books Must Chariotest to a Dark Wintry Bed: How We Used the OCLC WorldCat Search API to Inform Our Weeding Decisions with OCLC WorldCat Search API to Inform Our Weeding Decisions with Holdings Data Holdings Data__ + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.html b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.html new file mode 100644 index 0000000..982b60b --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/inst/doc/using-the-worldcat-search-api.html @@ -0,0 +1,1345 @@ + + + + + + + + + + + + + + +Using the WorldCat Search API + + + + + + + + + + + + + + + + + + + + + + + + + + +

Using the WorldCat Search API

+ + + +
# let's load this package before getting started
+library(libbib)
+

Intermediate knowledge of R is required to follow the examples +here.

+

Basic knowledge of how to manipulate data.tables if +helpful but following the examples should be possible without +it.

+
+

Introduction

+

libbib’s ability to communicate to the WorldCat Search +API is probably the most helpful capability of the package. As such, an +entire vignette dedicated to this powerful tool is warranted.

+

Also of note is that documentation on how to use this API is +scattered throughout the web, in different places, and sometimes even no +longer available and only accessible through the internet archive. +Because of this, the goal of this vignette is not only to document +libbib’s worldcat_api_search function, but to +provide a single location for compiling this archived documentation and +providing information/examples of what the WorldCat Search API is +capable, in general.

+

The terminology/nomenclature of the different WorldCat API offerings +is fuzzy and inconsistent. The specific kind of Search API that this +package offers usage of can, more specifically, be described as the +‘WorldCat SRU Search API version 1’.

+

There is a version 2 of this API, but version 1 hasn’t been sunsetted +as of yet.

+

First, let’s speak of what this API is and what it is not.

+
+
+

What the WorldCat SRU Search API is

+

This API is allows a developer to search for bibliographic records +that are cataloged in WorldCat.

+

The queries are made using the SRU +standard search protocol (Search/Retrieve via URL) using a standard +query syntax called CQL +(Contextual Query Language). The WorldCat Search API doesn’t implement +all features of CQL; this vignette will illustrate SRU/CQL only insofar +as it is supported by this API.

+

This API is open to libraries that maintain both WorldCat Discovery +and OCLC Cataloging subscriptions and needs an API key (called a +WSKey) to work. A request can be made for a key (if your +institution doesn’t already have one) via this +link.

+
+
+

What the WorldCat SRU Search API is not

+

This API is not the OpenSearch/Basic API, which doesn’t allow +field-specific searches and only supports keyword-anywhere searches.

+

This is also not the same as using the advanced search option on +worldcat.org. That option only provides a subset of the +bibliographic records in WorldCat and is a far less powerful tool.

+

This API is most akin to using the “expert search” option in OCLC’s +FirstSearch, using the WorldCat database, but differs in that (a) +searching the API is programmatically automate-able, and (b) the API +allows for, still, more powerful search queries.

+
+
+

What libbib’s worldcat_api_search function +provides

+

At its most basic, this function takes a SRU query and returns a +data.table with most of the bibliographic metadata from the +MARCXml that the API returns. We’ll see how the behavior of this +function can be controlled by specifying certain function +parameters.

+

This function also offers assistance with the SRU query syntax. +Mainly, the function allows you to substitute the arcane search index +codes for more human-readable equivalents, prefixed be a (US) +dollar-sign. Examples of these aids will be explained later in the +vignette.

+
+
+

An example of usage and what the function returns

+

Let’s look at an example of a simple query and what the returned +data.table looks like.

+

Specifically, we’ll search for “Madame Bovary” by “Gustave Flaubert” +and we’ll only show the first three results

+
library(libbib)      # load this package
+
+result <- worldcat_api_search('$title="Madame Bovary" and
+                                 $author="Gustave Flaubert"')
+
+# get the column names
+names(result)
+#>  [1] "total_wc_results" "result_number"   "oclc"           "isbn"            
+#>  [5] "issn"             "title"           "author"         "pub_date"        
+#>  [9] "lang_code"        "bib_level"       "record_type"    "pub_place_code"  
+#> [13] "publisher"        "leader"          "oh08"           "query"
+
+# show the first three results
+result[1:3,]
+#>    total_wc_results result_number       oclc          isbn   issn
+#>              <char>         <int>     <char>        <char> <char>
+#> 1:              986             1 1125170419 9782253183464   <NA>
+#> 2:              986             2 1049849403 9788415618843   <NA>
+#> 3:              986             3 1203070641 9781664921993   <NA>
+#>              title             author pub_date lang_code      bib_level
+#>             <char>             <char>    <int>    <char>         <char>
+#> 1: Madame Bovary : Flaubert, Gustave,     2019       fre Monograph/Item
+#> 2: Madame Bovary / Flaubert, Gustave,     2019       spa Monograph/Item
+#> 3: Madame Bovary / Flaubert, Gustave,     2021       eng Monograph/Item
+#>                   record_type pub_place_code          publisher
+#>                        <char>         <char>             <char>
+#> 1:          Language Material             fr le Livre de poche,
+#> 2:          Language Material             sp               <NA>
+#> 3: Nonmusical sound recording            ohu               <NA>
+#>                      leader                                     oh08
+#>                      <char>                                   <char>
+#> 1: 00000cam a2200000Mi 4500 190619s2019    fr a   g      000 1 fre d
+#> 2: 00000cam a2200000Ii 4500 180827t20192018sp a          000 1 spa d
+#> 3: 00000cim a2200000Mi 4500 201104s2021    ohunnnneq      f  n eng d
+#>                                                    query
+#>                                                   <char>
+#> 1: srw.ti="Madame Bovary" and srw.au="Gustave Flauber...
+#> 2: srw.ti="Madame Bovary" and srw.au="Gustave Flauber...
+#> 3: srw.ti="Madame Bovary" and srw.au="Gustave Flauber...
+

This should give you an idea of the rich information returned by the +results data.table. All of the information returned is from +(or derived from) the MARCXml that the API returns, save for

+
    +
  • total_wc_results Which returns the number of the +results the query yields in WorldCat even if the number of +records/results requested is lower than this number.

  • +
  • result_number This number of the result, which is +helpful if you’re using a starting position other than 1 +(the default)

  • +
  • query The final SRU query (after any of the SRU +query assistance routines step in) that is sent to the API. This can be +useful for debugging.

  • +
+

Hereafter, the output of the example queries will be abbreviated, +truncated, elided, or only show a subset of columns in order to save +space and aid in following the guide.

+
+
+

What does an error look like

+

If you craft a query that yields no results, a message telling you +such will be displayed, and the return value is NULL.

+

If you make an error in the query syntax, no results will be +returned, but a diagnostic message returned from the server may tell you +what went wrong. Here are two examples


+
# missing ending double quotes
+worldcat_api_search('$title="Madame Bovary and $langauge=greek')
+#> Received diagnostic message: Query syntax error (org.z3950.zing.cql.CQLParseException: expected index or term, got EOF)
+#> no results found
+#> NULL
+
+# "$titley" is not a valid search index
+worldcat_api_search('$titley="Madame Bovary" and $langauge=greek')
+#> Received diagnostic message: Unsupported index (srw.tiy)
+#> no results found
+#> NULL
+
+worldcat_api_search("$holding_library=NYP")
+#> Received diagnostic message: Limit index, can only be used to narrow a result
+#> for a non-limit index (srw.li)
+#> no results found
+#> NULL
+

This last one failed because $holding_library is +considered a limit index. This means that you can’t use it to +search directly, you can only combine with search facet with other +non-limiting indexes to filter the results. Hopefully this will make +more sense as you go through this vignette.

+
+
+

worldcat_api_search by example / quick start

+

In guides like this, there is frequently tension between wanting to +be a complete reference, and wanting to show cool/helpful examples at a +glance.

+

In service of easing this tension, we’ll first look at some examples +illustrating things this function can do and then turn our +attention to an adequate explanation of boolean operators, relations +operators, search indexes, etc


+

These examples are largely taken from the examples +section of the R documentation for this function.

+

These examples (and the ones further along in this vignette) will +also use data.table syntax to limit number of rows and +columns returned to aid reading.

+

We’ll be focusing on the types of queries you can use in this +section; controlling the behavior of the function via changing +parameters will come later.

+
library(libbib)
+
+# title search for "The Brothers Karamazov"
+results <- worldcat_api_search('$title="Brothers Karamazov"')
+
+# Madame Bovary by Gustave Flaubert in Greek
+sru <- '$author="Gustave Flaubert" and
+          $title="Madame Bovary" and
+          $language=greek'
+results <- worldcat_api_search(sru)
+
+# Hip Hop materials on wax, cassette, or CD published from
+# 1987 to 1990
+sru <- '(($material_type=cas or $material_type=cda or $material_type=lps)
+           and $subject="Rap") and $year="1987-1990"'
+results <- worldcat_api_search(sru)
+
+# keyword search for "Common Lisp" for materials held
+# at The New York Public Library
+sru <- '$keyword="common lisp" and $holding_library=NYP'
+results <- worldcat_api_search(sru)
+
+# keyword search for "Common Lisp" for materials held
+# by any of the members of the "Manhattan Research
+# Library Initiative" (MaRLI) joint borrowing program
+# (New York Public Library, Columbia University, and
+# New York University)
+sru <- '($keyword="common lisp" and $holding_library=NYP)
+          or ($keyword="common lisp" and $holding_library=ZYU)
+          or ($keyword="common lisp" and $holding_library=ZCU)'
+results <- worldcat_api_search(sru)
+
+# Books (only books) about Ethics (by dewey division 170s or
+# LC call number subject class "BJ") published in the 19th
+# century
+sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*" and
+           $material_type=bks'
+results <- worldcat_api_search(sru)
+
+# Materials on Musicology (by Dewey division 780s) at
+# the New York Public Library and not held by any
+# other insitution
+sru <- '$dewey="78*" and $holding_library=NYP and
+          $library_holdings_group=11'
+results <- worldcat_api_search(sru)
+
+# Search for materials on "Danger Music" published since 2010
+results <- worldcat_api_search('$keyword="danger music" and $year="2010-"')
+

Now that we’ve seen these examples, sans explanation, we can now have +a closer look into the components of a query. Broadly speaking, there +are four concepts to be aware of


+
    +
  • relations operators

  • +
  • boolean operators

  • +
  • wildcards

  • +
  • search indexes

  • +
+

We’ll be looking at each in this order, because I think that makes +the most sense. To illustrate the first three concepts, though, we have +to use search indexes, before a formal explanation of what they are.

+

Briefly, a search index is a facet along which to search. In all of +the examples above, the search indexes were prefixed by a $ +character (e.g. $title, author, +$keyword, etc
)

+
+
+

Relations operators

+

There are four relations operators available for use


+
    +
  • =

  • +
  • exact

  • +
  • any

  • +
  • all

  • +
+

It should be noted that not every relations operator is available for +use with every search index.

+
+

=

+

This was the most common operator used in the quick-start examples +above. Though this operator can be most fully understood via contrast +with the next operator, exact, suffice it to say, for now, +that using = means that all of your search terms must +match, without intervening words. This is sometimes referred to as an +“un-anchored” search.

+

If the phrase you’re search for has spaces in it, you have to +surround it with double quotes. Since the SRU query to the +worldcat_api_search function must be a string, and strings +can be made with single quotes and double quotes, we need to surround +the entire query with single quotes.

+

We can get around this by “escaping” the quotes, but using only +single quotes to surround the whole query is the most elegant +approach.

+

You can use both spaces and + to separate the search +index and the search term on both sides of the relations operator


+
sru <- '$title+=+"Common Lisp"'
+results <- worldcat_api_search(sru)
+results[1:3, .(total_wc_results, title)]
+#>    total_wc_results                   title
+#>              <char>                  <char>
+#> 1:              367           Common Lisp /
+#> 2:              367 Practical Common Lisp /
+#> 3:              367           Common LISP /
+

is the same as


+
sru <- '$title = "Common Lisp"'
+results <- worldcat_api_search(sru)
+results[1:3, .(total_wc_results, title)]
+#>    total_wc_results                   title
+#>              <char>                  <char>
+#> 1:              367           Common Lisp /
+#> 2:              367 Practical Common Lisp /
+#> 3:              367           Common LISP /
+

But we’ll be using spaces here.

+

The = relations operator is the only one that doesn’t +require any space or + on either side of the operator, and +we’ll be using both the spaced version and non-spaced version in these +examples for this operator, only.

+
+ +
+

any

+

Using any means that any of your search terms (inside +the double quotes) can match. For example


+
results <- worldcat_api_search('$title any "Common Lisp"')
+results[1:3, .(total_wc_results, title)]
+#>    total_wc_results                                                 title
+#>              <char>                                                <char>
+#> 1:           351777 An Inquiry into the Human Mind on the Principles o...
+#> 2:           351777                            The book of common prayer.
+#> 3:           351777                        Dictionary of Phrase and Fable
+

matches the title “The book of common prayer” (decidedly not +a book of the subject of Common Lisp) since it has the word “common” in +it. (Note that capitalization doesn’t matter).

+

Using any in this context is tantamount to using an +or boolean operator, which we’ll look at in the next +section


+
results <- worldcat_api_search('$title = Common or $title = "Lisp"')
+results[1:3, .(total_wc_results, title)]
+#>    total_wc_results                                                 title
+#>              <char>                                                <char>
+#> 1:           351777 An Inquiry into the Human Mind on the Principles o...
+#> 2:           351777                            The book of common prayer.
+#> 3:           351777                        Dictionary of Phrase and Fable
+

(Note the same number and order of results)

+
+
+

all

+

Using the all operator means that all of the +search terms must match but the search terms can be in any order and +have intervening terms in between. For example, search like +$title all "Common Lisp" can match a (fictional) book named +“Speaking with a lisp is common”.

+
+
+

A quick note before continuing

+

If your search term is one word, you do not have to use double quotes +to surround the term. For example, $title = Ethics and +$title exact Ethics work perfectly well.

+

If your search term as a single quote in it, it must be escaped so +that R doesn’t interpret it as the end of the search string. That being +said, it appears as if you can just drop the single quote and the search +will carry on perfectly fine


+
results <- worldcat_api_search('$title exact "Finnegans Wake"')
+results[1:3, .(total_wc_results, title, query)]
+#>    total_wc_results            title                         query
+#>              <char>           <char>                        <char>
+#> 1:              761 Finnegans wake / srw.ti exact "Finnegans Wake"
+#> 2:              761   Finnegans Wake srw.ti exact "Finnegans Wake"
+#> 3:              761   Finnegans wake srw.ti exact "Finnegans Wake"
+
+# yields the same results as
+
+results <- worldcat_api_search('$title exact "Finnegan\'s Wake"')
+results[1:3, .(total_wc_results, title, query)]
+#>    total_wc_results            title                         query
+#>              <char>           <char>                        <char>
+#> 1:              761 Finnegans wake / srw.ti exact "Finnegan's Wake"
+#> 2:              761   Finnegans Wake srw.ti exact "Finnegan's Wake"
+#> 3:              761   Finnegans wake srw.ti exact "Finnegan's Wake"
+

I suspect single quotes are automatically elided by the API.

+
+
+
+

Boolean operators (and operator precedence)

+

As evinced in the examples shown earlier in this vignette, you can +use the boolean operators and, or, and +not to refine your search.

+

As you mix different boolean operators in a single query, care must +be taken to ensure that the order/precedence of these operators matches +your intention.

+

For example, in one of the examples above, we searched for Hip Hop +materials on wax, cassette, or CD published from 1987 to 1990 with the +following SRU query

+
'(($material_type=cas or $material_type=cda or $material_type=lps)
+   and $subject="Rap") and $year="1987-1990"'
+

It’s important to note that if we wrote the query like shown +below

+
$material_type=cas or $material_type=cda or $material_type=lps
+   and $subject="Rap" and $year="1987-1990"'
+

without any parentheses, the meaning of the query would be ambiguous. +Make sure you use parentheses around distinct sections of your search +incantation to disambiguate the query.

+
+
+

Wildcards

+

taken verbatim from the archived documentation

+

For right truncation use an asterisk - * There must be at least three +characters before the * for the query to work. There is no left +truncation.

+

To wildcard a single character wildcard use a number sign - #. So a +query for wom#n provides results that include both woman and women in +the results.

+

For a 0-9 number of characters as wildcard characters use ?n. So a +query for colo?1r provides results of color and colour.

+

To wildcard characters within (or at the end) a term use the question +mark - ?. So a query for colo?r provides results of color, colour, +colonizer, and colorimeter.

+
+
+

Table of all available search indexes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Formal search index codelibbib alias
srw.kw$keyword
srw.ti$title
srw.ln$language
srw.au$author
srw.yr$year
srw.su$subject
srw.li$holding_library
srw.mt$material_type
srw.no$oclc
srw.lc$lc_call
srw.dd$dewey
srw.dn$lccn
srw.bn$isbn
srw.in$issn
srw.cg$library_holdings_group
srw.la$language_code
srw.pl$place_of_publication
srw.pb$publisher
srw.am$access_method
srw.cn$corporate_conference_name
srw.pc$dlc_limit
srw.dt$document_type
srw.gn$government_document_number
srw.mn$music_publisher_number
srw.nt$notes
srw.on$open_digital_limit
srw.pn$personal_name
srw.se$series
srw.sn$standard_number
+
+
+

Selected Search Indexes in focus

+
+

$title / srw.ti

+

According to the archived Search API documentation, (I have strong +doubts) the title search phrase will automatically elide certain common +and “un-important” words. In the field of Natural Language Processing, +we call these “stop words”.

+

The archive docs indicates that the following words will be removed +from the search phase:

+

a, als, am, an, are, as, at, auf, aus, be, but, by, das, dass, de, +der, des, dich, dir, du, er, es, for, from, had, have, he, her, his, +how, ihr, ihre, ihres, im, in, is, ist, it, kein, la, le, les, mein, +mich, mir, mit, of, on, sein, sie, that, the, this, to, un, une, von, +was, wer, which, wie, wird, with, yousie, that, the, this, to, un, une, +von, was, wer, which, wie, wird, with, you.

+

This means that title searches for The Brothers Karamazov, +La Noche Boca Arriba, Das Spiel ist aus, or Das +Kapital will, alledgely, internally use the seach phrases +Brothers Karamazov, Noche Boca Arriba, Spiel, +and Kapital, respectively.

+

When searching the title index, though, I’d leave these words in the +SRU search query for two reasons


+
    +
  • It makes the title search phrase more readable, +especially with non-english phrases.

  • +
  • I have strong doubts that all of these words are elided. For +example, a search for Das Spiel ist aus, yields results as if +the search phrase were indeed Das Spiel ist aus, and not as if +it were simply Spiel.

  • +
+
+
+

$holding_library / srw.li

+

As shown in one of the examples above, the holding library search +term is the official OCLC designator. You can search for an +institution’s code by the institutions name using this +link.

+
+
+

$material_type / srw.mt

+

An exhaustive crosswalk of all material types and their (normally +3-letter) codes would be too large to include here, but you can access +the crosswalk in the documentation that is archived at +this link

+
+
+

$library_holdings_group / srw.cg

+

The “library holdings group” search term is, perhaps, a confusing +one. The table below is a crosswalk between the search codes to use in +the SRU query, and what they mean.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Search codeMeaning
055 or more holdings
0610 or more holdings
0750 or more holdings
08100 or more holdings
09500 or more holdings
10No holdings
111 holding only
122 – 4 holdings
135 – 9 holdings
1410 – 24 holdings
1525 – 49 holdings
1650 - 74 holdings
1775 – 99 holdings
18100 - 149 holdings
19150 - 199 holdings
20200 - 299 holdings
21300 - 399 holdings
22400 - 499 holdings
23500 - 599 holdings
24600 - 699 holdings
25700 - 799 holdings
26800 - 899 holdings
27900 - 999 holdings
281,000 - 1,499 holdings
291,500 - 1,999 holdings
302,000 - 2,499 holdings
312,500 or more holdings
+

So, for example, if you wanted to limit your search to items that are +held by between 100 to 149 institutions, you would have to add +$library_holdings_group=18 to your SRU query.

+
+
+

others

+

For all the available search indexes, it is very helpful to know +which exact MARC fields are searched in each one. This +archived documentation link contains that information.

+

On that page, the SRU index codes have a prefix of sru, +but it’s really srw. Consult the Table of all available +search indexes above to find the libbib aliases for the indexes of +interest (though, of course, you can use the un-translated index codes +if you’d like, too).

+
+
+
+
+

Options in the worldcat_api_search function

+

Besides for, of course, the SRU query, the +worldcat_api_search function takes a number of optional +parameters that can be used to alter its semantics. Below is a list and +explanation of each of those parameters. (This information is also +available by running help("worldcat_api_search") in an R +console after loading the libbib package.)

+
    +
  • max_records The maximum number of search results +to return. This must be a number between 0 and 100 or Inf. +If Inf, the function will automatically make all follow-up +requests to retrieve all search results. To limit the number of times +the API is hit, the default is 10 search results.

  • +
  • sru_query_assist A logical (boolean) indicating +whether translation from more human-readable aliases to the SRU search +index codes should be allowed. The default is TRUE. It can +also be set to FALSE. You can control this parameter +globally by setting +options("libbib.sru_query_assist").

  • +
  • frbrGrouping FRBR (Functional Requirements +for Bibliographic Records) is a conceptual framework for +understanding the relationships between a “work” (e.g. a novel as +planned by an author), its “expression” (e.g. the manuscript of that +novel), it’s “manifestation” (e.g. the first published version of the +novel), and, finally, an “item” (e.g an actual physical book [or +microform; audio file; etc
] of the work). With the +frbrGrouping parameter set to on (default), an +attempt is made by the WorldCat API to group together similar editions +and present only the top held record as the representative record for +that group. This, conceptually, can be viewed as an attempt to return +search results for any expression of the “work” (or works) referred to +in the search query.

  • +
  • start_at The search result to start at (default +is 1)

  • +
  • wskey A WorldCat API key. This function is +easiest to use by setting the wskey globally, with the following +incantation: +options(libbib.wskey="YOUR WSKEY GOES HERE")

  • +
  • more A logical indicating whether more +information from the MARCXML search results should be returned +(publisher, bib level, etc
.). The default is +TRUE.

  • +
  • print.progress A logical indicating whether a +message should be displayed for each API request. If +max_records is Inf a message will be displayed +for every group of 100 search results the function fetches. The default +is TRUE.

  • +
  • debug A logical indicating whether the HTTP and +API responses should be printed (for debugging). The default is +FALSE.

  • +
+
+
+

Combining this with the other API search functions in +libbib

+

There are numerous ways to combine the +worldcat_api_search with the other functions that +libbib provides to do some really useful investigations. In +the example below, will be using the worldcat_api_search +and worldcat_api_locations_by_oclc functions to get a list +of institutions that hold any edition of my textbook. (This example uses +some data.table specific syntax for brevity, but it will +work with base R [or “tidyverse”] translations just fine.)

+

First, let’s use the search function to get a list of all search +results for the book


+
results <- worldcat_api_search('srw.ti="Data Analysis with r"
+                                  and srw.au=fischetti',
+                                max_records=Inf)
+
+# inspect some of the columns in the first 5 results
+results[1:5, .(total_wc_results, result_number, oclc,
+               title, author, pub_date)
+#>    total_wc_results result_number       oclc                   title
+#>              <char>         <int>     <char>                  <char>
+#> 1:               11             1 1005106045 DATA ANALYSIS WITH R -.
+#> 2:               11             2 1089176194  Data analysis with R :
+#> 3:               11             3  949229431  Data analysis with R :
+#> 4:               11             4 1242682069    Data Analysis with R
+#> 5:               11             5 1242707288    Data Analysis with R
+#>              author pub_date
+#>              <char>    <int>
+#> 1: FISCHETTI, TONY.     2018
+#> 2: Fischetti, Tony.     2018
+#> 3: Fischetti, Tony.     2015
+#> 4:  Fischetti, Tony     2015
+#> 5:  Fischetti, Tony     2015
+

Now let’s get all the unique OCLC numbers from all the search +results.

+
all_the_oclcs <- results[, unique(oclc)]
+all_the_oclcs
+#>  [1] "1005106045" "1089176194" "949229431"  "1242682069" "1242707288"
+#>  [6] "1244405806" "1104264768" "1242685020" "1242707684" "1244406814"
+#> [11] "1104846312"
+

On to the worldcat_api_locations_by_oclc function! Since +this function takes one OCLC number at a time, we need to use a +looping-construct to run the function with all the OCLC numbers +in all_the_oclcs. We’ll be using the pblapply +function (from the great pbapply package) to do this +because we get a useful progress bar with no extra effort.

+
holds <- pblapply(all_the_oclcs,
+                  function(x){
+                    worldcat_api_locations_by_oclc(x,
+                      include.bib.info=FALSE)
+                    })
+

Since the pblapply function returns a list of +data.tables (on for each OCLC), we’ll use +data.table’s rbindlist function to one +data.table containing all the results.

+
all_holdings_dt <- rbindlist(holds)
+all_holdings_dt[1:3]
+#>          oclc institution_identifier            institution_name copies
+#>        <char>                 <char>                      <char> <char>
+#> 1: 1005106045                    FEM        The Ferguson Library      1
+#> 2: 1005106045                    YDX        YBP Library Services      1
+#> 3: 1005106045                    DUQ Duquesne University Library      1
+
+all_holdings_dt[, .(institution_name)]
+#>                                            institution_name
+#>                                                      <char>
+#>    1:                                  The Ferguson Library
+#>    2:                                  YBP Library Services
+#>    3:                           Duquesne University Library
+#>    4:                                    Centennial College
+#>    5:                                  George Brown College
+#>   ---
+#> 1029:        Hochschule Mittweida (FH), Hochschulbibliothek
+#> 1030:                                           Cyberlibris
+#> 1031:                                           Cyberlibris
+#> 1032:                                           Cyberlibris
+#> 1033: BibliothÚque de l'Université du Québec à Trois-Riv...
+

There you have it! My textbook is held by 1033 distinct OCLC +institutions!

+

Although the example above only searches the holding institutions of +one specific book, the idiom is most helpful/interesting/cool when used +for finding the holding institution of a entire class of materials.

+

For example, in a recent project for a curator at my institution, I +used the Search API to find all search results for materials on a very +specific topic, got all the holding institutions for each of the search +results, and then aggregated the institutions (with this package’s +dt_counts_and_percents function) to find the institutions +holding the most items on this particular (very specific) topic.

+
+
+ +
+

Similar projects / code

+ +
+
+

Papers/Articles

+ +
+ + + + + + + + + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/books_serials_etc_sample.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/books_serials_etc_sample.Rd new file mode 100644 index 0000000..591d01d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/books_serials_etc_sample.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/books_serials_etc_sample_data.R +\docType{data} +\name{books_serials_etc_sample} +\alias{books_serials_etc_sample} +\title{Small sample of books, monographs, and serials and their information} +\format{ +An object of class \code{"data.table"}; +} +\usage{ +data(books_serials_etc_sample) +} +\description{ +A very small sample of books, serials, VHSs, CDs, and Computer files +and some information including title, control numbers, call numbers, and +call number subject classifications. Somewhat messy/inconsistent +(deliberately) and mainly for testing. +Will be expanded in future versions. +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/car.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/car.Rd new file mode 100644 index 0000000..4db84e7 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/car.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/split-map-filter-reduce.R +\name{car} +\alias{car} +\title{Return first element of vector} +\usage{ +car(x) +} +\arguments{ +\item{x}{A vector} +} +\value{ +Returns first element of vector +} +\description{ +Takes a vector and returns the first element +Equivalent to Lisp's \code{car} function +} +\details{ +Originally for use as a reduction function in \code{split_map_filter_reduce} +} +\examples{ +library(data.table) +car(c(8, 6, 7, 5, 3, 0, 9)) # 8 +mt <- as.data.table(mtcars) +dt_del_cols(mt, "cyl", "disp", "hp") + +} +\seealso{ +\code{\link{split_map_filter_reduce}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_10_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_10_check_digit.Rd new file mode 100755 index 0000000..ee0ad23 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_10_check_digit.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{check_isbn_10_check_digit} +\alias{check_isbn_10_check_digit} +\title{Check the check digit of an ISBN 10} +\usage{ +check_isbn_10_check_digit(x, allow.hyphens = TRUE, errors.as.false = TRUE) +} +\arguments{ +\item{x}{A string of 10 digits or 9 digits with terminal "X"} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{FALSE})} + +\item{errors.as.false}{return false if error instead of throwing error +(default is \code{TRUE})} +} +\value{ +Returns TRUE if check passes, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISBN 10 and verifies that check digit +checks out +} +\examples{ + +check_isbn_10_check_digit("012491540X") # TRUE +check_isbn_10_check_digit("0-124-91540-X") # TRUE + +# vectorized +check_isbn_10_check_digit(c("012491540X", "9004037812")) # TRUE FALSE + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_13_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_13_check_digit.Rd new file mode 100644 index 0000000..22cc52a --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/check_isbn_13_check_digit.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{check_isbn_13_check_digit} +\alias{check_isbn_13_check_digit} +\title{Check the check digit of an ISBN 13} +\usage{ +check_isbn_13_check_digit(x, allow.hyphens = TRUE, errors.as.false = TRUE) +} +\arguments{ +\item{x}{A string of 13 digits} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{TRUE})} + +\item{errors.as.false}{return false if error instead of throwing error +(default is \code{TRUE})} +} +\value{ +Returns TRUE if check passes, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISBN 13 and verifies that check digit +checks out +} +\examples{ + +check_isbn_13_check_digit("9780306406157") # TRUE +check_isbn_13_check_digit("978-0-306-40615-7") # TRUE + +# vectorized +check_isbn_13_check_digit(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/check_issn_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/check_issn_check_digit.Rd new file mode 100644 index 0000000..97ab0a6 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/check_issn_check_digit.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{check_issn_check_digit} +\alias{check_issn_check_digit} +\title{Check the check digit of an ISSN} +\usage{ +check_issn_check_digit(x, allow.hyphens = TRUE, errors.as.false = FALSE) +} +\arguments{ +\item{x}{A string of 8 digits or 7 digits with terminal "X"} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{TRUE})} + +\item{errors.as.false}{return false if error instead of throwing error +(default is \code{FALSE})} +} +\value{ +Returns TRUE if check passes, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISSN and verifies that check digit +checks out +} +\examples{ + +check_issn_check_digit("2434561X") # TRUE +check_issn_check_digit("2434-561X") # TRUE + +# vectorized +check_issn_check_digit(c("03785955", "2434561X", NA)) # TRUE TRUE NA +check_issn_check_digit(c("0378-5955", "2434-561X", NA)) +# TRUE TRUE NA + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/convert_to_isbn_13.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/convert_to_isbn_13.Rd new file mode 100644 index 0000000..d84d0a0 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/convert_to_isbn_13.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{convert_to_isbn_13} +\alias{convert_to_isbn_13} +\title{Convert ISBN 10 to ISBN 13} +\usage{ +convert_to_isbn_13(x, skip.validity.check = FALSE, errors.as.nas = FALSE) +} +\arguments{ +\item{x}{A string of 10 digits or 9 digits with terminal "X"} + +\item{skip.validity.check}{Skip the checking for whether the ISBN 10 is valid +(default is \code{FALSE})} + +\item{errors.as.nas}{return NA if error instead of throwing error +(default is \code{FALSE})} +} +\value{ +Returns ISBN 13 as a string +} +\description{ +Takes a string representation of an ISBN 10 and converts it to an ISBN 13. +} +\examples{ + +convert_to_isbn_13("012491540X") # 9780124915404 + +# vectorized +convert_to_isbn_13(c("012491540X", "9004037810")) +# "9780124915404" "9789004037816" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/country_code_crosswalk.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/country_code_crosswalk.Rd new file mode 100644 index 0000000..da86995 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/country_code_crosswalk.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/country_code_crosswalk-data.R +\docType{data} +\name{country_code_crosswalk} +\alias{country_code_crosswalk} +\title{Country code / country crosswalk} +\format{ +An object of class \code{"data.table"}; +} +\source{ +\url{https://www.loc.gov/marc/countries/countries_code.html} +} +\usage{ +data(country_code_crosswalk) +} +\description{ +A cross-walk between the country code +and it's human readable version +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/cp_lb_attributes.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/cp_lb_attributes.Rd new file mode 100644 index 0000000..42b476e --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/cp_lb_attributes.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/special-attributes.R +\name{cp_lb_attributes} +\alias{cp_lb_attributes} +\title{Copy special libbib attributes from one object to another} +\usage{ +cp_lb_attributes(a, b) +} +\arguments{ +\item{a}{The first object (the one with the attributes to copy)} + +\item{b}{The second object (the one to copy those attributes to)} +} +\value{ +Nothing, since the object is modified by reference. +} +\description{ +Takes two objects and copies all special libbib attributes +(attributes beginning with \code{lb.}) from the first object +to the second, by reference. +} +\examples{ + +tmp1 <- "a" +set_lb_date(tmp1, "2021-05-08") +set_lb_attribute(tmp1, "note", "just an example") + +tmp2 <- "b" +cp_lb_attributes(tmp1, tmp2) +attributes(tmp2)$lb.date +# [1] "2021-05-08" +attributes(tmp2)$lb.note +# [1] "just an example" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dewey_subject_crosswalk.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dewey_subject_crosswalk.Rd new file mode 100644 index 0000000..606d36e --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dewey_subject_crosswalk.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/dewey_subject_crosswalk-data.R +\docType{data} +\name{dewey_subject_crosswalk} +\alias{dewey_subject_crosswalk} +\title{Dewey Decimal Classification / Subject Description crosswalk} +\format{ +An object of class \code{"data.table"}; +} +\source{ +Edited from \url{https://www.oclc.org/content/dam/oclc/dewey/ddc23-summaries.pdf} +} +\usage{ +data(dewey_subject_crosswalk) +} +\description{ +A cross-walk between the Dewey Decimal Classification code +and it's human readable subject description +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_add_to_col_names.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_add_to_col_names.Rd new file mode 100644 index 0000000..85e6903 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_add_to_col_names.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_add_to_col_names} +\alias{dt_add_to_col_names} +\title{Add string to all column names in a data.table} +\usage{ +dt_add_to_col_names( + DT, + astring, + prefix = FALSE, + exclude = NULL, + include = NULL, + fix.duplicates = FALSE +) +} +\arguments{ +\item{DT}{A data.table} + +\item{astring}{A string to add to each column name} + +\item{prefix}{A logical indicating whether the string should be added +to the beginning of each column name, instead of the end. +(default is \code{FALSE})} + +\item{exclude}{A quoted vector or column names to exclude from renaming. +Cannot co-exist with \code{include}} + +\item{include}{A quoted vector or column names. Changes names of only +these columns. Cannot co-exist with \code{exclude}} + +\item{fix.duplicates}{A logical indicating whether to, if after the +suffix/prefixes are added to the selected column +names, correct those duplicate column names by +making them unique. If \code{FALSE} (default), +if any of the column names are duplicated, an +error is raised and the new names are not set. +If \code{TRUE}, all the column names are made unique, +potentially renaming excluded column names that +were not supposed to be changed.} +} +\value{ +Returns data.table with string appended or prefixed to all selected + column names. +} +\description{ +Takes a data.table and a string. The supplied string will +be added to end of the each column's name. If \code{prefix} +is \code{TRUE}, the string is added to the beginning, instead. +} +\examples{ +library(data.table) +DT <- as.data.table(iris) + +dt_add_to_col_names(DT, "_post") +names(DT) +# [1] "Sepal.Length_post" "Sepal.Width_post" "Petal.Length_post" +# [4] "Petal.Width_post" "Species_post" + + DT <- as.data.table(iris) +dt_add_to_col_names(DT, "pre_", prefix=TRUE) +names(DT) +# [1] "pre_Sepal.Length" "pre_Sepal.Width" "pre_Petal.Length" "pre_Petal.Width" +# [5] "pre_Species" + +DT <- as.data.table(iris) +dt_add_to_col_names(DT, "_post", exclude="Species") +names(DT) +# [1] "Sepal.Length_post" "Sepal.Width_post" "Petal.Length_post" +# [4] "Petal.Width_post" "Species" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_counts_and_percents.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_counts_and_percents.Rd new file mode 100644 index 0000000..1e9bcbb --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_counts_and_percents.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_counts_and_percents} +\alias{dt_counts_and_percents} +\title{Group by, count, and percent count in a data.table} +\usage{ +dt_counts_and_percents(DT, group_by_this, percent.cutoff = 0, big.mark = FALSE) +} +\arguments{ +\item{DT}{The data.table object to operate on} + +\item{group_by_this}{A quoted column to group by} + +\item{percent.cutoff}{A percent (out of 100) such that all +the count percents lower than this number will be +grouped into "OTHER" in the returned data.table +(default is 0)} + +\item{big.mark}{If \code{FALSE} (default) the "count" column is left +as an integer. If not \code{FALSE}, it must be a +character to separate every three digits of the count. +This turns the count column into a string.} +} +\value{ +Returns a data.table with three columns: + the grouped-by column, a count column, and a + percent column (out of 100) to two decimal places +} +\description{ +This function takes a (quoted) column to group by, counts the +number of occurrences, sorts descending, and adds the percent +of occurrences for each level of the grouped-by column. +} +\details{ +For long-tailed count distributions, a cutoff on the percent can be +placed; percent of counts lower than this percent will be grouped +into a category called "OTHER". +The percent is a number out of 100 + +The final row is a total count. + +The quoted group-by variable must be a character or factor. If it is +not, it will be temporarily converted into one and a warning is issued. +} +\examples{ +library(data.table) + +iris_dt <- as.data.table(iris) +dt_counts_and_percents(iris_dt, "Species") +mt <- as.data.table(mtcars) +mt[, cyl:=factor(cyl)] +dt_counts_and_percents(mt, "cyl") +dt_counts_and_percents(mt, "cyl", percent.cutoff=25) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_del_cols.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_del_cols.Rd new file mode 100644 index 0000000..96ccc19 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_del_cols.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_del_cols} +\alias{dt_del_cols} +\title{Delete columns in a data.table} +\usage{ +dt_del_cols(DT, ...) +} +\arguments{ +\item{DT}{A data.table} + +\item{...}{arbitrary number of column names in quotes} +} +\value{ +Returns data.table with those columns removed +} +\description{ +Takes a data.table and a quoted sequence of column names +and removes the specified column names from the data.table +} +\examples{ +library(data.table) +mt <- as.data.table(mtcars) +dt_del_cols(mt, "cyl", "disp", "hp") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_keep_cols.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_keep_cols.Rd new file mode 100644 index 0000000..642dd4f --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_keep_cols.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_keep_cols} +\alias{dt_keep_cols} +\title{Keep columns in a data.table} +\usage{ +dt_keep_cols(DT, ...) +} +\arguments{ +\item{DT}{A data.table} + +\item{...}{arbitrary number of column names in quotes} +} +\value{ +Returns data.table with only those columns +} +\description{ +Takes a data.table and a quoted sequence of column names +and removes all columns but the ones specified +} +\examples{ +library(data.table) +mt <- as.data.table(mtcars) +dt_keep_cols(mt, "mpg", "am", "gear", "carb") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_na_breakdown.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_na_breakdown.Rd new file mode 100644 index 0000000..928d3fb --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_na_breakdown.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_na_breakdown} +\alias{dt_na_breakdown} +\title{Get a breakdown of the NA-status of a column in a data.table} +\usage{ +dt_na_breakdown(DT, acolumn, big.mark = FALSE) +} +\arguments{ +\item{DT}{The data.table object to operate on} + +\item{acolumn}{a quoted column name} + +\item{big.mark}{If \code{FALSE} (default) the "count" column is left +as an integer. If not \code{FALSE}, it must be a +character to separate every three digits of the count. +This turns the count column into a string.} +} +\value{ +Returns a data.table with three columns: + the not-NA status of the column specified, a count column, and a + percent column (out of 100) to two decimal places +} +\description{ +This function takes a (quoted) column to group by, and tabulates +the count of how many of those values are not-NA and NA, and adds +the percent of occurrences. A \code{TRUE} in the first output +column means the data is _not_ missing; \code{FALSE} corresponds +to missing. +} +\details{ +The final row is a total count + +The quoted group-by variable must be a character or factor +} +\examples{ +library(data.table) + +iris_dt <- as.data.table(iris) +iris_dt[sample(1:.N, 10), Species:=NA_character_] +dt_na_breakdown(iris_dt, "Species") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_percent_not_na.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_percent_not_na.Rd new file mode 100644 index 0000000..02727b7 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_percent_not_na.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_percent_not_na} +\alias{dt_percent_not_na} +\title{Return the percentage of non-NA instances in a data.table column} +\usage{ +dt_percent_not_na(DT, acolumn) +} +\arguments{ +\item{DT}{A data.table object} + +\item{acolumn}{a quoted column name} +} +\value{ +Returns percentage of non-NA instances in column +} +\description{ +This function takes a data.table and a quoted column name and +returns the percentage of the data in the column that is not +NA. +The percent is out of 100 and contains up to two decimal places +} +\examples{ +library(data.table) + +mt <- as.data.table(mtcars) +mt[mpg<16, mpg:=NA] +dt_percent_not_na(mt, "mpg") # 68.75 + +} +\seealso{ +\code{\link{is.na}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/dt_set_clean_names.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/dt_set_clean_names.Rd new file mode 100644 index 0000000..25883a9 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/dt_set_clean_names.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{dt_set_clean_names} +\alias{dt_set_clean_names} +\title{Takes a data.table and set to cleaned column names} +\usage{ +dt_set_clean_names(DT, lower = TRUE) +} +\arguments{ +\item{DT}{a data.table} + +\item{lower}{A logical indicating whether all column names should be +made lower case (default \code{TRUE}).} +} +\value{ +Returns the data.table but with cleaned names +} +\description{ +This function takes a data.table, and returns the same data.table +with column names that are cleaned and stripped of potentially +troublesome names +} +\details{ +All space/whitespace characters are replaced with underscores, +as are all characters not from A-Z, a-z, an underscore, or a digit +} +\examples{ +library(data.table) + +ejemplo <- as.data.table(iris) +setnames(ejemplo, c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\\\nWidth", "SpĂȘcies")) +dt_set_clean_names(ejemplo) + +} +\seealso{ +\code{\link{get_clean_names}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/fread_plus_date.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/fread_plus_date.Rd new file mode 100644 index 0000000..2c917c8 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/fread_plus_date.Rd @@ -0,0 +1,63 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/special-attributes.R +\name{fread_plus_date} +\alias{fread_plus_date} +\title{Read a file and set a special libbib date attribute} +\usage{ +fread_plus_date(fname, allow.fallback.date = TRUE, ...) +} +\arguments{ +\item{fname}{The file name to read} + +\item{allow.fallback.date}{A logical indicating whether, if no +matching file name with a date is found, +to use today's date as the date attribute. +Default is \code{TRUE}.} + +\item{...}{Arbitrary arguments to use with \code{fread}} +} +\value{ +A \code{data.table} with an attribute called \code{lb.date} set +} +\description{ +Takes a file name, reads it with \code{data.table::fread}, and +sets an attribute called \code{lb.date} with a date extracted +from the file name. +} +\details{ +The file name can be one with a valid ISO 8601 date (yyyy-mm-dd) +already in it, or it can be a file name with the date elided. + +For example, if there is a file you'd like to read on your disk +called "iris-2021-05-08.csv", you can call this function with +either "iris.csv" or "iris-2021-05-08.csv" as the file name. + +When you call this function with a file name without an ISO 8601 +date (e.g. "iris.csv.gz"), the file name extension ".csv.gz" is +removed and the function looks for a file name beginning with +"iris", a date, and the file extension. The file extension is +considered to be anything after the first period in the base name. +For example, if the file name given is "./my.data/iris.csv.gz", the +extension is ".csv.gz". This means no period can be present in +the base file name (after any directories) with the exception of +the file extension. + +If you call this function with "iris.csv" and there is no file name +with an ISO 8601 date appended to that file name on your disk, and +\code{allow.fallback.date} is \code{TRUE}, then the \code{lb.date} +attribute is set to the current date. +} +\examples{ +\dontrun{ + # there's a file called "iris-2021-05-08.csv" on disk + dat <- fread_plus_date("iris.csv") + attribute(dat)$lb.date + # [1] "2021-05-08 + + # can also read the full file name + dat <- fread_plus_date("iris-2021-05-08.csv") + attribute(dat)$lb.date + # [1] "2021-05-08 +} + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/fwrite_plus_date.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/fwrite_plus_date.Rd new file mode 100644 index 0000000..d160778 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/fwrite_plus_date.Rd @@ -0,0 +1,71 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/special-attributes.R +\name{fwrite_plus_date} +\alias{fwrite_plus_date} +\title{Write a file with a date appended to the file name.} +\usage{ +fwrite_plus_date( + DT, + fname, + from.attribute = TRUE, + allow.fallback.date = TRUE, + ... +) +} +\arguments{ +\item{DT}{a \code{data.table} to write to disk} + +\item{fname}{The file name to write the \code{data.table} to. The +date will be appended between the file name and its +file extension} + +\item{from.attribute}{A logical indicating whether the date should +be taken from the \code{lb.date} attribute of +the \code{data.table}, or whether it should be +today's date. Default (\code{TRUE}) takes it +from the \code{lb.date} attribute.} + +\item{allow.fallback.date}{A logical indicating, if there is no +\code{lb.date} attribute in the supplied +\code{data.table}, whether it is permissible +to use today's date, instead. +Default is \code{TRUE}.} + +\item{...}{Arbitrary arguments to pass to \code{fwrite}} +} +\description{ +Takes a \code{data.table}, a file name, and writes it with +\code{data.table::fwrite}. +} +\details{ +The supplied file name will be modified to include an ISO 8601 date +(yyyy-mm-dd) between the file name and the file extension. Under the +default settings, the date used will be from the \code{lb.date} +attribute of the supplied \code{data.table}. If there is no \code{lb.date} +attribute, the current date will be used, instead. + +For example, if there is a \code{data.table} with an \code{lb.date} +attribute of "2021-05-08", and you supply this function with the file +name "iris.csv", the file name actually written to disk will be +"iris-2021-05-08.csv". Under the default settings, if there is no +\code{lb.date} attribute, but today's date is "2038-01-19", the file +name written to disk will be "iris-2038-01-19.csv". + +The ISO 8601 date is sandwiched between the file name and the file +extension. The file extension is considered to be anything after the +first period in the base name. +For example, if the file name given is "./my.data/iris.csv.gz", the +extension is ".csv.gz". This means no period can be present in +the base file name (after any directories) with the exception of +the file extension. +} +\examples{ +\dontrun{ + +set_lb_date(iris, "2021-05-08") +fwrite_plus_date(iris, "iris.csv.gz") +# "iris-2021-05-08.csv.gz" is now written to disk + +} + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_all_lc_call_subject_letters.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_all_lc_call_subject_letters.Rd new file mode 100644 index 0000000..bc8c73d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_all_lc_call_subject_letters.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_all_lc_call_subject_letters} +\alias{get_all_lc_call_subject_letters} +\title{Get all subject letters of LC Call Number} +\usage{ +get_all_lc_call_subject_letters(x, allow.bare = FALSE) +} +\arguments{ +\item{x}{A Library of Congress call number (string)} + +\item{allow.bare}{A logical indicating whether an LC Call with only +the letters should be considered valid +(default is \code{FALSE})} +} +\value{ +Returns all the subject letters or NA if invalid +} +\description{ +Takes a string representation of a Library of Congress +call number and returns all the subject letters if and only if +the LC Call Number is valid +} +\examples{ + +get_all_lc_call_subject_letters("Q172.5.E77") +# Q +get_all_lc_call_subject_letters("AF172.5.E77") +# NA + +# vectorized +get_all_lc_call_subject_letters(c("Q 172.5", "AF172", "PR6023.A93")) +# Q NA PR + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_clean_names.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_clean_names.Rd new file mode 100644 index 0000000..ffc98f2 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_clean_names.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utilities.R +\name{get_clean_names} +\alias{get_clean_names} +\title{Takes a data.frame and returns cleaned column names} +\usage{ +get_clean_names(dat, lower = TRUE) +} +\arguments{ +\item{dat}{A data.frame} + +\item{lower}{A logical indicating whether all column names should be +made lower case (default \code{TRUE}).} +} +\value{ +Returns a vector of cleaned names +} +\description{ +This function takes a data.frame, extracts the column names, +and returns a vector of those column names but cleaned and +stripped of potentially troublesome names +} +\details{ +All space/whitespace characters are replaced with underscores, +as are all characters not from A-Z, a-z, an underscore, or a digit + +If there are duplicate column names after the cleaning, a message +will show stating such and the duplicate column names will be +make unique. +} +\examples{ +ejemplo <- iris +names(ejemplo) <- c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\\\nWidth", "SpĂȘcies") +# c("sepal_length" "sepal_width" "petallength" "petal_nwidth" "sp_cies") + +# c("Sepal_Length" "Sepal_Width" "PetalLength" "Petal_nWidth" "Sp_cies") + +} +\seealso{ +\code{\link{make.unique}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_country_from_code.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_country_from_code.Rd new file mode 100644 index 0000000..3bd850d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_country_from_code.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/other-code-translations.R +\name{get_country_from_code} +\alias{get_country_from_code} +\title{Conversion from country code to country name} +\usage{ +get_country_from_code(x) +} +\arguments{ +\item{x}{A country code (defined in the Marc standards) or a vector +of country codes} +} +\value{ +Returns the country (place) name. NA if cannot be matched + to country in standard. +} +\description{ +Takes a country code (defined in the Marc standards) +and returns the country name. +} +\details{ +Interestingly, although it's called 'country' in the Marc standard, +cities, states, and other non-countries also have codes +} +\examples{ + +get_country_from_code("ck") +# Colombia + +# tolerant of case and leading/trailing whitespace +get_country_from_code(c(" PE", "not-a-country", "nyu")) +# c("Peru", NA, "New York (State)") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_class.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_class.Rd new file mode 100644 index 0000000..4dc8c41 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_class.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_dewey_decimal_subject_class} +\alias{get_dewey_decimal_subject_class} +\title{Conversion from Dewey Decimal call numbers to first-level subject description} +\usage{ +get_dewey_decimal_subject_class(x) +} +\arguments{ +\item{x}{A Dewey Decimal call number} +} +\value{ +Returns the most general subject classification using the + hundreds places from the DDC. Returns NA if the DDC looks + invalid +} +\description{ +Takes a string representation of a Dewey Decimal +call number (DDC) and returns it's subject description. +This uses the hundreds place of the DDC number +and returns the most general subject classification. +} +\examples{ + +get_dewey_decimal_subject_class("709.05") # Arts + +get_dewey_decimal_subject_class("823.912") +# Literature (Belles-lettres) and rhetoric + +# vectorized +get_dewey_decimal_subject_class(c("709.05", "invalid", NA, "823.912")) +# c("Arts", NA, NA, "Literature (Belles-lettres) and rhetoric") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_division.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_division.Rd new file mode 100644 index 0000000..b15edab --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_division.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_dewey_decimal_subject_division} +\alias{get_dewey_decimal_subject_division} +\title{Conversion from Dewey Decimal call numbers to second-level subject description} +\usage{ +get_dewey_decimal_subject_division(x) +} +\arguments{ +\item{x}{A Dewey Decimal call number} +} +\value{ +Returns the most general subject classification using the + first two digits from the DDC. Returns NA if the DDC looks + invalid +} +\description{ +Takes a string representation of a Dewey Decimal +call number (DDC) and returns it's subject description. +This uses the first two digits of the DDC number +and returns the second most general subject classification. +} +\examples{ + +get_dewey_decimal_subject_division("709.05") # Arts + +get_dewey_decimal_subject_division("823.912") +# "English and Old English literatures" + +# vectorized +get_dewey_decimal_subject_division(c("709.05", "invalid", NA, "823.912")) +# c("Arts", NA, NA, "English and Old English literatures") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_section.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_section.Rd new file mode 100644 index 0000000..6828b38 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_dewey_decimal_subject_section.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_dewey_decimal_subject_section} +\alias{get_dewey_decimal_subject_section} +\title{Conversion from Dewey Decimal call numbers to third-level subject description} +\usage{ +get_dewey_decimal_subject_section(x) +} +\arguments{ +\item{x}{A Dewey Decimal call number} +} +\value{ +Returns the most general subject sectionification using the + first three digits from the DDC. Returns NA if the DDC looks + invalid +} +\description{ +Takes a string representation of a Dewey Decimal +call number (DDC) and returns it's subject description. +This uses the first three digits of the DDC number +and returns the third most general subject classification. +} +\examples{ + +get_dewey_decimal_subject_section("709.05") +# "History, geographic treatment, biography" + +get_dewey_decimal_subject_section("823.912") +# "English fiction" + +# vectorized +get_dewey_decimal_subject_section(c("709.05", "invalid", NA, "823.912")) +# c("History, geographic treatment, biography", NA, NA, +# "English fiction") + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_10_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_10_check_digit.Rd new file mode 100755 index 0000000..07d559f --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_10_check_digit.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{get_isbn_10_check_digit} +\alias{get_isbn_10_check_digit} +\title{Get ISBN 10 check digit} +\usage{ +get_isbn_10_check_digit(x, allow.hyphens = FALSE, errors.as.nas = FALSE) +} +\arguments{ +\item{x}{A string of 9 or 10 digits} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{FALSE})} + +\item{errors.as.nas}{return NA if error instead of throwing error +(default is \code{FALSE})} +} +\value{ +Returns the character check digit that satifies the + mod 11 condition. Returns "X" if 10. Returns NA if input is NA +} +\description{ +Takes a string representation of an ISBN 10 +and returns the check digit that satisfies the necessary condition. +It can take a 10 digit string (and ignore the already extant check digit) +or a 9 digit string (without the last digit) +} +\examples{ + +get_isbn_10_check_digit("012491540X") +get_isbn_10_check_digit("0-124-91540-X", allow.hyphens=TRUE) + +# nine digit string +get_isbn_10_check_digit("900403781") + +get_isbn_10_check_digit("onetwothre", errors.as.nas=TRUE) # NA + +# vectorized +get_isbn_10_check_digit(c("012491540X", "9004037810", "900403781")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_13_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_13_check_digit.Rd new file mode 100644 index 0000000..eacc640 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_isbn_13_check_digit.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{get_isbn_13_check_digit} +\alias{get_isbn_13_check_digit} +\title{Get ISBN 13 check digit} +\usage{ +get_isbn_13_check_digit(x, allow.hyphens = FALSE, errors.as.nas = FALSE) +} +\arguments{ +\item{x}{A string of 12 or 13 digits} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{FALSE})} + +\item{errors.as.nas}{return NA if error instead of throwing error +(default is \code{FALSE})} +} +\value{ +Returns the character check digit that satifies the + mod 10 condition. Returns NA if input is NA +} +\description{ +Takes a string representation of an ISBN 13 +and returns the check digit that satisfies the necessary condition. +It can take a 13 digit string (and ignore the already extant check digit) +or a 12 digit string (without the last digit) +} +\examples{ + +get_isbn_13_check_digit("9780306406157") + +# 12 digit string +get_isbn_13_check_digit("978030640615") + +get_isbn_13_check_digit("onetwothreefo", errors.as.nas=TRUE) # NA + +# vectorized +get_isbn_13_check_digit(c("9780306406157", "9783161484100")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_issn_check_digit.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_issn_check_digit.Rd new file mode 100644 index 0000000..6d900f1 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_issn_check_digit.Rd @@ -0,0 +1,41 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{get_issn_check_digit} +\alias{get_issn_check_digit} +\title{Get ISSN check digit} +\usage{ +get_issn_check_digit(x, allow.hyphens = FALSE, errors.as.nas = FALSE) +} +\arguments{ +\item{x}{A string of 7 or 8 digits} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{FALSE})} + +\item{errors.as.nas}{return NA if error instead of throwing error +(default is \code{FALSE})} +} +\value{ +Returns the character check digit that satifies the + mod 11 condition. Returns "X" if 10. Returns NA if input is NA +} +\description{ +Takes a string representation of an ISSN +and returns the check digit that satisfies the necessary condition. +It can take a 8 digit string (and ignore the already extant check digit) +or a 7 digit string (without the last digit) +} +\examples{ + +get_issn_check_digit("03785955") + +get_issn_check_digit("2434-561X", allow.hyphens=TRUE) + +# nine digit string +get_issn_check_digit("0378595") + +# vectorized +get_issn_check_digit(c("0378595", "2434561X", NA)) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_language_from_code.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_language_from_code.Rd new file mode 100644 index 0000000..44c71f3 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_language_from_code.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/other-code-translations.R +\name{get_language_from_code} +\alias{get_language_from_code} +\title{Conversion from language code to language name} +\usage{ +get_language_from_code(x) +} +\arguments{ +\item{x}{A language code (defined in the Marc standards) or a vector +of language codes} +} +\value{ +Returns the language name. NA if cannot be matched + to language in standard. +} +\description{ +Takes a language code (defined in the Marc standards) +and returns the language name. +} +\examples{ + +get_language_from_code("yor") +# Yoruba + +# tolerant of case and leading/trailing whitespace +get_language_from_code(c("yor", " SPA ", "not-a-language", "nah", NA)) +# c("Yoruba", "Spanish", NA, "Nahuatl", NA) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_first_letter.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_first_letter.Rd new file mode 100644 index 0000000..a3708cc --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_first_letter.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_lc_call_first_letter} +\alias{get_lc_call_first_letter} +\title{Get the first letter of LC Call Number} +\usage{ +get_lc_call_first_letter(x, allow.bare = FALSE) +} +\arguments{ +\item{x}{A Library of Congress call number (string)} + +\item{allow.bare}{A logical indicating whether an LC Call with only +the letters should be considered valid +(default is \code{FALSE})} +} +\value{ +Returns first letter or NA if invalid +} +\description{ +Takes a string representation of a Library of Congress +call number and returns the first letter if and only if +the LC Call Number is valid +} +\examples{ + +get_lc_call_first_letter("Q172.5.E77") +# Q +get_lc_call_first_letter("AF172.5.E77") +# NA + +# vectorized +get_lc_call_first_letter(c("Q 172.5", "AF172", "PR6023.A93")) +# Q NA P + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_subject_classification.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_subject_classification.Rd new file mode 100644 index 0000000..6129dde --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/get_lc_call_subject_classification.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{get_lc_call_subject_classification} +\alias{get_lc_call_subject_classification} +\title{Conversion from Library of Congress Call number to subject +classification} +\usage{ +get_lc_call_subject_classification( + x, + subclassification = FALSE, + already.parsed = FALSE, + allow.bare = TRUE +) +} +\arguments{ +\item{x}{A Library of Congress call number (string)} + +\item{subclassification}{A logical indicating whether the letters of +call number past the first should be used to match to +a subject subclassification (default is \code{FALSE})} + +\item{already.parsed}{Skips the extraction of the subject letters +and jumps to the subject matching (default is \code{FALSE})} + +\item{allow.bare}{A logical indicating whether an LC Call with only +the letters should be considered valid +(default is \code{TRUE})} +} +\value{ +Returns either the broad (top-level) subject classification + description or the second level subject subclassification + description. Returns "NA" if no subject could not be matched + or call number is invalid +} +\description{ +Takes a string representation of a Library of Congress +call number and returns either the broad subject +classification description (default) based on the first +letter, or a second-level subclassification +description based on the all the letters +} +\examples{ + +get_lc_call_subject_classification("ND 237.S18 $b S87 1997") +# Fine Arts + +get_lc_call_subject_classification("ND 237.S18 $b S87 1997", subclassification=TRUE) +# Painting + +get_lc_call_subject_classification("PQ2246.M3") +# Language and Literature + +get_lc_call_subject_classification("PQ2246.M3", + subclassification=TRUE) +# "French, Italian, Spanish, and Portuguese literature" + +get_lc_call_subject_classification("PQ2246.M3", already.parsed=TRUE) +# NA + +get_lc_call_subject_classification("PQ", already.parsed=TRUE, + subclassification=TRUE) +# "French, Italian, Spanish, and Portuguese literature" + +# vectorized +get_lc_call_subject_classification(c("ND 237", "\\\\\\\\$a ND 2", "PQ2246.M3"), + subclassification=TRUE) +# c("Painting", NA, "French, Italian, Spanish, and Portuguese literature") + + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_10.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_10.Rd new file mode 100644 index 0000000..1210618 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_10.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{is_valid_isbn_10} +\alias{is_valid_isbn_10} +\title{Return TRUE if valid ISBN 10} +\usage{ +is_valid_isbn_10(x, allow.hyphens = TRUE, lower.x.allowed = TRUE) +} +\arguments{ +\item{x}{A string of 10 digits or 9 digits with terminal "X"} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{TRUE})} + +\item{lower.x.allowed}{A logical indicating whether ISBN 10s with +a check digit with a lower-case "x" should +be treated as valid +(default is \code{TRUE})} +} +\value{ +Returns TRUE if checks pass, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISBN 10 verifies that it is valid. +An ISBN 10 is valid if it is a 10 digit string or a 9 digit string +with a terminal "X" AND the check digit matches +} +\examples{ + +is_valid_isbn_10("012491540X") # TRUE +is_valid_isbn_10("0-124-91540-X") # TRUE + +# vectorized +is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +is_valid_isbn_10(c("012491540X", "hubo un tiempo")) # TRUE FALSE + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_13.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_13.Rd new file mode 100644 index 0000000..74eaaf2 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_isbn_13.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{is_valid_isbn_13} +\alias{is_valid_isbn_13} +\title{Return TRUE if valid ISBN 13} +\usage{ +is_valid_isbn_13(x, allow.hyphens = TRUE) +} +\arguments{ +\item{x}{A string of 13} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{TRUE})} +} +\value{ +Returns TRUE if checks pass, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISBN 13 verifies that it is valid. +An ISBN 13 is valid if it is a 13 digit string and the check digit matches +} +\examples{ + +is_valid_isbn_13("9780306406157") # TRUE +is_valid_isbn_13("978-0-306-40615-7") # TRUE + +# vectorized +is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +is_valid_isbn_13(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE +is_valid_isbn_13(c("978-0-306-40615-7", "hubo un tiempo")) # TRUE FALSE + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_issn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_issn.Rd new file mode 100644 index 0000000..95a135c --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_issn.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{is_valid_issn} +\alias{is_valid_issn} +\title{Return TRUE if valid ISSN} +\usage{ +is_valid_issn(x, allow.hyphens = TRUE, lower.x.allowed = TRUE) +} +\arguments{ +\item{x}{A string of 8 digits or 7 digits with terminal "X"} + +\item{allow.hyphens}{A logical indicating whether the hyphen +separator should be allowed +(default is \code{TRUE})} + +\item{lower.x.allowed}{A logical indicating whether ISSNs with +a check digit with a lower-case "x" should +be treated as valid +(default is \code{TRUE})} +} +\value{ +Returns TRUE if checks pass, FALSE if not, and NA if NA +} +\description{ +Takes a string representation of an ISSN verifies that it is valid. +An ISSN is valid if it is a 8 digit string or a 7 digit string +with a terminal "X" AND the check digit matches +} +\examples{ + +is_valid_issn("2434561X") # TRUE +is_valid_issn("2434-561X") # TRUE + +# vectorized + +is_valid_issn(c("2434-561X", "2434-5611", "0378-5955", NA)) +# TRUE FALSE TRUE NA + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_lc_call.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_lc_call.Rd new file mode 100644 index 0000000..a1a01fb --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/is_valid_lc_call.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/call-numbers-and-subject.R +\name{is_valid_lc_call} +\alias{is_valid_lc_call} +\title{Check if LC Call Number is valid} +\usage{ +is_valid_lc_call(x, allow.bare = FALSE) +} +\arguments{ +\item{x}{A Library of Congress call number (string)} + +\item{allow.bare}{A logical indicating whether an LC Call with only +the letters should be considered valid +(default is \code{FALSE})} +} +\value{ +Returns either TRUE or FALSE based on whether the + call number is valid +} +\description{ +Takes a string representation of a Library of Congress +call number and returns either TRUE or FALSE based on +whether or not the input fits the canonical LC Call +Number pattern +} +\examples{ + +is_valid_lc_call("Q172.5.E77") +# TRUE +is_valid_lc_call("AF172.5.E77") +# FALSE + +# vectorized +is_valid_lc_call(c("Q 172.5", "AF172", "PR6023.A93")) +# TRUE FALSE TRUE + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/language_code_crosswalk.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/language_code_crosswalk.Rd new file mode 100644 index 0000000..c88645d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/language_code_crosswalk.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/language_code_crosswalk-data.R +\docType{data} +\name{language_code_crosswalk} +\alias{language_code_crosswalk} +\title{language code / language crosswalk} +\format{ +An object of class \code{"data.table"}; +} +\source{ +\url{https://www.loc.gov/marc/languages/language_code.html} +} +\usage{ +data(language_code_crosswalk) +} +\description{ +A cross-walk between the language code +and it's human readable version +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_classification.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_classification.Rd new file mode 100644 index 0000000..d31c3fd --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_classification.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lc_subject_classification-data.R +\docType{data} +\name{lc_subject_classification} +\alias{lc_subject_classification} +\title{LC Call Subject Code Classification / Classification name crosswalk} +\format{ +An object of class \code{"data.table"}; +} +\source{ +\url{https://www.loc.gov/catdir/cpso/lcco/} +} +\usage{ +data(lc_subject_classification) +} +\description{ +A cross-walk between the LC Subject classification and +and it's human readable name (first letter of LC Call Number) +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_subclassification.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_subclassification.Rd new file mode 100644 index 0000000..d8be5b1 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/lc_subject_subclassification.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lc_subject_subclassification-data.R +\docType{data} +\name{lc_subject_subclassification} +\alias{lc_subject_subclassification} +\title{LC Subject Subclassification / Subclassification name crosswalk} +\format{ +An object of class \code{"data.table"}; +} +\source{ +\url{https://www.loc.gov/catdir/cpso/lcco/} +} +\usage{ +data(lc_subject_subclassification) +} +\description{ +A cross-walk between the LC Subject subclassification and +and it's human readable name (all letters in an LC Call Number) +} +\keyword{datasets} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/loc_permalink_from_lccn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/loc_permalink_from_lccn.Rd new file mode 100644 index 0000000..ceebb91 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/loc_permalink_from_lccn.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/the-web.R +\name{loc_permalink_from_lccn} +\alias{loc_permalink_from_lccn} +\title{Get Library of Congress catalog permalinks from LCCNs} +\usage{ +loc_permalink_from_lccn(x, normalize = TRUE, format = "") +} +\arguments{ +\item{x}{A string (or vector of strings) of LCCNs} + +\item{normalize}{a logical indicating whether the LCCN should be +normalized prior to creating the permalink +(default is \code{TRUE})} + +\item{format}{One of "", "marcxml", "mods", "mads", or "dublin" to return +the link to the main permalink page, or the link directly +to the record's MARCXml, MODS, MADS, or Dublin Core +representation, respectively.} +} +\value{ +Library of Congress permalinks using LCCNs. +} +\description{ +Takes a string representation of an LCCNs. Returns permalinks +to the Library of Congress catalog entries using those LCCNs. +} +\details{ +If normalize=TRUE and the LCCN is invalid, the permalink is NA. +If normalize=FALSE, the permalink may be invalid. No validity +check on the URL is performed +} +\examples{ +loc_permalink_from_lccn("n78-890351") # "https://lccn.loc.gov/n78890351" +loc_permalink_from_lccn("85-2 ") # "https://lccn.loc.gov/85000002" +loc_permalink_from_lccn("75-425165//r75") # "https://lccn.loc.gov/75425165" + +# vectorized +loc_permalink_from_lccn(c("###78890351#", NA, "n78-890351")) + +# MARCXML metadata format +loc_permalink_from_lccn("73167510", format="marcxml") +# "https://lccn.loc.gov/73167510/marcxml" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/marc_008_get_info.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/marc_008_get_info.Rd new file mode 100644 index 0000000..0d7b3d7 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/marc_008_get_info.Rd @@ -0,0 +1,63 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/marc-field-deconstruction.R +\name{marc_008_get_info} +\alias{marc_008_get_info} +\title{Get info from MARC control field 008} +\usage{ +marc_008_get_info( + x, + original.pub.date = FALSE, + include.questionable.dates = FALSE +) +} +\arguments{ +\item{x}{A string (or vector of strings) of LCCNs} + +\item{original.pub.date}{If \code{TRUE} and if applicable, +return the original publication date, not +the re-issue publication date. (Default +is \code{FALSE})} + +\item{include.questionable.dates}{A logical indicating whether "questionable" +dates should be replaced with \code{NA}. +Questionable dates are when the "type of +date" in character position 06 is "q". +(default is \code{FALSE})} +} +\value{ +A \code{data.table} +} +\description{ +Takes one or more MARC 008 fields (string/strings) and returns a +\code{data.table} containing the publication date, publication +place code, and language code. +} +\details{ +If any date element is "unknown" (contains a "u"), the returned +date is NA. The returned date is always an integer. +} +\examples{ + +# reissue publication date +marc_008_get_info("950622r19701880ru 000 0 rus d") +# pub_date pub_place_code lang_code +# +# 1: 1970 ru rus + +# The Brothers Karamazov (1970 reissue but original publication date) +marc_008_get_info("950622r19701880ru 000 0 rus d", + original.pub.date=TRUE) +# pub_date pub_place_code lang_code +# +# 1: 1880 ru rus + +# vectorized +marc_008_get_info(c("101106s1992 gr 000 1 gre d", NA, + "180528s2017 ag 000 j spa d")) +# pub_date pub_place_code lang_code +# +# 1: 1992 gr gre +# 2: NA +# 3: 2017 ag spa + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/marc_leader_get_info.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/marc_leader_get_info.Rd new file mode 100644 index 0000000..f1fa29d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/marc_leader_get_info.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/marc-field-deconstruction.R +\name{marc_leader_get_info} +\alias{marc_leader_get_info} +\title{Get info from MARC leader} +\usage{ +marc_leader_get_info(x) +} +\arguments{ +\item{x}{A string (or vector of strings) of MARC leaders} +} +\value{ +A \code{data.table} +} +\description{ +Takes one or more MARC leaders (string/strings) and returns a +\code{data.table} containing the record type and bib level +} +\examples{ + +marc_leader_get_info("00000cam a22000008i 4500") +# record_type bib_level +# +# 1: Language Material Monograph/Item + +# vectorized +marc_leader_get_info(c("00000cam a2200000Ma 4500", NA, + "00000cem a2200000Ma 4500")) +# record_type bib_level +# +# 1: Language Material Monograph/Item +# 2: +# 3: Cartographic material Monograph/Item + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn.Rd new file mode 100644 index 0000000..5de584e --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn.Rd @@ -0,0 +1,54 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{normalize_isbn} +\alias{normalize_isbn} +\title{Attempt to enforce validity and canonical form to an ISBN} +\usage{ +normalize_isbn(x, aggressive = TRUE, convert.to.isbn.13 = FALSE) +} +\arguments{ +\item{x}{A string} + +\item{aggressive}{A logical indicating whether aggressive measures +should be taken to try to get the "ISBN 10" +into a valid form. See "Details" for more info +(default is \code{TRUE})} + +\item{convert.to.isbn.13}{A logical indicating whether the ISBN 10 +should be converted into an ISBN 13 +(default is \code{FALSE})} +} +\value{ +Returns valid ISBN if possible, NA if not +} +\description{ +Takes a string representation of an ISBN (10 or 13). This function uses +tries to normalize the string as a ISBN 13, then an ISBN 10. If one of +those methods are able to salvage the ISBN, the canonicalized ISBN is +returned. User can specify whether "aggressive" +measures should be taken to salvage the malformed ISBN string. +} +\details{ +If \code{aggressive} is TRUE, aggressive measures are taken to +try to salvage the malformed ISBN string. Since this function attempts +to salvage both an ISBN 10 and 13, to learn about examples of the +aggressive methods, see \code{\link{normalize_isbn_10}} and +\code{\link{normalize_isbn_13}} +} +\examples{ + +normalize_isbn("012491540x") # "012491540X" +normalize_isbn("012491540x", convert.to.isbn.13=TRUE) +"9780124915404" + +# vectorized +normalize_isbn(c("513213012491540x245", + "978966819^*!X7918", + NA, + "97815724115799781572411579")) +# "012491540X", "9789668197918", NA, "9781572411579" + +} +\seealso{ +\code{\link{normalize_isbn_10}} \code{\link{normalize_isbn_13}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_10.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_10.Rd new file mode 100644 index 0000000..9d935d7 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_10.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{normalize_isbn_10} +\alias{normalize_isbn_10} +\title{Attempt to enforce validity and canonical form to ISBN 10} +\usage{ +normalize_isbn_10(x, aggressive = TRUE, convert.to.isbn.13 = FALSE) +} +\arguments{ +\item{x}{A string} + +\item{aggressive}{A logical indicating whether aggressive measures +should be taken to try to get the "ISBN 10" +into a valid form. See "Details" for more info +(default is \code{TRUE})} + +\item{convert.to.isbn.13}{A logical indicating whether the ISBN 10 +should be converted into an ISBN 13 +(default is \code{FALSE})} +} +\value{ +Returns valid ISBN 10 if possible, NA if not +} +\description{ +Takes a string representation of an ISBN 10. Strips all non-digit +and non-"X" characters and checks if it is valid (whether the +check digit works out, etc). User can specify whether "aggressive" +measures should be taken to salvage the malformed ISBN 10 string. +} +\details{ +If \code{aggressive} is TRUE, aggressive measures are taken to +try to salvage the malformed ISBN 10 string. If the ISBN 10, for example, +is 9 digits, and either adding an "X" to the end, or leading "0"s fix it, +this function will return the salvaged ISBN 10. If the ISBN 10 has +garbage digits/characters in the front and has an "X" check digit, +it will return the salvaged ISBN 10. +} +\examples{ + +normalize_isbn_10("012491540x") # "012491540X" +normalize_isbn_10("012491540x xe32ea") # "012491540X" +normalize_isbn_10("012491540x", convert.to.isbn.13=TRUE) +# "9780124915404" +normalize_isbn_10("513213012491540x") # "012491540X" + +} +\seealso{ +\code{\link{normalize_isbn}} \code{\link{normalize_isbn_13}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_13.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_13.Rd new file mode 100644 index 0000000..defbe4d --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_isbn_13.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{normalize_isbn_13} +\alias{normalize_isbn_13} +\title{Attempt to enforce validity and canonical form to ISBN 13} +\usage{ +normalize_isbn_13(x, aggressive = TRUE) +} +\arguments{ +\item{x}{A string} + +\item{aggressive}{A logical indicating whether aggressive measures +should be taken to try to get the "ISBN 13" +into a valid form. See "Details" for more info +(default is \code{TRUE})} +} +\value{ +Returns valid ISBN 13 if possible, NA if not +} +\description{ +Takes a string representation of an ISBN 13. Strips all non-digit +characters and checks if it is valid (whether the +check digit works out, etc). User can specify whether "aggressive" +measures should be taken to salvage the malformed ISBN 13 string. +} +\details{ +If \code{aggressive} is TRUE, aggressive measures are taken to +try to salvage the malformed ISBN 13 string. If the ISBN 13, for example, +is more than 13 characters, this function will attempt to make a valid +ISBN 13 from the first 13 digits. +} +\examples{ + +normalize_isbn_13("978966819^*!X7918") # "9789668197918" + +# vectorized +normalize_isbn_13(c("978-9-66-819791-8", "__9__781572411579")) +# "9789668197918" "9781572411579" + +} +\seealso{ +\code{\link{normalize_isbn}} \code{\link{normalize_isbn_10}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/normalize_issn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_issn.Rd new file mode 100644 index 0000000..4a67a82 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_issn.Rd @@ -0,0 +1,55 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{normalize_issn} +\alias{normalize_issn} +\title{Attempt to enforce validity and canonical form to ISSN} +\usage{ +normalize_issn(x, aggressive = TRUE, pretty = FALSE) +} +\arguments{ +\item{x}{A string} + +\item{aggressive}{A logical indicating whether aggressive measures +should be taken to try to get the "ISSN" +into a valid form. See "Details" for more info +(default is \code{TRUE})} + +\item{pretty}{A logical indicating whether the ISSN should be +prettily hyphenated +(default is \code{FALSE})} +} +\value{ +Returns valid ISSN if possible, NA if not +} +\description{ +Takes a string representation of an ISSN. Strips all non-digit +and non-"X" characters and checks if it is valid (whether the +check digit works out, etc). User can specify whether "aggressive" +measures should be taken to salvage the malformed ISSN string. +} +\details{ +If \code{aggressive} is TRUE, aggressive measures are taken to +try to salvage the malformed ISSN string. If the ISSN, for example, +is 7 digits, and either adding an "X" to the end, or leading "0"s fix it, +this function will return the salvaged ISSN. If the ISSN has +garbage digits/characters in the front and has an "X" check digit, +it will return the salvaged ISSN. +} +\examples{ + +# adds leading zero +normalize_issn("3785955") # "03785955" + +# adds X to 7 digit ISSN if valid +normalize_issn("2434561") # "2434561X" + +normalize_issn("2434561", pretty=TRUE) # "2434-561X" + +# finds correct sequence +normalize_issn("21335212434561X") # "2434561X" + +# vectorized +normalize_issn(c("__2434__561X", "2434561", "21335212434561X")) +# "2434561X" "2434561X" "2434561X" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/normalize_lccn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_lccn.Rd new file mode 100644 index 0000000..96c4f08 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/normalize_lccn.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/bibcodes.R +\name{normalize_lccn} +\alias{normalize_lccn} +\title{Attempt to enforce validity of LCCN and convert to normalized form} +\usage{ +normalize_lccn(userlccns, allow.hyphens = TRUE) +} +\arguments{ +\item{userlccns}{A string (or vector of strings) of LCCNs} + +\item{allow.hyphens}{a logical indicating whether hyphens separating +the year and serial should be handled. Adds +complexity and time to the function. +(default is \code{TRUE})} +} +\value{ +Returns valid LCCN if possible, NA if not +} +\description{ +Takes a string representation of an LCCN. Returns a normalized one +} +\details{ +Normalization procedure is documented here: +https://www.loc.gov/marc/lccn-namespace.html + +This does not include revisions or use "#" as a padding character +The normalized LCCN is not always the same number of characters +} +\examples{ + +normalize_lccn("n 78890351 ") # "n78890351" + +normalize_lccn("###78890351#") # "78890351" + +normalize_lccn(" 79139101 /AC/r932") # "79139101" + +normalize_lccn("85-2 ") # "85000002" +normalize_lccn("85-2 ", allow.hyphens=FALSE) # NA + +# vectorized +normalize_lccn(c("85-2 ", " 79139101 /AC/r932", "n 78890351 ")) +# c("85000002", "79139101", "n78890351")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/oclc_classify_link_from_standard_num.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/oclc_classify_link_from_standard_num.Rd new file mode 100644 index 0000000..5f9bfde --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/oclc_classify_link_from_standard_num.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/the-web.R +\name{oclc_classify_link_from_standard_num} +\alias{oclc_classify_link_from_standard_num} +\title{Get OCLC Classify link from a standard number} +\usage{ +oclc_classify_link_from_standard_num(x) +} +\arguments{ +\item{x}{A string (or vector of strings) of a standard number. +Must be an ISSN, ISBN, UPC, and/or OCLC numbers.} +} +\value{ +Links to OCLC's Classify web service +} +\description{ +Takes a string representation of ISSNs, ISBNs, UPC, +or OCLC numbers. +Returns a link to the OCLC's experimental classify +service which provides the most frequent call numbers, +FAST subject headings, etc... +} +\details{ +Since this can take a variety of standard numbers, no +normalization can be performed. The numbers much be normalized +before the call to this function. +No validity check on the URL is performed +} +\examples{ + +oclc_classify_link_from_standard_num("629725006") +# "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" + +oclc_classify_link_from_standard_num(c("039333712X", NA, "629725006")) +# [1] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=039333712X&startRec=0" +# [2] NA +# [3] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/recombine_with_sep_closure.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/recombine_with_sep_closure.Rd new file mode 100644 index 0000000..ea20c69 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/recombine_with_sep_closure.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/split-map-filter-reduce.R +\name{recombine_with_sep_closure} +\alias{recombine_with_sep_closure} +\title{Return a function that will combine/contatenate a vector} +\usage{ +recombine_with_sep_closure(sep = ";") +} +\arguments{ +\item{sep}{A character to use in between the elements +(default is a semicolon character)} +} +\value{ +Returns a closure/function +} +\description{ +This function takes and optional separator, and returns +a function that takes a vector and \code{paste}s the +elements of that vector together +} +\details{ +Can be used as a reduction function in \code{split_map_filter_reduce} +} +\examples{ + +lambda <- recombine_with_sep_closure() +lambda(c(8, 6, 7)) # "8;6;7" + +# directly +recombine_with_sep_closure()(c(8,6,7)) # "8;6;7" +lambda <- recombine_with_sep_closure(" ") +lambda(c("this", "that", NA,"the-other")) # "this that NA the-other" + +} +\seealso{ +\code{\link{split_map_filter_reduce}} + +\code{\link{paste}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/remove_duplicates_and_nas.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/remove_duplicates_and_nas.Rd new file mode 100644 index 0000000..f62d451 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/remove_duplicates_and_nas.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/split-map-filter-reduce.R +\name{remove_duplicates_and_nas} +\alias{remove_duplicates_and_nas} +\title{Remove duplicate elements and NAs from a vector} +\usage{ +remove_duplicates_and_nas(x) +} +\arguments{ +\item{x}{A vector} +} +\value{ +Returns vector with duplicates and NAs removed +} +\description{ +Takes a vector and returns the same vector without duplicate +elements and without NA values +} +\details{ +Can be used as a filtering function in \code{split_map_filter_reduce} +} +\examples{ + +remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) +# 8 6 7 5 3 0 9 + +remove_duplicates_and_nas(c(NA, NA)) +# NA + +} +\seealso{ +\code{\link{split_map_filter_reduce}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_attribute.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_attribute.Rd new file mode 100644 index 0000000..e8d1dc5 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_attribute.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/special-attributes.R +\name{set_lb_attribute} +\alias{set_lb_attribute} +\title{Set special libbib attribute on object} +\usage{ +set_lb_attribute(x, type, value) +} +\arguments{ +\item{x}{An object to set the attribute on} + +\item{type}{The name of the attribute to set. \code{lb.} will be appended +to this attribute name. For example, if this argument is +\code{source}, and attribute called \code{lb.source} will +be set on the object with the value specified} + +\item{value}{The value of the attribute} +} +\value{ +Nothing, since the object is modified by reference. +} +\description{ +Takes an object, attribute name, and a value and sets a special +libbib attribute by reference +} +\examples{ +set_lb_attribute(mtcars, "source", "R built-in dataset") + +versicolor <- iris[iris$Species=="versicolor", ] +set_lb_attribute(versicolor, "note", "modified built-in dataset") +attributes(versicolor)$lb.note +# [1] "modified built-in dataset" + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_date.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_date.Rd new file mode 100644 index 0000000..f638c85 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/set_lb_date.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/special-attributes.R +\name{set_lb_date} +\alias{set_lb_date} +\title{Set special libbib date attribute on object} +\usage{ +set_lb_date(x, value) +} +\arguments{ +\item{x}{An object to set the attribute on} + +\item{value}{Either a value of class \code{Date} or a string in ISO 8601 +date format (yyyy-mm-dd) which will be converted into a Date} +} +\value{ +Nothing, since the object is modified by reference. +} +\description{ +Takes an object and a date and sets a special attribute, "lb.date" +by reference +} +\examples{ +set_lb_date(mtcars, "2021-05-08") +attributes(mtcars)$lb.date +# [1] "2021-05-08 + +set_lb_date(mtcars, Sys.Date()) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/split_map_filter_reduce.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/split_map_filter_reduce.Rd new file mode 100644 index 0000000..9c4c583 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/split_map_filter_reduce.Rd @@ -0,0 +1,111 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/split-map-filter-reduce.R +\name{split_map_filter_reduce} +\alias{split_map_filter_reduce} +\title{Split, Map, Filter, and Reduce a string vector} +\usage{ +split_map_filter_reduce( + x, + sep = ";", + fixed = TRUE, + mapfun = identity, + filterfun = identity, + reduxfun = car, + cl = 0 +) +} +\arguments{ +\item{x}{A vector of strings} + +\item{sep}{A character to use containing a character, string, or +regular expression pattern to split each element by. +If \code{fixed=TRUE}, the separator will be used exactly; +If not, a Perl-compatible regular expression can be used +(default is ";")} + +\item{fixed}{Should it be split by a fixed string/character or +a regular expression (default is \code{TRUE})} + +\item{mapfun}{A vectorized function that will be applied to the +sub-elements (after splitting) of each element in x +(default is \code{identity} which would leave the +sub-elements unchanged)} + +\item{filterfun}{A vectorized function that, when given a vector +returns the same vector with un-wanted elements +removed +(default is \code{identity} which would not remove +any sub-elements)} + +\item{reduxfun}{A vectorized function that, when given a vector, +will combine all of it's elements into one value +(default is \code{car}, which would return the first +element only)} + +\item{cl}{An integer to indicate the number of child processes +should be used to parallelize the work-load. If 0, +the workload will not be parallelized. Can also +take a cluster object created by 'makeCluster' +(default is 0)} +} +\value{ +Returns a vector +} +\description{ +This function takes a vector of strings, splits those strings +on a particular character; string; or regex pattern, applies a +user-specified function to each sub-element of the now split element, +filters those sub-elements using a user-specified function, and, finally, +recombines each element's sub-elements using a user specified reduction +function. +} +\details{ +Since this operation cannot be vectorized, if the user specifies +a non-zero \code{cl} argument, the workload will be parallelized +and \code{cl} many child processes will be spawned to do the work. +The package \code{pbapply} will be used to do this. + +See \code{examples} for more information and ideas on why this +might be useful for, as an example, batch normalizing ISBNs that, +for each bibliographic record, is separated by a semicolon +} +\examples{ + +someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952; 978-1-86189-795-4") + +# will return only the first ISBN for each record +split_map_filter_reduce(someisbns) +# "9782711875177" "1861897952" + +# will return only the first ISBN for each record, after normalizing +# each ISBN +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}) +# "9782711875177" "9781861897954" + +# will return all ISBNs, for each record, separated by a semicolon +# after applying normalize_isbn to each ISBN +# note the duplicates introduced after normalization occurs +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + reduxfun=recombine_with_sep_closure()) +# "9782711875177;NA;9782711875177;9782844268907" "9781861897954;9781861897954" + +# After splitting each items ISBN list by semicolon, this runs +# normalize_isbn in each of them. Duplicates are produced when +# an ISBN 10 converts to an ISBN 13 that is already in the ISBN +# list for the item. NAs are produced when an ISBN fails to normalize. +# Then, all duplicates and NAs are removed. Finally, the remaining +# ISBNs, for each record, are pasted together using a space as a separator +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + filterfun=remove_duplicates_and_nas, + reduxfun=recombine_with_sep_closure(" ")) +# "9782711875177 9782844268907" "9781861897954" + +} +\seealso{ +\code{\link{car}} + +\code{\link{remove_duplicates_and_nas}} + +\code{\link{recombine_with_sep_closure}} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_bib_read_info_by.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_bib_read_info_by.Rd new file mode 100644 index 0000000..4a0dc28 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_bib_read_info_by.Rd @@ -0,0 +1,110 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/worldcat-api.R +\name{worldcat_api_bib_read_info_by} +\alias{worldcat_api_bib_read_info_by} +\alias{worldcat_api_bib_read_info_by_oclc} +\alias{worldcat_api_bib_read_info_by_isbn} +\alias{worldcat_api_bib_read_info_by_issn} +\title{Get bibliographic info from a standard number} +\usage{ +worldcat_api_bib_read_info_by_oclc( + x, + wskey = getOption("libbib.wskey", NULL), + more = FALSE, + debug = FALSE +) + +worldcat_api_bib_read_info_by_isbn( + x, + wskey = getOption("libbib.wskey", NULL), + more = FALSE, + debug = FALSE +) + +worldcat_api_bib_read_info_by_issn( + x, + wskey = getOption("libbib.wskey", NULL), + more = FALSE, + debug = FALSE +) +} +\arguments{ +\item{x}{A string representation of the standard number that the function +chosen accepts.} + +\item{wskey}{A WorldCat API key (default is \code{getOption("libbib.wskey")})} + +\item{more}{A logical indicating whether more infomation from the MARCXML +should be returned (publisher, bib level etc....) In the +interest of memory consumption, the default is \code{FALSE}} + +\item{debug}{A logical indicating whether the HTTP and bib read API +responses should be printed (for debugging) +(default is \code{FALSE})} +} +\value{ +A \code{data.table} containing the OCLC number, ISBN, ISSN, + title, author, MARC leader, and the 008 control field, + respectively, +} +\description{ +Access the results of a WorldCat bib read API search by ISBN, ISSN, +or OCLC number. The MARCXML returned by the API is parsed and the +function returns a \code{data.table} containing the oclc number, +ISBN, ISSN, title, author, MARC leader, and the 008 control field, +respectively. +} +\details{ +Though this function gets all standard numbers (OCLC, ISBN, ISSN) +from the MARCXML, the standard number that was supplied to the function +will be the one in the returned \code{data.table}. For example, if +you use \code{worldcat_api_bib_read_info_by_isbn}, the returned +\code{data.table} will have that ISBN in the ISBN column, not the +ISBN in the MARC record. + +If something went wrong, all columns (except the one corresponding to +the supplied standard number) will be NA. + +This function is helpful to call before attempting to use +the Location and Classify API functions as it will ensure that +the supplied standard number actually resolves to a OCLC work. + +As with all API access functions in this package, it's up to the +user to limit their API usage so as to not get blocked. These +functions are deliberately not vectorized for this reason; they +only accept one standard number at a time. + +This (and other) WorldCat API communication functions require a +WorldCat API key. The easiest way to use these functions is to +set a global options with your key: +\code{options("libbib.wskey"="YOUR KEY HERE")} + +Final note: all of these API functions seem to work better with +OCLC numbers than any other standard number. If multiple standard +numbers are available, using the OCLC number is always preferred. +} +\examples{ + +\dontrun{ +worldcat_api_bib_read_info_by_isbn("9780984201006") +# oclc isbn issn title +# +# 1: 462894360 9780984201006 The Great Debate about Art / +# author leader +# +# 1: Harris, Roy, 00000cam a2200000 a 4500 +# oh08 +# +# 1: 091031s2010 ilua b 000 0 eng c + +worldcat_api_bib_read_info_by_issn("13602365") +# oclc isbn issn title author +# +# 1: 37787277 14664410 The journal of architecture. +# leader oh08 +# +# 1: 00000cas a2200000 a 4500 971015c19969999enkbx pso 0 a0eng c + +} + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_classify_by.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_classify_by.Rd new file mode 100644 index 0000000..e598729 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_classify_by.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/worldcat-api.R +\name{worldcat_api_classify_by} +\alias{worldcat_api_classify_by} +\alias{worldcat_api_classify_by_oclc} +\alias{worldcat_api_classify_by_isbn} +\alias{worldcat_api_classify_by_issn} +\title{Search WorldCat classify API by ISBN, ISSN, or OCLC number} +\usage{ +worldcat_api_classify_by_oclc(x, debug = FALSE) + +worldcat_api_classify_by_isbn(x, debug = FALSE) + +worldcat_api_classify_by_issn(x, debug = FALSE) +} +\arguments{ +\item{x}{A string representation of the standard number that the function +chosen accepts.} + +\item{debug}{A logical indicating whether the HTTP and classify API +responses should be printed (for debugging) +(default is \code{FALSE})} +} +\value{ +A \code{data.table} with most popular DDC and LCC call numbers + and various other metadata. See "Details" for more information. +} +\description{ +Access the results of a WorldCat classify API search by ISBN, ISSN, +or OCLC number to get the most frequent call numbers (DDC and LCC) +associated with a work. Returns a \code{data.table} with those call +numbers and various other metadata. See "Details" for more information. +} +\details{ +The returned \code{data.table} contains fields for various pieces of +metadata returned by the API request. These fields include the +ISBN/ISSN/OCLC number used, title of work, author, total number of +holdings, total number of electronic holdings, call number type, +call number recommendation (by most popular), number of holdings +using that call number, the HTTP status code, and the Classify +API response code. + +For each ISBN/ISSN/OCLC number used, two rows will be returned; one for +the DDC and one for the LCC. Common information (work metadata) +will the the same in both rows. If one of the call numbers is missing, +the recommendation and holdings fields will be NA. + +The API can be persnickety, and there are many things that can go +wrong. For example, the API can respond with multiple works for a +single standard number (ISBN 9780900565748, for example). If this happens, +no attempt is made to follow one of the results, and the returned +\code{data.table} will return no useful information. + +If the \code{http_status_code} is 200 and the \code{classify_response_code} +is 0, you've received good results.If the \code{classify_response_code} is +4, the standard number may have returned multiple works. + +The \code{http_status_code} should never not be 200. + +If something went wrong (for example, the status/response codes are not +200 and 0, respectively), you may want to re-run the function call with +\code{print.api.responses} set to \code{TRUE}. This will print the +HTTP status code and the raw XML text response from the API. + +As with all API access functions in this package, it's up to the +user to limit their API usage so as to not get blocked. These +functions are deliberately not vectorized for this reason; they +only accept one standard number at a time. + +Final note: all of these API functions seem to work better with +OCLC numbers than any other standard number. If multiple standard +numbers are available, using the OCLC number is always preferred. +} +\examples{ + +\dontrun{ + worldcat_api_classify_by_oclc("93976650") + # oclc title author total_holdings total_eholdings call_type + # + # 1: 939766505 Lobster King, Richard J. 244 534 DDC + # 2: 939766505 Lobster King, Richard J. 244 534 LCC + # recommendation holdings http_status_code classify_response_code + # + # 1: 641.395 767 200 0 + # 2: QL444.M33 318 200 0 + +} + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_locations_by.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_locations_by.Rd new file mode 100644 index 0000000..7f29a82 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_locations_by.Rd @@ -0,0 +1,175 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/worldcat-api.R +\name{worldcat_api_locations_by} +\alias{worldcat_api_locations_by} +\alias{worldcat_api_locations_by_oclc} +\alias{worldcat_api_locations_by_isbn} +\alias{worldcat_api_locations_by_issn} +\title{Get holding libraries by standard number} +\usage{ +worldcat_api_locations_by_oclc( + x, + location = "10032", + include.bib.info = TRUE, + max_libraries = Inf, + servicelevel = "full", + frbrGrouping = "on", + libtype = NULL, + wskey = getOption("libbib.wskey", NULL), + print.progress = TRUE, + debug = FALSE +) + +worldcat_api_locations_by_isbn( + x, + location = "10032", + include.bib.info = TRUE, + max_libraries = Inf, + servicelevel = "full", + frbrGrouping = "on", + libtype = NULL, + wskey = getOption("libbib.wskey", NULL), + print.progress = TRUE, + debug = FALSE +) + +worldcat_api_locations_by_issn( + x, + location = "10032", + include.bib.info = TRUE, + max_libraries = Inf, + servicelevel = "full", + frbrGrouping = "on", + libtype = NULL, + wskey = getOption("libbib.wskey", NULL), + print.progress = TRUE, + debug = FALSE +) +} +\arguments{ +\item{x}{The standard number to search using. Must be a string.} + +\item{location}{The holding institutions are sorted roughly by geographic +proximity to this zip-code, country code, etc... +If \code{max_libraries} is \code{Inf} (the default), the +starting location doesn't matter since all holding +institutions are returned. Defaults to the zip code +of Washington Heights, NYC.} + +\item{include.bib.info}{A logical indicating whether to include +bibliographic metadata associated with the +work (provided by +\code{worldcat_api_bib_read_info_by_...}). +This is very useful for error checking so +default is \code{TRUE}.} + +\item{max_libraries}{The maximum number of libraries to return. +Must be a number between 0 and 100 or \code{Inf}. +If \code{Inf} (default), the function will +automatically make all follow-up requests to retrieve +all holding institutions. Beware that each page of +100 institutions counts as one API request. If the +bib searched for is popular, set this to non-\code{Inf}.} + +\item{servicelevel}{Either "full" (the default) or "default". If "full", +the number of holding libraries returned is the same +as if a user logged in to an institution when making +a WorldCat search. If "default", the results are +a subset of WorldCat libraries, namely those that +participate in worldcat.org. In this way, the number +of holding libraries is tantamount to if a non-logged-in +user searched WorldCat. The number of results with "full" +is always at least as high as with "default", so the +default is "full". If this package is being used in +an application where a user is not logged in to an +institution, set this to "default". It is up to you +to respect the WorldCat API's conditions.} + +\item{frbrGrouping}{With this parameter set to "on" (default), +an attempt is made by the WorldCat API to group +together similar editions and present only the top +held record as the representative record for that group. +If not, only institutions holding the exact standard +number specified will be returned.} + +\item{libtype}{One of \code{NULL} (default), "academic", "public", +"government", or "other". \code{NULL} will return all +library subsets. The others will only search for holdings +from insitutions of that library type.} + +\item{wskey}{A WorldCat API key (default is \code{getOption("libbib.wskey")})} + +\item{print.progress}{A logical indicating whether a message should be +displayed for each API request. If \code{max_libraries} +is \code{TRUE} a message will be displayed for every +group of 100 institutions the function fetches. +(default is \code{TRUE})} + +\item{debug}{A logical indicating whether the HTTP and API +responses should be printed (for debugging) +(default is \code{FALSE})} +} +\value{ +A \code{data.table} with each row corresponding to a holding library. +} +\description{ +Access the results of a WorldCat location API search by ISBN, ISSN, +or OCLC number. Returns a \code{data.table} with rows corresponding to +each holding institution. The columns contain the standard number +provided, the institution identifier, the institution name, number +of copies held by that insitution, and, by default, the bibliographic +information provided by \code{worldcat_api_bib_read_info_by_...}. +This information is helpful to ensure thaat the standard number +provided successfully resolved to a single OCLC work. +} +\details{ +Numerous parameters are provided that change the API url +parameters. See parameter section for details on each. + + +If something went wrong, most columns (especially the bibliographic +info columns) will be NA. You should always check the output. + +As with all API access functions in this package, it's up to the +user to limit their API usage so as to not get blocked. These +functions are deliberately not vectorized for this reason; they +only accept one standard number at a time. + +This (and other) WorldCat API communication functions require a +WorldCat API key. The easiest way to use these functions is to +set a global options with your key: +\code{options("libbib.wskey"="YOUR KEY HERE")} + +Final note: all of these API functions seem to work better with +OCLC numbers than any other standard number. If multiple standard +numbers are available, using the OCLC number is always preferred. +In this function, for example, searching for ISSN: 14664410 +(Journal of Architecture) will (at time of writing) return only one +insitution, whereas searching by it's OCLC number (958283020) will +yield many more (660, at time of writing, with default parameters). +} +\examples{ + +\dontrun{ +# worldcat_api_locations_by_oclc("877749545", max_libraries=10, +# include.bib.info=FALSE) +# oclc institution_identifier +# +# 1: 877749545 NLE +# 2: 877749545 NLW +# 3: 877749545 EUM +# 4: 877749545 LTU +# 5: 877749545 ELU +# 6: 877749545 UKUAL +# institution_name copies +# +# 1: National Library of Scotland 1 +# 2: National Library of Wales 1 +# 3: University of Manchester Library 1 +# 4: University of Leicester, David Wilson Library 1 +# 5: University of London Senate House Library 1 +# 6: University of the Arts London 1 + +} + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_search.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_search.Rd new file mode 100644 index 0000000..69c8b35 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_api_search.Rd @@ -0,0 +1,132 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/worldcat-api.R +\name{worldcat_api_search} +\alias{worldcat_api_search} +\title{Use the WorldCat Search API} +\usage{ +worldcat_api_search( + sru, + max_records = 10, + sru_query_assist = getOption("libbib.sru_query_assist", TRUE), + frbrGrouping = "on", + start_at = 1, + wskey = getOption("libbib.wskey", NULL), + more = TRUE, + print.progress = TRUE, + debug = FALSE +) +} +\arguments{ +\item{sru}{The search query (in CQL syntax). See \code{examples} section +for some examples.} + +\item{max_records}{The maximum number of search results to return. +Must be a number between 0 and 100 or \code{Inf}. +If \code{Inf}, the function will +automatically make all follow-up requests to retrieve +all search results. For safety, the default is 10.} + +\item{sru_query_assist}{A logical indicating whether translation from +more human-readable aliases to the SRU search +index codes should be allowed. See details for +more information. (default is \code{TRUE}). You +can control this parameter globally by setting +\code{options("libbib.sru_query_assist")}.} + +\item{frbrGrouping}{With this parameter set to "on" (default), +an attempt is made by the WorldCat API to group +together similar editions and present only the top +held record as the representative record for that group.} + +\item{start_at}{The search result to start at (default is 1)} + +\item{wskey}{A WorldCat API key (default is \code{getOption("libbib.wskey")})} + +\item{more}{A logical indicating whether more information from the MARCXML +search results should be returned (publisher, bib level, etc....). +(Default is \code{TRUE})} + +\item{print.progress}{A logical indicating whether a message should be +displayed for each API request. If \code{max_records} +is \code{Inf} a message will be displayed for every +group of 100 search results the function fetches. +(default is \code{TRUE})} + +\item{debug}{A logical indicating whether the HTTP and API +responses should be printed (for debugging) +(default is \code{FALSE})} +} +\value{ +A \code{data.table} containing the bibliographic metadata of the + results, along with the total number of results. +} +\description{ +Searches WorldCat using a CQL query. Returns a \code{data.table} +containing the bibliographic metadata of the results, along +with the total number of results. +} +\details{ +There is an entire vignette dedicated to this function; to view it, +execute \code{vignette("using-the-worldcat-search-api")} + + + +By default, this function allows for the usage of more human-readable +aliases to the arcane SRU search index codes. This allows you, for +example, to search using "$title" instead of "srw.ti". This behavior is +controlled using the `sru_query_assist` parameter. If it is \code{TRUE} +(the default) you can still use the formal search index codes. See +\code{vignette("using-the-worldcat-search-api")} for more information. + +As with all API access functions in this package, it's up to the +user to limit their API usage so as to not get blocked. These +functions are deliberately not vectorized for this reason; they +only accept one standard number at a time. + +This (and other) WorldCat API communication functions require a +WorldCat API key. The easiest way to use these functions is to +set a global options with your key: +\code{options("libbib.wskey"="YOUR KEY HERE")} +} +\examples{ + +\dontrun{ + +# A title search for "The Brothers Karamazov" +worldcat_api_search('$title = "Brothers Karamazov"') + +# An exact title search for "The Brothers Karamazov" +worldcat_api_search('$title exact "Brothers Karamazov"') + +# Search for title "Madame Bovary" by author "Gustave Flaubert" +# in language Greek (all results) +# (queries may span multiple lines) +sru <- '$author = "Gustave Flaubert" and $title="Madame Bovary" + and $language=greek' +worldcat_api_search(sru, max_records=Inf) + +# Hip Hop (subject) materials on Cassette, CD, or wax from years 1987 to 1990 +sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) + and $subject="Rap") and $year="1987-1990"' +worldcat_api_search(sru) + +# all materials with keyword "Common Lisp" at The New York Public Library +sru <- '$keyword="common lisp" and $holding_library=NYP' +worldcat_api_search(sru, max_records=Inf) + +# 19th century materials on ethics (Dewey code 170s / LC Call prefix BJ) +sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*"' +worldcat_api_search(sru, max_records=Inf) + +# Music (Dewey 780s) materials that are only held by The New York Public +# Library (a "cg" code of 11 means there is only one holding) +# [searching with debugging] +sru <- '$dewey="78*" and $holding_library=NYP + and $library_holdings_group=11' +worldcat_api_search(sru, debug=TRUE) + +Keyword search for "danger music" from year 2010 to present +worldcat_api_search('$keyword="danger music" and $year="2010-"') + +} +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_isbn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_isbn.Rd new file mode 100644 index 0000000..4a19bf1 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_isbn.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/the-web.R +\name{worldcat_permalink_from_isbn} +\alias{worldcat_permalink_from_isbn} +\title{Get WorldCat catalog permalinks from ISBNs} +\usage{ +worldcat_permalink_from_isbn(x, normalize = TRUE) +} +\arguments{ +\item{x}{A string (or vector of strings) of ISBNs} + +\item{normalize}{a logical indicating whether the ISBNs should be +normalized prior to creating the permalink +(default is \code{TRUE})} +} +\value{ +Worldcat permalinks using ISBNs. +} +\description{ +Takes a string representation of ISBNs. Returns permalinks +to the WorldCat catalog entries using those ISBNs. +} +\details{ +If normalize=TRUE and the ISBN is invalid, the permalink is NA. +If normalize=FALSE, the permalink may be invalid. No validity +check on the URL is performed +} +\examples{ + +worldcat_permalink_from_isbn("1788393724") +# http://www.worldcat.org/isbn/1788393724 + +worldcat_permalink_from_isbn("0-124-91540-X") +# http://www.worldcat.org/isbn/012491540X + +worldcat_permalink_from_isbn("0-124-91540-X", normalize=FALSE) +# http://www.worldcat.org/isbn/0-124-91540-X + +# vectorized +worldcat_permalink_from_isbn(c("1788393724", NA, "0-124-91540-X")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_issn.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_issn.Rd new file mode 100644 index 0000000..c6e4a4f --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_issn.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/the-web.R +\name{worldcat_permalink_from_issn} +\alias{worldcat_permalink_from_issn} +\title{Get WorldCat catalog permalinks from ISSNs} +\usage{ +worldcat_permalink_from_issn(x, normalize = TRUE) +} +\arguments{ +\item{x}{A string (or vector of strings) of ISSNs} + +\item{normalize}{a logical indicating whether the ISSNs should be +normalized prior to creating the permalink +(default is \code{TRUE})} +} +\value{ +Worldcat permalinks using ISSNs. +} +\description{ +Takes a string representation of ISSNs. Returns permalinks +to the WorldCat catalog entries using those ISSNs. +} +\details{ +If normalize=TRUE and the ISSN is invalid, the permalink is NA. +If normalize=FALSE, the permalink may be invalid. No validity +check on the URL is performed +} +\examples{ +worldcat_permalink_from_issn("0968-1221") # http://www.worldcat.org/issn/0968-1221 + +worldcat_permalink_from_issn("2434-561X") # http://www.worldcat.org/issn/2434561X + +# vectorized +worldcat_permalink_from_issn(c("0968-1221", NA, "2434-561X")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_oclc_number.Rd b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_oclc_number.Rd new file mode 100644 index 0000000..8842a27 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/man/worldcat_permalink_from_oclc_number.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/the-web.R +\name{worldcat_permalink_from_oclc_number} +\alias{worldcat_permalink_from_oclc_number} +\title{Get WorldCat catalog permalinks from OCLC numbers} +\usage{ +worldcat_permalink_from_oclc_number(x) +} +\arguments{ +\item{x}{A string (or vector of strings) of OCLC numbers} +} +\value{ +Worldcat permalinks using the OCLC numbers +} +\description{ +Takes a string representation of OCLC numbers. Returns permalinks +to the WorldCat catalog entries using those OCLC numbers +} +\details{ +No validity check on the URL is performed +} +\examples{ + +worldcat_permalink_from_oclc_number("1005106045") +# http://www.worldcat.org/oclc/1005106045 + +# vectorized +worldcat_permalink_from_oclc_number(c("1049727704", NA, + "1005106045")) + +} diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat.R new file mode 100755 index 0000000..74b686b --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat.R @@ -0,0 +1,4 @@ +library(testthat) +library(libbib) + +test_check("libbib") diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-bibcodes.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-bibcodes.R new file mode 100755 index 0000000..a509307 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-bibcodes.R @@ -0,0 +1,422 @@ +context("checking functions in bibcodes.R") + + +############################################## +### SETUP ### +############################################## + +EX.valid.10.digit.isbns <- c("012491540X", "9004037810", "0256016054") +EX.invalid.10.digit.isbns <- c("0124915401", "9004037811", "0256016051", "0256X01605") +EX.9.digit.isbns <- c("012491540", "900403781", "025601605") + +EX.hairy.isbn.10s <- c("01249-^@^1540X", # has nonsense but good + "01249-^@^15402", # has nonsense and bad + "9004037810", # good + "898477250", # good if x added + "900403781", # too short and bad + "1249-^@^1540X", # good if leading 0 is added + "95700683539570068361", # good if divided in half + "95700683539570068361", # good if divided in half + NA, # NA (obviously) + "90040X3781", # no + "32132012491540X23464" # ok but hidden +) + +EX.valid.13.digit.isbns <- c("9780306406157", "9783161484100") +EX.12.digit.isbns <- c("978030640615", "978316148410") +EX.invalid.13.digit.isbns <- c("978316__84101", "9780306406151") + +EX.hairy.isbn.13s <- c("9789668197918", + "978966819^*@!)X7918", + NA, + "9770800783197708007912", + "97815724115799781572411579", + "", + "9789668197911") + + + +############################################## +### ISBN 10 ### +############################################## + +# get_isbn_10_check_digit succeeds properly +test_that("get_isbn_10_check_digit() succeeds properly", { + expect_equal(get_isbn_10_check_digit(EX.valid.10.digit.isbns[1]), "X") + expect_equal(get_isbn_10_check_digit(EX.valid.10.digit.isbns), c("X", "0", "4")) + expect_equal(get_isbn_10_check_digit(EX.9.digit.isbns), c("X", "0", "4")) + expect_equal(get_isbn_10_check_digit(c(EX.valid.10.digit.isbns, NA)), + c("X", "0", "4", NA)) + expect_equal(get_isbn_10_check_digit(EX.invalid.10.digit.isbns, errors.as.nas=TRUE), + c("X", "0", "4", NA)) + expect_equal(get_isbn_10_check_digit("0-124-91540-X", allow.hyphens=TRUE), "X") + expect_equal(get_isbn_10_check_digit(NA), as.character(NA)) +}) + +# get_isbn_10_check_digit fails properly +test_that("get_isbn_10_check_digit() fails properly", { + expect_error(get_isbn_10_check_digit(123456789), + "Input must be a character string") + expect_error(get_isbn_10_check_digit("123456"), + "Input must be either 9 or 10 characters") + expect_error(get_isbn_10_check_digit(EX.invalid.10.digit.isbns), + "Illegal input") +}) + + +# check_isbn_10_check_digit succeeds properly +test_that("check_isbn_10_check_digit() succeeds properly", { + expect_equal(check_isbn_10_check_digit(EX.valid.10.digit.isbns[1]), + TRUE) + expect_equal(check_isbn_10_check_digit(EX.valid.10.digit.isbns), + c(TRUE, TRUE, TRUE)) + expect_equal(check_isbn_10_check_digit(EX.invalid.10.digit.isbns), + c(FALSE, FALSE, FALSE, FALSE)) + expect_equal(check_isbn_10_check_digit(c(EX.valid.10.digit.isbns, + EX.invalid.10.digit.isbns)), + c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE)) + expect_equal(check_isbn_10_check_digit(c(12, 12), errors.as.false = TRUE), + c(FALSE, FALSE)) + expect_equal(check_isbn_10_check_digit(c(EX.valid.10.digit.isbns, + "hubo un tiempo"), + errors.as.false = TRUE), + c(TRUE, TRUE, TRUE, FALSE)) + expect_equal(check_isbn_10_check_digit("0-124-91540-X"), TRUE) + expect_equal(check_isbn_10_check_digit("0-124-91540-X", allow.hyphens=FALSE), + FALSE) + expect_equal(check_isbn_10_check_digit(NA, errors.as.false = FALSE), as.character(NA)) +}) + +# check_isbn_10_check_digit fails properly +test_that("check_isbn_10_check_digit() fails properly", { + expect_equal(check_isbn_10_check_digit(c(EX.valid.10.digit.isbns, NA)), + c(TRUE, TRUE, TRUE, NA)) + expect_error(check_isbn_10_check_digit(0123456789, errors.as.false=FALSE), + "Input must be a character string") + expect_error(check_isbn_10_check_digit("123456789", errors.as.false=FALSE), + "Illegal input") + expect_error(check_isbn_10_check_digit("0-124-91540-X", allow.hyphens=FALSE, + errors.as.false=FALSE), + "Illegal input") +}) + + +# is_valid_isbn_10 +test_that("is_valid_isbn_10() succeeds properly", { + expect_equal(is_valid_isbn_10(EX.valid.10.digit.isbns[1]), + TRUE) + expect_equal(is_valid_isbn_10(EX.valid.10.digit.isbns), + c(TRUE, TRUE, TRUE)) + expect_equal(is_valid_isbn_10(c(EX.valid.10.digit.isbns, "012491540x")), + c(TRUE, TRUE, TRUE, TRUE)) + expect_equal(is_valid_isbn_10(c(EX.valid.10.digit.isbns, "012491540x"), + lower.x.allowed=FALSE), + c(TRUE, TRUE, TRUE, FALSE)) + expect_equal(is_valid_isbn_10(EX.invalid.10.digit.isbns), + c(FALSE, FALSE, FALSE, FALSE)) + expect_equal(is_valid_isbn_10(c(EX.valid.10.digit.isbns, + EX.invalid.10.digit.isbns)), + c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE)) + expect_equal(is_valid_isbn_10(c(EX.valid.10.digit.isbns, "hubo un tiempo")), + c(TRUE, TRUE, TRUE, FALSE)) + expect_equal(is_valid_isbn_10("0-124-91540-X"), TRUE) + expect_equal(is_valid_isbn_10("0-124-91540-1"), FALSE) + expect_equal(is_valid_isbn_10("0-124-91540-X", allow.hyphens=FALSE), FALSE) + expect_equal(is_valid_isbn_10(NA), as.character(NA)) +}) + +test_that("is_valid_isbn_10() fails properly", { + expect_equal(is_valid_isbn_10(c(EX.valid.10.digit.isbns, NA)), + c(TRUE, TRUE, TRUE, NA)) + expect_error(is_valid_isbn_10(0123456789), + "Input must be a character string") +}) + + +# normalize ISBN 10 +test_that("normalize_isbn_10() succeeds properly", { + expect_equal(normalize_isbn_10(EX.hairy.isbn.10s), + c("012491540X", NA, "9004037810", "898477250X", + NA, "012491540X", "9570068353", "9570068353", NA, NA, + "012491540X")) + expect_equal(normalize_isbn_10(EX.hairy.isbn.10s, aggressive=FALSE), + c("012491540X", NA, "9004037810", NA, + NA, NA, NA, NA, NA, NA, NA)) + expect_equal(normalize_isbn_10("012491540x"), + "012491540X") + expect_equal(normalize_isbn_10("012491540x xe32ea"), + "012491540X") + expect_equal(normalize_isbn_10("012491540x", convert.to.isbn.13=TRUE), + "9780124915404") + expect_equal(normalize_isbn_10(c("513213012491540x", "012491540x", NA)), + c("012491540X", "012491540X", NA)) + expect_equal(normalize_isbn_10(c("513213012491540x", "012491540x", NA), aggressive=FALSE), + c(NA, "012491540X", NA)) + expect_equal(normalize_isbn_10(NA), as.character(NA)) +}) + +# ------------------------------------------ # + +############################################## +### ISBN 13 ### +############################################## + +# get_isbn_13_check_digit succeeds properly +test_that("get_isbn_13_check_digit() succeeds properly", { + expect_equal(get_isbn_13_check_digit(EX.valid.13.digit.isbns[1]), "7") + expect_equal(get_isbn_13_check_digit(EX.valid.13.digit.isbns), c("7", "0")) + expect_equal(get_isbn_13_check_digit(EX.12.digit.isbns), c("7", "0")) + expect_equal(get_isbn_13_check_digit(c(EX.valid.13.digit.isbns, NA)), + c("7", "0", NA)) + expect_equal(get_isbn_13_check_digit(EX.invalid.13.digit.isbns, errors.as.nas=TRUE), + c(NA, "7")) + expect_equal(get_isbn_13_check_digit("978-0-306-40615-7", allow.hyphens=TRUE), "7") + expect_equal(get_isbn_13_check_digit(NA), as.character(NA)) +}) + +# get_isbn_13_check_digit fails properly +test_that("get_isbn_13_check_digit() fails properly", { + expect_error(get_isbn_13_check_digit(1234567891234), + "Input must be a character string") + expect_error(get_isbn_13_check_digit("123456"), + "Input must be either 12 or 13 characters") + expect_error(get_isbn_13_check_digit(EX.invalid.13.digit.isbns), + "Illegal input") + expect_error(get_isbn_13_check_digit("978-0-306-40615-7"), + "Input must be either 12 or 13 characters") +}) + + +# check_isbn_13_check_digit succeeds properly +test_that("check_isbn_13_check_digit() succeeds properly", { + expect_equal(check_isbn_13_check_digit(EX.valid.13.digit.isbns[1]), + TRUE) + expect_equal(check_isbn_13_check_digit(EX.valid.13.digit.isbns), + c(TRUE, TRUE)) + expect_equal(check_isbn_13_check_digit(EX.invalid.13.digit.isbns), + c(FALSE, FALSE)) + expect_equal(check_isbn_13_check_digit(c(EX.valid.13.digit.isbns, + EX.invalid.13.digit.isbns)), + c(TRUE, TRUE, FALSE, FALSE)) + expect_equal(check_isbn_13_check_digit(c(12, 12), errors.as.false = TRUE), + c(FALSE, FALSE)) + expect_equal(check_isbn_13_check_digit(c(EX.valid.13.digit.isbns, + "hubo un tiempo"), + errors.as.false = TRUE), + c(TRUE, TRUE, FALSE)) + expect_equal(check_isbn_13_check_digit("978-0-306-40615-7"), TRUE) + expect_equal(check_isbn_13_check_digit("978-0-306-40615-7", allow.hyphens=FALSE), + FALSE) + expect_equal(check_isbn_13_check_digit(NA, errors.as.false = FALSE), as.character(NA)) +}) + +# check_isbn_13_check_digit fails properly +test_that("check_isbn_13_check_digit() fails properly", { + expect_equal(check_isbn_13_check_digit(c(EX.valid.13.digit.isbns, NA)), + c(TRUE, TRUE, NA)) + expect_error(check_isbn_13_check_digit(0123456789, errors.as.false=FALSE), + "Input must be a character string") + expect_error(check_isbn_13_check_digit("978-0-306-40615-", errors.as.false=FALSE), + "Illegal input") + expect_error(check_isbn_13_check_digit("978-0-306-40615-7", allow.hyphens=FALSE, + errors.as.false=FALSE), + "Illegal input") +}) + +# is_valid_isbn_13 +test_that("is_valid_isbn_13() succeeds properly", { + expect_equal(is_valid_isbn_13(EX.valid.13.digit.isbns[1]), + TRUE) + expect_equal(is_valid_isbn_13(EX.valid.13.digit.isbns), + c(TRUE, TRUE)) + expect_equal(is_valid_isbn_13(EX.invalid.13.digit.isbns), + c(FALSE, FALSE)) + expect_equal(is_valid_isbn_13(c(EX.valid.13.digit.isbns, + EX.invalid.13.digit.isbns)), + c(TRUE, TRUE, FALSE, FALSE)) + expect_equal(is_valid_isbn_13(c(EX.valid.13.digit.isbns, "hubo un tiempo")), + c(TRUE, TRUE, FALSE)) + expect_equal(is_valid_isbn_13("978-0-306-40615-7"), TRUE) + expect_equal(is_valid_isbn_13("978-0-306-40615-1"), FALSE) + expect_equal(is_valid_isbn_13("978-0-306-40615-7", allow.hyphens=FALSE), FALSE) + expect_equal(is_valid_isbn_13(NA), as.character(NA)) +}) + +test_that("is_valid_isbn_13() fails properly", { + expect_equal(is_valid_isbn_13(c(EX.valid.13.digit.isbns, NA)), + c(TRUE, TRUE, NA)) + expect_error(is_valid_isbn_13(0123456789), + "Input must be a character string") +}) + + +# normalize ISBN 13 +test_that("normalize_isbn_13() succeeds properly", { + expect_equal(normalize_isbn_13(EX.hairy.isbn.13s), + c("9789668197918", "9789668197918", NA, NA, "9781572411579", NA, NA)) + expect_equal(normalize_isbn_13(EX.hairy.isbn.13s, aggressive=FALSE), + c("9789668197918", "9789668197918", NA, NA, NA, NA, NA)) + expect_equal(normalize_isbn_13(NA), as.character(NA)) +}) + + + +# convert_to_isbn_13 +test_that("convert_to_isbn_13() succeeds properly", { + expect_equal(convert_to_isbn_13(c("012491540X", "9004037810")), + c("9780124915404", "9789004037816")) + expect_equal(convert_to_isbn_13(c("012491540X", "9004037810", NA)), + c("9780124915404", "9789004037816", NA)) + expect_equal(convert_to_isbn_13("0124915401", errors.as.nas=TRUE), + c(NA)) + expect_equal(convert_to_isbn_13(NA, errors.as.nas=TRUE), + as.character(c(NA))) + expect_equal(convert_to_isbn_13("9780124915404", skip.validity.check=TRUE), + "9789780124915") + expect_equal(convert_to_isbn_13(NA, skip.validity.check=TRUE), + as.character(c(NA))) + +}) + +test_that("convert_to_isbn_13() fails properly", { + expect_error(convert_to_isbn_13("0124915401"), + "Invalid ISBN 10 detected") + expect_error(convert_to_isbn_13(123), + "Input must be a character string") +}) + +# ------------------------------------------ # + + + +# ------------------------------------------ # + + +############################################## +### GENERAL ISBN ### +############################################## + + +# normalize ISBN (general) +test_that("normalize_isbn() succeeds properly", { + expect_equal(normalize_isbn(c(EX.hairy.isbn.10s, EX.hairy.isbn.13s)), + c(c("012491540X", NA, "9004037810", "898477250X", + NA, "012491540X", "9570068353", "9570068353", NA, NA, + "012491540X"), + c("9789668197918", "9789668197918", NA, "9770800783", + "9781572411579", NA, NA))) + expect_equal(normalize_isbn(NA), as.character(NA)) +}) + + + + + + +############################################## +### ISSN ### +############################################## + +# get_issn_check_digit succeeds properly +test_that("get_issn_check_digit() succeeds properly", { + expect_equal(get_issn_check_digit("03785955"), "5") + expect_equal(get_issn_check_digit(c("0378595", "2434561X", NA)), + c("5", "X", NA)) + expect_equal(get_issn_check_digit(c("0378595", "2434-561X", NA), + allow.hyphens=TRUE), + c("5", "X", NA)) + expect_equal(get_issn_check_digit(NA), as.character(NA)) +}) + +# get_issn_check_digit fails properly +test_that("get_issn_check_digit() fails properly", { + expect_error(get_issn_check_digit(03785955), + "Input must be a character string") + expect_error(get_issn_check_digit("03785955432"), + "Input must be either 7 or 8 characters") +}) + + +# check_issn_check_digit succeeds properly +test_that("get_issn_check_digit() succeeds properly", { + expect_equal(check_issn_check_digit(c("03785955", "2434561X", NA)), + c(TRUE, TRUE, NA)) + expect_equal(check_issn_check_digit(c("03785954", "2434-561X", NA)), + c(FALSE, TRUE, NA)) + expect_equal(check_issn_check_digit(c("03785954", "________", NA), + errors.as.false=TRUE), + c(FALSE, FALSE, NA)) + expect_equal(check_issn_check_digit(NA), as.character(NA)) +}) + +# check_issn_check_digit fails properly +test_that("get_issn_check_digit() fails properly", { + expect_error(check_issn_check_digit(c(12345678)), + "Input must be a character string") + expect_error(check_issn_check_digit(c("03785954", "2434-561X", NA), + allow.hyphens=FALSE), + "Illegal input") +}) + +# is_valid_issn +test_that("is_valid_issn() works", { + expect_equal(is_valid_issn("2434561X"), TRUE) + expect_equal(is_valid_issn("2434-561X"), TRUE) + expect_equal(is_valid_issn(c("2434-561X", "2434-5611", "0378-5955", NA)), + c(TRUE, FALSE, TRUE, NA)) +}) + +# normalize_issn +test_that("normalize_issn() works", { + expect_equal(normalize_issn(c("__2434__561X", NA, "2434561", + "21335212434561X")), + c("2434561X", NA, "2434561X", "2434561X")) + expect_equal(normalize_issn(3785955), "03785955") +}) + +# ------------------------------------------ # + + +############################################## +### LCCN ### +############################################## + +test_that("normalize_lccn() succeeds properly", { + expect_equal(normalize_lccn("n 78890351 "), "n78890351") + expect_equal(normalize_lccn(" 85000002 "), "85000002") + expect_equal(normalize_lccn(" 79139101 /AC/r932"), "79139101") + expect_equal(normalize_lccn("1‡a 2014356397"), NA_character_) + expect_equal(normalize_lccn("A 2014356397"), NA_character_) + expect_equal(normalize_lccn("98114143 /MN"), "98114143") + expect_equal(normalize_lccn("sa 65001662"), "sa65001662") + expect_equal(normalize_lccn("2003306761"), "2003306761") + expect_equal(normalize_lccn("###78890351#"), "78890351") + expect_equal(normalize_lccn("^^^78890351^"), "78890351") + expect_equal(normalize_lccn("i was happy for a day in 1975"), NA_character_) + + # hyphen fails + expect_equal(normalize_lccn("n78-890351"), "n78890351") + expect_equal(normalize_lccn("n78-89035"), "n78089035") + expect_equal(normalize_lccn("85-2 "), "85000002") + expect_equal(normalize_lccn("2001-000002"), "2001000002") + expect_equal(normalize_lccn("75-425165//r75"), "75425165") + expect_equal(normalize_lccn("75-425165//r75", allow.hyphens = FALSE), + NA_character_) + + expect_error(normalize_lccn(8675309), "Input must be a character string") + expect_equal(normalize_lccn(NA), NA_character_) + + # test vectorized + expect_equal(normalize_lccn(c("1‡a 2014356397", "n 78890351 ")), + c(NA_character_, "n78890351")) + expect_equal(normalize_lccn(c("85-2 ", " 79139101 /AC/r932", "n 78890351 ")), + c("85000002", "79139101", "n78890351")) + expect_equal(normalize_lccn(c("85-2 ", " 79139101 /AC/r932", "n 78890351 "), + allow.hyphens=FALSE), + c(NA_character_, "79139101", "n78890351")) + expect_equal(normalize_lccn(c("85-8675309 ", " 79139101 /AC/r932", "n 78890351 ")), + c(NA_character_, "79139101", "n78890351")) + +}) + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-call-numbers-and-subject.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-call-numbers-and-subject.R new file mode 100755 index 0000000..c35a064 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-call-numbers-and-subject.R @@ -0,0 +1,177 @@ +context("checking functions in call-numbers-and-subject.R") + + +data("books_serials_etc_sample") + +# get_lc_call_subject_classification +test_that("lc_call_subject_classification() works", { + expect_equal(get_lc_call_subject_classification("ND 237.S18 $b S87 1997"), + "Fine Arts") + expect_equal(get_lc_call_subject_classification(" ND 237.S18 $b S87 1997 "), + "Fine Arts") + expect_equal(get_lc_call_subject_classification("ND 237.S18 $b S87 1997", subclassification=TRUE), + "Painting") + expect_equal(get_lc_call_subject_classification("PQ2246.M3", already.parsed=TRUE), + NA_character_) + expect_equal(get_lc_call_subject_classification(c("ND 237", + "\\\\$a ND 2", + NA, + "PQ2246.M3"), + subclassification=TRUE), + c("Painting", NA, NA, + "French, Italian, Spanish, and Portuguese literature")) + expect_equal(get_lc_call_subject_classification(books_serials_etc_sample$lccall), + books_serials_etc_sample$lc_subject_class) + expect_equal(get_lc_call_subject_classification(books_serials_etc_sample$lccall, + subclassification=TRUE), + books_serials_etc_sample$lc_subject_subclass) + expect_equal(get_lc_call_subject_classification("H29.S75 A38"), + "Social Sciences") + expect_equal(get_lc_call_subject_classification("H29.S75 A38", subclassification=TRUE), + "Social Sciences (General)") + expect_equal(get_lc_call_subject_classification("Pk3798.K74 C33 1963"), + "Language and Literature") + expect_equal(get_lc_call_subject_classification("Pk3798.K74 C33 1963", subclassification=TRUE), + "Indo-Iranian languages and literatures") + expect_equal(get_lc_call_subject_classification("KKT5674.18 .P75 1986"), + "Law") + expect_equal(get_lc_call_subject_classification("KKT5674.18 .P75 1986", subclassification=TRUE), + "Spain") + expect_equal(get_lc_call_subject_classification("KZD1006 .J68", subclassification=TRUE), + "Space law. Law of outer space") + expect_equal(get_lc_call_subject_classification("KLP13 1919", subclassification=TRUE), + "Ukraine (1919-1991) and Zakavkazskaia Sotsialisticheskaia Federativnaia Sovetskaia Respublika (to 1936)") + expect_equal(get_lc_call_subject_classification("KDC296.A75", subclassification=TRUE), + "Scotland") + expect_equal(get_lc_call_subject_classification("KDC", subclassification=TRUE), + "Scotland") + expect_equal(get_lc_call_subject_classification("KDC", allow.bare=FALSE, subclassification=TRUE), + NA_character_) + expect_equal(get_lc_call_subject_classification("K"), "Law") + expect_equal(get_lc_call_subject_classification(" K "), "Law") + expect_equal(get_lc_call_subject_classification("K", allow.bare=FALSE), NA_character_) + expect_equal(get_lc_call_subject_classification("C13.2:R 31/7"), + "Auxiliary Sciences of History") + expect_equal(get_lc_call_subject_classification("C13.2:R 31/7", subclassification=TRUE), + "Auxiliary Sciences of History (General)") + expect_equal(get_lc_call_subject_classification("A11.K5"), + "General Works") + expect_equal(get_lc_call_subject_classification("A11.K5", subclassification=TRUE), + "General Works") + + # these should fail but they didn't + expect_equal(get_lc_call_subject_classification("CLASSED SEPARATELY"), NA_character_) + expect_equal(get_lc_call_subject_classification("AW1"), NA_character_) + expect_equal(get_lc_call_subject_classification("CURRENT ISSUES ONLY"), NA_character_) + expect_equal(get_lc_call_subject_classification("Arents BIP"), NA_character_) + expect_equal(get_lc_call_subject_classification("IN PROCESS (ONLINE)"), NA_character_) + expect_equal(get_lc_call_subject_classification("AA"), NA_character_) + expect_equal(get_lc_call_subject_classification("Comic Book 10001"), NA_character_) + expect_equal(get_lc_call_subject_classification("CA2ALST A42"), NA_character_) + expect_equal(get_lc_call_subject_classification("Clarkson, Donald R"), NA_character_) + expect_equal(get_lc_call_subject_classification("AVGH (Appenzell) 88-43"), NA_character_) + expect_equal(get_lc_call_subject_classification("Columbia PS 34197"), NA_character_) + expect_equal(get_lc_call_subject_classification("CQ40 C749"), NA_character_) + expect_equal(get_lc_call_subject_classification("AA1116 N1 F4143"), NA_character_) + expect_equal(get_lc_call_subject_classification("AA9127 N4L1 N48667"), NA_character_) + expect_equal(get_lc_call_subject_classification("Atlantic SD 19258"), NA_character_) + expect_equal(get_lc_call_subject_classification("Canadian Broadcasting Corp. SM5044"), NA_character_) + expect_equal(get_lc_call_subject_classification("AA7545 Un32537"), NA_character_) + expect_equal(get_lc_call_subject_classification("AK3780 G182"), NA_character_) + expect_equal(get_lc_call_subject_classification("LAW"), NA_character_) + expect_equal(get_lc_call_subject_classification("Newspaper"), NA_character_) + expect_equal(get_lc_call_subject_classification("UNC"), NA_character_) + expect_equal(get_lc_call_subject_classification("MLCSA 91/02857 (P)"), NA_character_) + + expect_equal(get_lc_call_subject_classification("CLASSED SEPARATELY", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AW1", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("CURRENT ISSUES ONLY", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Arents BIP", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("IN PROCESS (ONLINE)", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AA", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Comic Book 10001", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("CA2ALST A42", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Clarkson, Donald R", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Columbia PS 34197", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("CQ40 C749", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AA1116 N1 F4143", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AA9127 N4L1 N48667", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Atlantic SD 19258", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Canadian Broadcasting Corp. SM5044", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AA7545 Un32537", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("AK3780 G182", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("LAW", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("Newspaper", subclassification=TRUE), NA_character_) + expect_equal(get_lc_call_subject_classification("UNC", subclassification=TRUE), NA_character_) + + +}) + +# is_valid_lc_call +test_that("is_valid_lc_call() works", { + expect_equal(is_valid_lc_call(c("Q 172.5", "AF172", "PR6023.A93")), + c(TRUE, FALSE, TRUE)) + expect_equal(is_valid_lc_call("H29.S75 A38"), TRUE) + expect_equal(is_valid_lc_call(" H29.S75 A38 "), TRUE) + expect_equal(is_valid_lc_call("Pk3798.K74 C33 1963"), TRUE) + expect_equal(is_valid_lc_call("Rs164 .K894818 1966"), TRUE) + expect_equal(is_valid_lc_call("KKT5674.18 .P75 1986"), TRUE) + expect_equal(is_valid_lc_call("KDC"), FALSE) + expect_equal(is_valid_lc_call("KDC", allow.bare=TRUE), TRUE) + expect_equal(is_valid_lc_call("K"), FALSE) + expect_equal(is_valid_lc_call("K", allow.bare=TRUE), TRUE) +}) + +# get_lc_call_first_letter +test_that("get_lc_call_first_letter() works", { + expect_equal(get_lc_call_first_letter(c("Q 172.5", "AF172", NA, "PR6023.A93")), + c("Q", NA, NA, "P")) + expect_equal(get_lc_call_first_letter("H29.S75 A38"), "H") + expect_equal(get_lc_call_first_letter("\tH29.S75 A38"), "H") + expect_equal(get_lc_call_first_letter("Pk3798.K74 C33 1963"), "P") + expect_equal(get_lc_call_first_letter("KKT5674.18 .P75 1986"), "K") + expect_equal(get_lc_call_first_letter("KDC"), NA) + expect_equal(get_lc_call_first_letter("KDC", allow.bare=TRUE), "K") + expect_equal(get_lc_call_first_letter("K"), NA) + expect_equal(get_lc_call_first_letter("K", allow.bare=TRUE), "K") +}) + +# get_all_lc_call_subject_letters +test_that("get_all_lc_call_subject_letters() works", { + expect_equal(get_all_lc_call_subject_letters(c("Q 172.5", "AF172", NA, + "PR6023.A93")), + c("Q", NA, NA, "PR")) + expect_equal(get_all_lc_call_subject_letters("Pk3798.K74 C33 1963"), "PK") + expect_equal(get_all_lc_call_subject_letters(" Pk3798.K74 C33 1963"), "PK") + expect_equal(get_all_lc_call_subject_letters("KKT5674.18 .P75 1986"), "KKT") + expect_equal(get_all_lc_call_subject_letters("KDC"), NA) + expect_equal(get_all_lc_call_subject_letters("KDC", allow.bare=TRUE), "KDC") +}) + + +# get_dewey_decimal_subject_class +test_that("get_dewey_decimal_subject_class() works", { + expect_equal(get_dewey_decimal_subject_class(books_serials_etc_sample$dewey), + books_serials_etc_sample$dewey_subject_class) + expect_equal(get_dewey_decimal_subject_class(c("709.05", "invalid", NA, "823.912")), + c("Arts", NA, NA, "Literature (Belles-lettres) and rhetoric")) +}) + +# get_dewey_decimal_subject_division +test_that("get_dewey_decimal_subject_division() works", { + expect_equal(get_dewey_decimal_subject_division(books_serials_etc_sample$dewey), + books_serials_etc_sample$dewey_subject_division) + expect_equal(get_dewey_decimal_subject_division(c("709.05", "invalid", NA, "823.912")), + c("Arts", NA, NA, "English and Old English literatures")) +}) + +# get_dewey_decimal_subject_section +test_that("get_dewey_decimal_subject_section() works", { + expect_equal(get_dewey_decimal_subject_section(books_serials_etc_sample$dewey), + books_serials_etc_sample$dewey_subject_section) + expect_equal(get_dewey_decimal_subject_section(c("709.05", "invalid", NA, "823.912")), + c("History, geographic treatment, biography", NA, NA, "English fiction")) +}) + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-marc-field-deconstruction.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-marc-field-deconstruction.R new file mode 100755 index 0000000..f343696 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-marc-field-deconstruction.R @@ -0,0 +1,21 @@ +context("checking functions in marc-field-deconstruction.R") + + +data("books_serials_etc_sample") + +# marc_leader_get_info +test_that("marc_leader_get_info() works", { + expect_equal(books_serials_etc_sample[, marc_leader_get_info(marc_leader)][,record_type], + books_serials_etc_sample[,record_type]) + expect_equal(books_serials_etc_sample[, marc_leader_get_info(marc_leader)][,bib_level], + books_serials_etc_sample[,bib_level]) +}) + +# marc_008_get_info +test_that("marc_008_get_info() works", { + expect_equal(books_serials_etc_sample[, marc_008_get_info(marc_008, original.pub.date=TRUE)][,pub_date], + books_serials_etc_sample[,pubyear2]) + expect_equal(books_serials_etc_sample[, marc_008_get_info(marc_008)][,lang_code], + books_serials_etc_sample[,language]) +}) + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-other-code-translations.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-other-code-translations.R new file mode 100755 index 0000000..46d426b --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-other-code-translations.R @@ -0,0 +1,25 @@ +context("checking functions in other-code-translations.R") + + + +# get_language_from_code +test_that("get_language_from_code() works properly", { + expect_equal(get_language_from_code("yor"), "Yoruba") + expect_equal(get_language_from_code(c("yor", " SPA")), + c("Yoruba", "Spanish")) + expect_equal(get_language_from_code(c("yor", " SPA", "not-a-language", "nah", NA)), + c("Yoruba", "Spanish", NA, "Nahuatl", NA)) + expect_equal(get_language_from_code(""), NA_character_) + expect_equal(get_language_from_code(NA), NA_character_) +}) + +# get_country_from_code +test_that("get_country_from_code() works properly", { + expect_equal(get_country_from_code("ck"), "Colombia") + expect_equal(get_country_from_code(c(" PE", "nyu")), c("Peru", "New York (State)")) + expect_equal(get_country_from_code(c(" PE", NA, "uv", "not-a-country", "nyu")), + c("Peru", NA, "Burkina Faso", NA, "New York (State)")) + expect_equal(get_country_from_code(""), NA_character_) + expect_equal(get_country_from_code(NA), NA_character_) +}) + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-split-map-filter-reduce.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-split-map-filter-reduce.R new file mode 100755 index 0000000..3f65a88 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-split-map-filter-reduce.R @@ -0,0 +1,85 @@ +context("checking functions in split-map-filter-reduce.R") + + +############################################## +### SETUP ### +############################################## + + +ejemplo <- c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952; 978-1-86189-795-4", + "1861897952 978-1-86189-795-4") + +ejemplo2 <- c("9782711875177;garbage-isbn;2711875172;2844268900", + NA, "") + + +# --------------------------------------------------------------- # + + +test_that("car() works", { + expect_equal(car(c(8, 6, 7, 5, 3, 0, 9)), 8) + # expect_equal(car(c(NA, 6, 7, 5, 3, 0, 9)), NA) + expect_equal(car(NA), NA) + expect_equal(car(""), "") +}) + + +test_that("remove_duplicates_and_nas() works", { + expect_equal(remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)), + c(8, 6, 7, 5, 3, 0, 9)) + expect_equal(remove_duplicates_and_nas(1), 1) + expect_equal(remove_duplicates_and_nas(c(NA, NA, NA)), NA) +}) + + +test_that("recombine_with_sep_closure() works", { + expect_equal(recombine_with_sep_closure()(c(8,6,7)), "8;6;7") + expect_equal(recombine_with_sep_closure()(c()), "") + expect_equal(recombine_with_sep_closure()(NA), NA) + expect_equal(recombine_with_sep_closure(sep=" ")(c("this", "that", NA,"the-other")), + "this that NA the-other") +}) + + +test_that("split_map_filter_reduce() works", { + expect_equal(split_map_filter_reduce(ejemplo), + c("9782711875177", "1861897952", + "1861897952 978-1-86189-795-4")) + + expect_equal(split_map_filter_reduce(ejemplo, sep="\\s+"), + c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952; 978-1-86189-795-4", + "1861897952 978-1-86189-795-4")) + + expect_equal(split_map_filter_reduce(ejemplo, sep="\\s+", fixed=FALSE), + c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952;", "1861897952")) + + expect_equal(split_map_filter_reduce(ejemplo, sep="\\s+", fixed=FALSE, + reduxfun=recombine_with_sep_closure(" ")), + c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952; 978-1-86189-795-4", "1861897952 978-1-86189-795-4")) + + expect_equal(split_map_filter_reduce(ejemplo, + mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + reduxfun=recombine_with_sep_closure(" ")), + c("9782711875177 NA 9782711875177 9782844268907", + "9781861897954 9781861897954", "9781861897954")) + + expect_equal(split_map_filter_reduce(ejemplo, + mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + filterfun=remove_duplicates_and_nas, + reduxfun=recombine_with_sep_closure(" ")), + c("9782711875177 9782844268907", "9781861897954", "9781861897954")) + + expect_equal(split_map_filter_reduce(ejemplo2, + mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + filterfun=remove_duplicates_and_nas, + reduxfun=recombine_with_sep_closure(" ")), + c("9782711875177 9782844268907", NA, NA)) +}) + + + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-the-web.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-the-web.R new file mode 100755 index 0000000..7e5230b --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-the-web.R @@ -0,0 +1,94 @@ +context("checking functions in the-web.R") + + + +# loc_permalink_from_lccn +test_that("loc_permalink_from_lccn() works", { + expect_equal(loc_permalink_from_lccn("n78-890351"), + "https://lccn.loc.gov/n78890351") + expect_equal(loc_permalink_from_lccn("85-2 "), + "https://lccn.loc.gov/85000002") + expect_equal(loc_permalink_from_lccn(c("n78-890351", "85-2 ")), + c("https://lccn.loc.gov/n78890351", + "https://lccn.loc.gov/85000002")) + expect_equal(loc_permalink_from_lccn(c("###78890351#", NA, "n78-890351")), + c("https://lccn.loc.gov/78890351", NA, + "https://lccn.loc.gov/n78890351")) + + expect_error(loc_permalink_from_lccn(123456789), + "Input must be a character string") + + expect_equal(loc_permalink_from_lccn("73167510", format="marcxml"), + "https://lccn.loc.gov/73167510/marcxml") + expect_equal(loc_permalink_from_lccn("73167510", format="mods"), + "https://lccn.loc.gov/73167510/mods") + expect_equal(loc_permalink_from_lccn("73167510", format="mads"), + "https://lccn.loc.gov/73167510/mads") + expect_equal(loc_permalink_from_lccn("73167510", format="dublin"), + "https://lccn.loc.gov/73167510/dc") + expect_error(loc_permalink_from_lccn("73167510", format="nonsense"), + 'format must be one of "", "marcxml", "mods", "mads", or "dublin"') +}) + + +# worldcat_permalink_from_issn +test_that("worldcat_permalink_from_issn() works", { + expect_equal(worldcat_permalink_from_issn(c("0968-1221", NA, "2434-561X")), + c("http://www.worldcat.org/issn/09681221", NA, + "http://www.worldcat.org/issn/2434561X")) + expect_equal(worldcat_permalink_from_issn(c("0968-1221", NA, "2434-561X"), + normalize=FALSE), + c("http://www.worldcat.org/issn/0968-1221", NA, + "http://www.worldcat.org/issn/2434-561X")) + + expect_error(worldcat_permalink_from_issn(123456789), + "Input must be a character string") +}) + + +# worldcat_permalink_from_isbn +test_that("worldcat_permalink_from_isbn() works", { + expect_equal(worldcat_permalink_from_isbn(c("1788393724", NA, + "0-124-91540-X")), + c("http://www.worldcat.org/isbn/1788393724", NA, + "http://www.worldcat.org/isbn/012491540X")) + expect_equal(worldcat_permalink_from_isbn(c("1788393724", NA, + "0-124-91540-X"), + normalize=FALSE), + c("http://www.worldcat.org/isbn/1788393724", NA, + "http://www.worldcat.org/isbn/0-124-91540-X")) + + expect_error(worldcat_permalink_from_isbn(123456789), + "Input must be a character string") +}) + + +# worldcat_permalink_from_oclc_number +test_that("worldcat_permalink_from_oclc_number() works", { + + expect_equal(worldcat_permalink_from_oclc_number(c("1049727704", NA, + "1005106045")), + c("http://www.worldcat.org/oclc/1049727704", NA, + "http://www.worldcat.org/oclc/1005106045")) + expect_equal(worldcat_permalink_from_oclc_number("733889 + 7"), "http://www.worldcat.org/oclc/7338897") + expect_error(worldcat_permalink_from_oclc_number(123456789), + "Input must be a character string") +}) + + +# oclc_classify_link_from_standard_num +test_that("oclc_classify_link_from_standard_num() works", { + expect_equal(oclc_classify_link_from_standard_num("629725006"), + "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0") + expect_equal(oclc_classify_link_from_standard_num(c("039333712X", NA, "629725006")), + c("http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=039333712X&startRec=0", + NA, "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0")) + expect_equal(oclc_classify_link_from_standard_num("733889 + 7"), "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=7338897&startRec=0") + expect_equal(oclc_classify_link_from_standard_num(NA), + NA_character_) + expect_error(oclc_classify_link_from_standard_num(1), + "Input must be a character string") +}) + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-utilities.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-utilities.R new file mode 100755 index 0000000..317fea9 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-utilities.R @@ -0,0 +1,106 @@ +context("checking functions in utilities.R") + + +############################################## +### SETUP ### +############################################## + +mt <- as.data.table(mtcars) +iris_dt <- as.data.table(iris) +mt_some_na <- copy(mt) +mt_some_na[mpg<16, mpg:=NA] + +ejemplo <- as.data.table(iris) +setnames(ejemplo, c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\nWidth", "SpĂȘcies")) + +ejemplo2 <- as.data.table(iris) +setnames(ejemplo2, c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\nWidth", "SpĂȘcies")) +ejemplo2[, Sp_cies:=1] +ejemplo2[, Sp_cies_1:=2] + +ejemplo3 <- as.data.table(iris) +setnames(ejemplo3, c("data0", "data1", "data!", "data@", "d4ta4")) + + +# --------------------------------------------------------------- # + + +test_that("dt_del_cols() works", { + expect_error(dt_del_cols(mtcars, "cyl"), + regexp="DT must be a data.table object", + fixed=TRUE) +}) + +test_that("dt_keep_cols() works", { + expect_error(dt_keep_cols(mtcars, "cyl"), + regexp="DT must be a data.table object", + fixed=TRUE) +}) + +test_that("dt_counts_and_percents() works", { + expect_error(dt_counts_and_percents(iris, "Species"), + regexp="DT must be a data.table object", + fixed=TRUE) +}) + + +test_that("get_clean_names() works", { + expect_equal(get_clean_names(ejemplo), + c("sepal_length", "sepal_width", "petal_length", + "petal_nwidth", "sp_cies")) + expect_equal(get_clean_names(ejemplo, lower=FALSE), + c("Sepal_Length", "Sepal_Width", "Petal_Length", + "Petal_nWidth", "Sp_cies")) + expect_equal(get_clean_names(ejemplo2, lower=FALSE), + c("Sepal_Length", "Sepal_Width", "Petal_Length", + "Petal_nWidth", "Sp_cies", "Sp_cies_2", "Sp_cies_1")) + expect_equal(get_clean_names(ejemplo3), + c("data0", "data1", "data_", "data__1", "d4ta4")) +}) + +test_that("dt_set_clean_names() works", { + expect_error(dt_set_clean_names(iris), + regexp="DT must be a data.table object", + fixed=TRUE) +}) + + +test_that("dt_percent_not_na() works", { + # expect_equal(dt_percent_not_na(mt, "mpg"), 68.75) + expect_error(dt_percent_not_na(iris, "Species"), + regexp="DT must be a data.table object", + fixed=TRUE) +}) + + +test_that("dt_add_to_col_names() works", { + expect_equal(names(dt_add_to_col_names(data.table(iris), "_post")), + c("Sepal.Length_post", "Sepal.Width_post", "Petal.Length_post", + "Petal.Width_post", "Species_post")) + expect_equal(names(dt_add_to_col_names(data.table(iris), "pre_", prefix=TRUE)), + c("pre_Sepal.Length", "pre_Sepal.Width", "pre_Petal.Length", + "pre_Petal.Width", "pre_Species")) + expect_equal(names(dt_add_to_col_names(data.table(iris), "pre_", prefix=TRUE, + exclude=c("Species", "Sepal.Length"))), + c("Sepal.Length", "pre_Sepal.Width", "pre_Petal.Length", + "pre_Petal.Width", "Species")) + expect_equal(names(dt_add_to_col_names(data.table(iris), "pre_", prefix=TRUE, + include=c("Sepal.Width", "Petal.Length", + "Petal.Width"))), + c("Sepal.Length", "pre_Sepal.Width", "pre_Petal.Length", + "pre_Petal.Width", "Species")) + expect_error(dt_add_to_col_names(iris, "hi"), + "DT must be a data.table") + expect_warning(dt_add_to_col_names(data.table(iris), "hi", include=c("people", "streets")), + '') #'Columns ("people", "streets") are missing from supplied data.table') + expect_warning(dt_add_to_col_names(data.table(iris), "hi", exclude=c("people", "streets")), + '') #'Columns ("people", "streets") are missing from supplied data.table') + expect_warning(dt_add_to_col_names(data.table(iris), "hi", exclude="people"), + '') #'Columns ("people") are missing from supplied data.table') + expect_error(dt_add_to_col_names(data.table(iris), exclude="bs", include="gs"), + "cannot have both 'include' and 'exclude' parameters at the same time") +}) + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-worldcat-api.R b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-worldcat-api.R new file mode 100755 index 0000000..fd82b8a --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/tests/testthat/test-worldcat-api.R @@ -0,0 +1,121 @@ +context("checking functions in worldcat-api.R") + + +options("libbib.wskey"="test") + + +# can't really test these functions much + +# worldcat_api_classify_by_oclc +test_that("worldcat_api_classify_by_oclc() works", { + expect_null(worldcat_api_classify_by_oclc(NA)) + expect_error(worldcat_api_classify_by_oclc(c("877749545", "939766505")), + "only accepts one standard number at a time") +}) + +# worldcat_api_classify_by_isbn +test_that("worldcat_api_classify_by_isbn() works", { + expect_null(worldcat_api_classify_by_isbn(NA)) + expect_error(worldcat_api_classify_by_isbn(c("978039333712", "978039333712")), + "only accepts one standard number at a time") +}) + +# worldcat_api_classify_by_issn +test_that("worldcat_api_classify_by_issn() works", { + expect_null(worldcat_api_classify_by_issn(NA)) + expect_error(worldcat_api_classify_by_issn(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + + + + +# worldcat_api_bib_read_info_by_oclc +test_that("worldcat_api_bib_read_info_by_oclc() works", { + expect_null(worldcat_api_bib_read_info_by_oclc(NA)) + expect_error(worldcat_api_bib_read_info_by_oclc(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + +# worldcat_api_bib_read_info_by_isbn +test_that("worldcat_api_bib_read_info_by_isbn() works", { + expect_null(worldcat_api_bib_read_info_by_isbn(NA)) + expect_error(worldcat_api_bib_read_info_by_isbn(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + +# worldcat_api_bib_read_info_by_issn +test_that("worldcat_api_bib_read_info_by_issn() works", { + expect_null(worldcat_api_bib_read_info_by_issn(NA)) + expect_error(worldcat_api_bib_read_info_by_issn(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + + + + +# construct_wcapiloc_url +test_that("construct_wcapiloc_url() works", { + expect_equal(construct_wcapiloc_url("877749545"), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10032&maximumLibraries=100&servicelevel=full&frbrGrouping=on&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("9781788393720", type_std_num="isbn"), + "http://www.worldcat.org/webservices/catalog/content/libraries/isbn/9781788393720?location=10032&maximumLibraries=100&servicelevel=full&frbrGrouping=on&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("877749545", location="10463"), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10463&maximumLibraries=100&servicelevel=full&frbrGrouping=on&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("877749545", max_libraries=2), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10032&maximumLibraries=2&servicelevel=full&frbrGrouping=on&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("877749545", servicelevel="default"), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10032&maximumLibraries=100&servicelevel=default&frbrGrouping=on&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("857542062", frbrGrouping="off"), + "http://www.worldcat.org/webservices/catalog/content/libraries/857542062?location=10032&maximumLibraries=100&servicelevel=full&frbrGrouping=off&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("877749545", libtype="government"), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10032&maximumLibraries=100&servicelevel=full&frbrGrouping=on&libtype=3&startLibrary=1&wskey=test") + expect_equal(construct_wcapiloc_url("877749545", start_at=10), + "http://www.worldcat.org/webservices/catalog/content/libraries/877749545?location=10032&maximumLibraries=100&servicelevel=full&frbrGrouping=on&startLibrary=10&wskey=test") + + expect_error(construct_wcapiloc_url(877749545), + "standard number must be a string") + expect_error(construct_wcapiloc_url(), + 'argument "stdnum" is missing, with no default') + expect_error(construct_wcapiloc_url("877749545", type_std_num="lccn"), + 'type of standard number must be "oclc", "isbn", or "issn"') + expect_error(construct_wcapiloc_url("877749545", max_libraries="a billion"), + "max_libraries must be a number between 1 and 100") + expect_error(construct_wcapiloc_url("877749545", max_libraries=1000), + "max_libraries must be a number between 1 and 100") + expect_error(construct_wcapiloc_url("877749545", servicelevel="all"), + 'service level must be "full" or "default"') + expect_error(construct_wcapiloc_url("877749545", frbrGrouping="all"), + 'frfbGrouping must be "on" or "off"') + expect_error(construct_wcapiloc_url("877749545", libtype="all"), + 'libtype must be either NULL, "academic", "public", "government", or "other"') + expect_error(construct_wcapiloc_url("877749545", start_at="all"), + 'start_at must be a number') + +}) + + + + +# worldcat_api_locations_by_oclc +test_that("worldcat_api_locations_by_oclc() works", { + expect_null(worldcat_api_locations_by_oclc(NA)) + expect_error(worldcat_api_locations_by_oclc(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + +# worldcat_api_locations_by_isbn +test_that("worldcat_api_locations_by_isbn() works", { + expect_null(worldcat_api_locations_by_isbn(NA)) + expect_error(worldcat_api_locations_by_isbn(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + +# worldcat_api_locations_by_issn +test_that("worldcat_api_locations_by_issn() works", { + expect_null(worldcat_api_locations_by_issn(NA)) + expect_error(worldcat_api_locations_by_issn(c("12341234", "12341234")), + "only accepts one standard number at a time") +}) + + diff --git a/libbib.Rcheck/00_pkg_src/libbib/vignettes/using-the-worldcat-search-api.Rmd b/libbib.Rcheck/00_pkg_src/libbib/vignettes/using-the-worldcat-search-api.Rmd new file mode 100644 index 0000000..500f093 --- /dev/null +++ b/libbib.Rcheck/00_pkg_src/libbib/vignettes/using-the-worldcat-search-api.Rmd @@ -0,0 +1,991 @@ +--- +title: "Using the WorldCat Search API" +# title: "using-the-worldcat-search-api" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Using the WorldCat Search API} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +# let's load this package before getting started +library(libbib) +``` + +_Intermediate knowledge of R is required to follow the examples here._ + +_Basic knowledge of how to manipulate `data.table`s if helpful but_ +_following the examples should be possible without it._ + +## Introduction + +`libbib`'s ability to communicate to the WorldCat Search API is probably +the most helpful capability of the package. As such, an entire vignette +dedicated to this powerful tool is warranted. + +Also of note is that documentation on how to use this API +is scattered throughout the web, in different places, and +sometimes even no longer available and only accessible through the +internet archive. Because of this, the goal of this vignette is not +only to document `libbib`'s `worldcat_api_search` function, but to +provide a single location for compiling this archived documentation +and providing information/examples of what the WorldCat Search API is +capable, in general. + +The terminology/nomenclature of the different WorldCat API offerings +is fuzzy and inconsistent. The specific kind of Search API that this package +offers usage of can, more specifically, be described as the +'WorldCat SRU Search API version 1'. + +There is a version 2 of this API, but version 1 hasn't been sunsetted as +of yet. + +First, let's speak of what this API is and what it is not. + +## What the WorldCat SRU Search API is + +This API is allows a developer to search for bibliographic records that +are cataloged in WorldCat. + +The queries are made using [the SRU standard search protocol](https://en.wikipedia.org/wiki/Search/Retrieve_via_URL) +(Search/Retrieve via URL) using a standard query syntax called [CQL](https://en.wikipedia.org/wiki/Contextual_Query_Language) +(Contextual Query Language). The WorldCat Search API doesn't implement +all features of CQL; this vignette will illustrate SRU/CQL only +insofar as it is supported by this API. + +This API is open to libraries that maintain both WorldCat Discovery and +OCLC Cataloging subscriptions and needs an API key (called a `WSKey`) to work. +A request can be made for a key (if your institution doesn't already have one) +via [this link.](https://help.oclc.org/Discovery_and_Reference/WorldCat_Discovery/Troubleshooting/How_do_I_request_a_WSKey_for_the_WorldCat_Search_API) + +## What the WorldCat SRU Search API is not + +This API is not the OpenSearch/Basic API, which doesn't allow field-specific +searches and only supports keyword-anywhere searches. + +This is also not the same as using the +[advanced search option on worldcat.org](https://www.worldcat.org/advancedsearch). +That option only provides a subset of the bibliographic records in WorldCat and +is a far less powerful tool. + +This API is most akin to using the "expert search" option in OCLC's +FirstSearch, using the WorldCat database, but differs in that (a) searching +the API is programmatically automate-able, and (b) the API allows for, still, +more powerful search queries. + +## What `libbib`'s `worldcat_api_search` function provides + +At its most basic, this function takes a SRU query and returns a +`data.table` with most of the bibliographic metadata from the MARCXml +that the API returns. We'll see how the behavior of this function can +be controlled by specifying certain function parameters. + +This function also offers assistance with the SRU query syntax. +Mainly, the function allows you to substitute the arcane search index +codes for more human-readable equivalents, prefixed be a (US) dollar-sign. +Examples of these aids will be explained later in the vignette. + +## An example of usage and what the function returns + +Let's look at an example of a simple query and what the returned +`data.table` looks like. + +Specifically, we'll search for "Madame Bovary" by "Gustave Flaubert" +and we'll only show the first three results + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +library(libbib) # load this package + +result <- worldcat_api_search('$title="Madame Bovary" and + $author="Gustave Flaubert"') + +# get the column names +names(result) +#> [1] "total_wc_results" "result_number" "oclc" "isbn" +#> [5] "issn" "title" "author" "pub_date" +#> [9] "lang_code" "bib_level" "record_type" "pub_place_code" +#> [13] "publisher" "leader" "oh08" "query" + +# show the first three results +result[1:3,] +#> total_wc_results result_number oclc isbn issn +#> +#> 1: 986 1 1125170419 9782253183464 +#> 2: 986 2 1049849403 9788415618843 +#> 3: 986 3 1203070641 9781664921993 +#> title author pub_date lang_code bib_level +#> +#> 1: Madame Bovary : Flaubert, Gustave, 2019 fre Monograph/Item +#> 2: Madame Bovary / Flaubert, Gustave, 2019 spa Monograph/Item +#> 3: Madame Bovary / Flaubert, Gustave, 2021 eng Monograph/Item +#> record_type pub_place_code publisher +#> +#> 1: Language Material fr le Livre de poche, +#> 2: Language Material sp +#> 3: Nonmusical sound recording ohu +#> leader oh08 +#> +#> 1: 00000cam a2200000Mi 4500 190619s2019 fr a g 000 1 fre d +#> 2: 00000cam a2200000Ii 4500 180827t20192018sp a 000 1 spa d +#> 3: 00000cim a2200000Mi 4500 201104s2021 ohunnnneq f n eng d +#> query +#> +#> 1: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +#> 2: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +#> 3: srw.ti="Madame Bovary" and srw.au="Gustave Flauber... +``` + +This should give you an idea of the rich information returned by the results +`data.table`. All of the information returned is from (or derived from) +the MARCXml that the API returns, save for + + - `total_wc_results` + Which returns the number of the results the query yields in WorldCat even + if the number of records/results requested is lower than this number. + + - `result_number` + This number of the result, which is helpful if you're using a starting + position other than `1` (the default) + + - `query` + The final SRU query (after any of the SRU query assistance routines step + in) that is sent to the API. This can be useful for debugging. + +Hereafter, the output of the example queries will be abbreviated, truncated, +elided, or only show a subset of columns in order to save space and +aid in following the guide. + +## What does an error look like + +If you craft a query that yields no results, a message telling you such +will be displayed, and the return value is `NULL`. + +If you make an error in the query syntax, no results will be returned, but +a diagnostic message returned from the server may tell you what went wrong. +Here are two examples... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +# missing ending double quotes +worldcat_api_search('$title="Madame Bovary and $langauge=greek') +#> Received diagnostic message: Query syntax error (org.z3950.zing.cql.CQLParseException: expected index or term, got EOF) +#> no results found +#> NULL + +# "$titley" is not a valid search index +worldcat_api_search('$titley="Madame Bovary" and $langauge=greek') +#> Received diagnostic message: Unsupported index (srw.tiy) +#> no results found +#> NULL + +worldcat_api_search("$holding_library=NYP") +#> Received diagnostic message: Limit index, can only be used to narrow a result +#> for a non-limit index (srw.li) +#> no results found +#> NULL +``` + +This last one failed because `$holding_library` is considered +a _limit index_. This means that you can't use it to search directly, +you can only combine with search facet with other non-limiting +indexes to filter the results. +Hopefully this will make more sense as you go through this vignette. + +## `worldcat_api_search` by example / quick start + +In guides like this, there is frequently tension between wanting to +be a complete reference, and wanting to show cool/helpful examples +at a glance. + +In service of easing this tension, we'll first look at some examples +illustrating things this function can do and _then_ turn our attention +to an adequate explanation of boolean operators, relations operators, +search indexes, etc... + +These examples are largely taken from the `examples` section of the +R documentation for this function. + +These examples (and the ones further along in this vignette) will also +use `data.table` syntax to limit number of rows and columns returned +to aid reading. + +We'll be focusing on the types of queries you can use in this section; +controlling the behavior of the function via changing parameters will +come later. + +```{r, eval=FALSE} +library(libbib) + +# title search for "The Brothers Karamazov" +results <- worldcat_api_search('$title="Brothers Karamazov"') + +# Madame Bovary by Gustave Flaubert in Greek +sru <- '$author="Gustave Flaubert" and + $title="Madame Bovary" and + $language=greek' +results <- worldcat_api_search(sru) + +# Hip Hop materials on wax, cassette, or CD published from +# 1987 to 1990 +sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) + and $subject="Rap") and $year="1987-1990"' +results <- worldcat_api_search(sru) + +# keyword search for "Common Lisp" for materials held +# at The New York Public Library +sru <- '$keyword="common lisp" and $holding_library=NYP' +results <- worldcat_api_search(sru) + +# keyword search for "Common Lisp" for materials held +# by any of the members of the "Manhattan Research +# Library Initiative" (MaRLI) joint borrowing program +# (New York Public Library, Columbia University, and +# New York University) +sru <- '($keyword="common lisp" and $holding_library=NYP) + or ($keyword="common lisp" and $holding_library=ZYU) + or ($keyword="common lisp" and $holding_library=ZCU)' +results <- worldcat_api_search(sru) + +# Books (only books) about Ethics (by dewey division 170s or +# LC call number subject class "BJ") published in the 19th +# century +sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*" and + $material_type=bks' +results <- worldcat_api_search(sru) + +# Materials on Musicology (by Dewey division 780s) at +# the New York Public Library and not held by any +# other insitution +sru <- '$dewey="78*" and $holding_library=NYP and + $library_holdings_group=11' +results <- worldcat_api_search(sru) + +# Search for materials on "Danger Music" published since 2010 +results <- worldcat_api_search('$keyword="danger music" and $year="2010-"') +``` + + +Now that we've seen these examples, sans explanation, we can now +have a closer look into the components of a query. +Broadly speaking, there are four concepts to be aware of... + + - relations operators + + - boolean operators + + - wildcards + + - search indexes + +We'll be looking at each in this order, because I think that makes +the most sense. To illustrate the first three concepts, though, +we have to use search indexes, before a formal explanation of what +they are. + +Briefly, a search index is a facet along which to search. In all of +the examples above, the search indexes were prefixed by a `$` +character (e.g. `$title`, `author`, `$keyword`, etc...) + + +## Relations operators + +There are four relations operators available for use... + + - `=` + + - `exact` + + - `any` + + - `all` + +It should be noted that not every relations operator is available +for use with every search index. + +### `=` + +This was the most common operator used in the quick-start examples above. +Though this operator can be most fully understood via contrast with the +next operator, `exact`, suffice it to say, for now, that using `=` means +that all of your search terms must match, without intervening words. +This is sometimes referred to as an "un-anchored" search. + +If the phrase you're search for has spaces in it, you have to surround +it with double quotes. Since the SRU query to the `worldcat_api_search` +function must be a string, and strings can be made with single quotes +and double quotes, we need to surround the entire query with single +quotes. + +We can get around this by "escaping" the quotes, but using only single +quotes to surround the whole query is the most elegant approach. + +You can use both spaces and `+` to separate the search index and the +search term on both sides of the relations operator... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +sru <- '$title+=+"Common Lisp"' +results <- worldcat_api_search(sru) +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 367 Common Lisp / +#> 2: 367 Practical Common Lisp / +#> 3: 367 Common LISP / +``` + +is the same as... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +sru <- '$title = "Common Lisp"' +results <- worldcat_api_search(sru) +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 367 Common Lisp / +#> 2: 367 Practical Common Lisp / +#> 3: 367 Common LISP / +``` + +But we'll be using spaces here. + +The `=` relations operator is the only one that doesn't require any +space or `+` on either side of the operator, and we'll be using both +the spaced version and non-spaced version in these examples for this +operator, only. + + +### `exact` (anchored search) + +The `exact` operator, in contrast with the `=` operator, signals to +the API that your search must match as an exact phrase, without +any other terms in the matching string. For this reason, this operator +is sometimes referred to as an "anchored search". + +Here's an example using the same title search as above... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title exact "Common Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 37 Common Lisp / +#> 2: 37 Common LISP / +#> 3: 37 Common LISP / +``` + +Note that the title "Practical Common Lisp" was returned by the +`=` operator query. The `exact` operator will not match this title +since it has another word/phrase in it besides "Common Lisp". + +Using an `exact` search is probably a better fit than `=` for some +indexes and in some situations. For example, if you know the exact +title of a book (e.g. `$title exact "Brothers Karamazov")`, using +`exact` will ensure that books with a title like _"A Guide to The_ +_Brothers Karamazov"_ or _"The Brothers Karamazov in Pictures"_ are +not returned by the search. + +That being said, we'll be using the `=` most heavily, and it's easier +to read. + +### any + +Using `any` means that any of your search terms (inside the double quotes) +can match. For example... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title any "Common Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 351777 An Inquiry into the Human Mind on the Principles o... +#> 2: 351777 The book of common prayer. +#> 3: 351777 Dictionary of Phrase and Fable +``` + +matches the title "The book of common prayer" (decidedly _not_ a book +of the subject of Common Lisp) since it has the word +"common" in it. (Note that capitalization doesn't matter). + +Using `any` in this context is tantamount to using an `or` boolean operator, +which we'll look at in the next section... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title = Common or $title = "Lisp"') +results[1:3, .(total_wc_results, title)] +#> total_wc_results title +#> +#> 1: 351777 An Inquiry into the Human Mind on the Principles o... +#> 2: 351777 The book of common prayer. +#> 3: 351777 Dictionary of Phrase and Fable +``` + +(Note the same number and order of results) + +### `all` + +Using the `all` operator means that _all_ of the search terms must match but +the search terms can be in any order and have intervening terms in between. +For example, search like `$title all "Common Lisp"` can match a (fictional) +book named _"Speaking with a lisp is common"_. + +### A quick note before continuing + +If your search term is one word, you do not have to use double quotes +to surround the term. For example, `$title = Ethics` and +`$title exact Ethics` work perfectly well. + +If your search term as a single quote in it, it must be escaped so +that R doesn't interpret it as the end of the search string. That +being said, it appears as if you can just drop the single quote +and the search will carry on perfectly fine... + +```{r, echo=FALSE} +# Sys.sleep(1) +``` + +```{r, eval=FALSE} +results <- worldcat_api_search('$title exact "Finnegans Wake"') +results[1:3, .(total_wc_results, title, query)] +#> total_wc_results title query +#> +#> 1: 761 Finnegans wake / srw.ti exact "Finnegans Wake" +#> 2: 761 Finnegans Wake srw.ti exact "Finnegans Wake" +#> 3: 761 Finnegans wake srw.ti exact "Finnegans Wake" + +# yields the same results as + +results <- worldcat_api_search('$title exact "Finnegan\'s Wake"') +results[1:3, .(total_wc_results, title, query)] +#> total_wc_results title query +#> +#> 1: 761 Finnegans wake / srw.ti exact "Finnegan's Wake" +#> 2: 761 Finnegans Wake srw.ti exact "Finnegan's Wake" +#> 3: 761 Finnegans wake srw.ti exact "Finnegan's Wake" + +``` + +I suspect single quotes are automatically elided by the API. + + +## Boolean operators (and operator precedence) + +As evinced in the examples shown earlier in this vignette, you can +use the boolean operators __and__, __or__, and __not__ to refine your +search. + +As you mix different boolean operators in a single query, care must be +taken to ensure that the order/precedence of these operators matches +your intention. + +For example, in one of the examples above, we searched for Hip Hop materials +on wax, cassette, or CD published from 1987 to 1990 with the following +SRU query + +``` +'(($material_type=cas or $material_type=cda or $material_type=lps) + and $subject="Rap") and $year="1987-1990"' +``` + +It's important to note that if we wrote the query like shown below + +``` +$material_type=cas or $material_type=cda or $material_type=lps + and $subject="Rap" and $year="1987-1990"' +``` + +without any parentheses, the meaning of the query would be ambiguous. +Make sure you use parentheses around distinct sections of your search +incantation to disambiguate the query. + +## Wildcards + +_taken verbatim from the archived documentation_ + +For right truncation use an asterisk - * There must be at least three +characters before the * for the query to work. There is no left truncation. + +To wildcard a single character wildcard use a number sign - #. So a query +for wom#n provides results that include both woman and women in the results. + +For a 0-9 number of characters as wildcard characters use ?n. So a query +for colo?1r provides results of color and colour. + +To wildcard characters within (or at the end) a term use the question +mark - ?. So a query for colo?r provides results of color, colour, colonizer, +and colorimeter. + +## Table of all available search indexes + + | Formal search index code | libbib alias | + |--------------------------|--------------| + | srw.kw | $keyword | + | srw.ti | $title | + | srw.ln | $language | + | srw.au | $author | + | srw.yr | $year | + | srw.su | $subject | + | srw.li | $holding_library | + | srw.mt | $material_type | + | srw.no | $oclc | + | srw.lc | $lc_call | + | srw.dd | $dewey | + | srw.dn | $lccn | + | srw.bn | $isbn | + | srw.in | $issn | + | srw.cg | $library_holdings_group | + | srw.la | $language_code | + | srw.pl | $place_of_publication | + | srw.pb | $publisher | + | srw.am | $access_method | + | srw.cn | $corporate_conference_name | + | srw.pc | $dlc_limit | + | srw.dt | $document_type | + | srw.gn | $government_document_number | + | srw.mn | $music_publisher_number | + | srw.nt | $notes | + | srw.on | $open_digital_limit | + | srw.pn | $personal_name | + | srw.se | $series | + | srw.sn | $standard_number | + + +## Selected Search Indexes in focus + +### $title / srw.ti + +According to the archived Search API documentation, (I have strong doubts) +the title search phrase will automatically elide certain common and +"un-important" words. In the field of Natural Language Processing, +we call these "stop words". + +The archive docs indicates that the following words will be removed +from the search phase: + +a, als, am, an, are, as, at, auf, aus, be, but, by, das, dass, de, der, +des, dich, dir, du, er, es, for, from, had, have, he, her, his, how, ihr, +ihre, ihres, im, in, is, ist, it, kein, la, le, les, mein, mich, mir, mit, +of, on, sein, sie, that, the, this, to, un, une, von, was, wer, which, wie, +wird, with, yousie, that, the, this, to, un, une, von, was, wer, which, wie, +wird, with, you. + +This means that title searches for _The Brothers Karamazov_, +_La Noche Boca Arriba_, _Das Spiel ist aus_, or _Das Kapital_ will, +alledgely, internally use the seach phrases _Brothers Karamazov_, +_Noche Boca Arriba_, _Spiel_, and _Kapital_, respectively. + +When searching the title index, though, I'd leave these words in the +SRU search query for two reasons... + + - It makes the title search phrase more readable, _especially_ with + non-english phrases. + + - I have strong doubts that all of these words are elided. For example, + a search for _Das Spiel ist aus_, yields results as if the search phrase + were indeed _Das Spiel ist aus_, and not as if it were simply _Spiel_. + +### $holding_library / srw.li + +As shown in one of the examples above, the holding library search term +is the official OCLC designator. You can search for an institution's +code by the institutions name [using this link.](https://www.oclc.org/en/contacts/libraries.html) + +### $material_type / srw.mt + +An exhaustive crosswalk of all material types and their (normally 3-letter) +codes would be too large to include here, but you can access the crosswalk +in the documentation that is archived [at this link](https://web.archive.org/web/20210426232556/https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en%3E) + +### $library_holdings_group / srw.cg + +The "library holdings group" search term is, perhaps, a confusing one. +The table below is a crosswalk between the search codes to use in the +SRU query, and what they mean. + + | Search code | Meaning | + |-------------|---------| + | 05 | 5 or more holdings | + | 06 | 10 or more holdings | + | 07 | 50 or more holdings | + | 08 | 100 or more holdings | + | 09 | 500 or more holdings | + | 10 | No holdings | + | 11 | 1 holding only | + | 12 | 2 – 4 holdings | + | 13 | 5 – 9 holdings | + | 14 | 10 – 24 holdings | + | 15 | 25 – 49 holdings | + | 16 | 50 - 74 holdings | + | 17 | 75 – 99 holdings | + | 18 | 100 - 149 holdings | + | 19 | 150 - 199 holdings | + | 20 | 200 - 299 holdings | + | 21 | 300 - 399 holdings | + | 22 | 400 - 499 holdings | + | 23 | 500 - 599 holdings | + | 24 | 600 - 699 holdings | + | 25 | 700 - 799 holdings | + | 26 | 800 - 899 holdings | + | 27 | 900 - 999 holdings | + | 28 | 1,000 - 1,499 holdings | + | 29 | 1,500 - 1,999 holdings | + | 30 | 2,000 - 2,499 holdings | + | 31 | 2,500 or more holdings | + +So, for example, if you wanted to limit your search to +items that are held by between 100 to 149 institutions, +you would have to add `$library_holdings_group=18` to +your SRU query. + +### others + +For all the available search indexes, it is very helpful to know which +exact MARC fields are searched in each one. +[This archived documentation link](https://web.archive.org/web/20130915101232/http://oclc.org/developer/documentation/worldcat-search-api/complete-list-indexes) contains that information. + +On that page, the SRU index codes have a prefix of `sru`, but it's really +`srw`. +Consult the _Table of all available search indexes_ above to find the libbib +aliases for the indexes of interest (though, of course, you can use the +un-translated index codes if you'd like, too). + +----- + +## Options in the `worldcat_api_search` function + +Besides for, of course, the SRU query, the `worldcat_api_search` function +takes a number of optional parameters that can be used to alter its semantics. +Below is a list and explanation of each of those parameters. +(This information is also available by running +`help("worldcat_api_search")` in an R console after loading the `libbib` +package.) + + - __max_records__ + The maximum number of search results to return. This must be a number + between 0 and 100 or `Inf`. If `Inf`, the function will automatically + make all follow-up requests to retrieve all search results. + To limit the number of times the API is hit, the default is 10 search + results. + + - __sru_query_assist__ + A logical (boolean) indicating whether translation from more human-readable + aliases to the SRU search index codes should be allowed. The default + is `TRUE`. It can also be set to `FALSE`. + You can control this parameter globally by setting + `options("libbib.sru_query_assist")`. + + - __frbrGrouping__ + FRBR (_Functional Requirements for Bibliographic Records_) is a conceptual + framework for understanding the relationships between a "work" (e.g. a + novel as planned by an author), its "expression" (e.g. the manuscript of + that novel), it's "manifestation" (e.g. the first published version of + the novel), and, finally, an "item" (e.g an actual physical book + [or microform; audio file; etc...] of the work). + With the `frbrGrouping` parameter set to `on` (default), an attempt is + made by the WorldCat API to group together similar editions and present + only the top held record as the representative record for that group. + This, conceptually, can be viewed as an attempt to return search results for + any expression of the "work" (or works) referred to in the search query. + + - __start_at__ + The search result to start at (default is 1) + + - __wskey__ + A WorldCat API key. This function is easiest to use by setting the + wskey globally, with the following incantation: + `options(libbib.wskey="YOUR WSKEY GOES HERE")` + + - __more__ + A logical indicating whether more information from the MARCXML + search results should be returned (publisher, bib level, etc....). + The default is `TRUE`. + + - __print.progress__ + A logical indicating whether a message should be displayed for each + API request. If `max_records` is `Inf` a message will be displayed for + every group of 100 search results the function fetches. The default is + `TRUE`. + + - __debug__ + A logical indicating whether the HTTP and API responses should be printed + (for debugging). The default is `FALSE`. + + +## Combining this with the other API search functions in `libbib` + +There are numerous ways to combine the `worldcat_api_search` with the +other functions that `libbib` provides to do some really useful +investigations. In the example below, will be using the +`worldcat_api_search` and `worldcat_api_locations_by_oclc` functions to +get a list of institutions that hold any edition of my textbook. (This +example uses some `data.table` specific syntax for brevity, but it will +work with base R [or "tidyverse"] translations just fine.) + +First, let's use the search function to get a list of all search results +for the book... + +```{r, eval=FALSE} +results <- worldcat_api_search('srw.ti="Data Analysis with r" + and srw.au=fischetti', + max_records=Inf) + +# inspect some of the columns in the first 5 results +results[1:5, .(total_wc_results, result_number, oclc, + title, author, pub_date) +#> total_wc_results result_number oclc title +#> +#> 1: 11 1 1005106045 DATA ANALYSIS WITH R -. +#> 2: 11 2 1089176194 Data analysis with R : +#> 3: 11 3 949229431 Data analysis with R : +#> 4: 11 4 1242682069 Data Analysis with R +#> 5: 11 5 1242707288 Data Analysis with R +#> author pub_date +#> +#> 1: FISCHETTI, TONY. 2018 +#> 2: Fischetti, Tony. 2018 +#> 3: Fischetti, Tony. 2015 +#> 4: Fischetti, Tony 2015 +#> 5: Fischetti, Tony 2015 +``` + +Now let's get all the unique OCLC numbers from all the search results. + +```{r, eval=FALSE} +all_the_oclcs <- results[, unique(oclc)] +all_the_oclcs +#> [1] "1005106045" "1089176194" "949229431" "1242682069" "1242707288" +#> [6] "1244405806" "1104264768" "1242685020" "1242707684" "1244406814" +#> [11] "1104846312" +``` + +On to the `worldcat_api_locations_by_oclc` function! +Since this function takes one OCLC number at a time, we need to use +a looping-construct to run the function with _all_ the OCLC numbers +in `all_the_oclcs`. +We'll be using the `pblapply` function (from the great `pbapply` package) +to do this because we get a useful progress bar with no extra effort. + +```{r, eval=FALSE} +holds <- pblapply(all_the_oclcs, + function(x){ + worldcat_api_locations_by_oclc(x, + include.bib.info=FALSE) + }) +``` + +Since the `pblapply` function returns a list of `data.tables` (on for each +OCLC), we'll use `data.table`'s `rbindlist` function to one `data.table` +containing all the results. + +```{r, eval=FALSE} +all_holdings_dt <- rbindlist(holds) +all_holdings_dt[1:3] +#> oclc institution_identifier institution_name copies +#> +#> 1: 1005106045 FEM The Ferguson Library 1 +#> 2: 1005106045 YDX YBP Library Services 1 +#> 3: 1005106045 DUQ Duquesne University Library 1 + +all_holdings_dt[, .(institution_name)] +#> institution_name +#> +#> 1: The Ferguson Library +#> 2: YBP Library Services +#> 3: Duquesne University Library +#> 4: Centennial College +#> 5: George Brown College +#> --- +#> 1029: Hochschule Mittweida (FH), Hochschulbibliothek +#> 1030: Cyberlibris +#> 1031: Cyberlibris +#> 1032: Cyberlibris +#> 1033: BibliothĂšque de l'UniversitĂ© du QuĂ©bec Ă  Trois-Riv... +``` + +There you have it! My textbook is held by 1033 distinct OCLC institutions! + +Although the example above only searches the holding institutions of one +specific book, the idiom is most helpful/interesting/cool when used for +finding the holding institution of a entire class of materials. + +For example, in a recent project for a curator at my institution, I used +the Search API to find all search results for materials on a very specific +topic, got all the holding institutions for each of the search results, and +then aggregated the institutions (with this package's `dt_counts_and_percents` +function) to find the institutions holding the most items on this particular +(very specific) topic. + +----- + +## Sundry external / archived documentation links + + +- __WorldCat Search API current documentation__ + + _scroll to SRU_ + + Current documentation on the (SRU) WorldCat Search API call. Contains all + index names and codes, parameters available, and the meaning of API + status code return numbers + + + + +- __WorldCat Search API > Using the API > Request Types > SRU__ + + _(archived OCLC documentation link from 2013)_ + + Examples of simple SRU requests and explanation of `frbrGrouping` + and `servicelevel` parameters + + + + +- __WorldCat Search API > Indexes__ + + _(archived OCLC documentation link from 2013)_ + + Explation of relations operators, boolean operators, title index + stop-words (removed words), the MARC subfields search by (only) the subject + index, and explation of the wildcard characters `*`; `#`; and `?`. + + + + +- __WorldCat Search API > Indexes > Complete List of Indexes__ + + _(archived OCLC documentation link from 2013)_ + + Explation of relations operators and a complete list of all indexes, their + respective SRU index code, the relations available for use with each, and + the MARC fields search for each index. Here, the SRU index codes have a + prefix of `sru`, but it's really `srw`. + + + + +- __Material Types Names and Codes__ + + A complete list of Material Types you can search for, their codes + + For use with the `srw.mt`/`$material_type` index. + + [Material Type names and codes - OCLC Support](https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en) + + [Archived from original for posterity](https://web.archive.org/web/20210425140401/https://help.oclc.org/Librarian_Toolbox/Searching_WorldCat_Indexes/Bibliographic_records/Material_Type_names_and_codes?sl=en>) + + +- __WorldCat Search API > Indexes > Tips for specific indexes__ + + _(archived OCLC documentation link from 2013)_ + + Contains a lot of very helpful information about some of the different + search indexes, the stop words they use, normalization rules, and + a very helpful cross-walk on the "Number of Holding Libraries" index. + + + + +- __WorldCat Search API > Using the API > Parameters__ + + _(archived OCLC documentation link from 2013)_ + + Helpful information about what the different SRU search parameters mean. + Remember that the parameters of the `worldcat_api_search` function (a) only + contain a subset of these, and (b) may have slightly different names + + + +- __Finding Institution Codes__ + + A search box for searching institution names and returning instituion + codes suitable for use in the holding institution search index. + + + + +- __Searching WorldCat Indexes__ + + _(archived OCLC documentation link from 2012)_ + + Information about search indexes that are largely available in the above + links. Not related to the (SRU) Search API but could be helpful, anyway. + + + + +- __CQL specification__ + + Helpful information about CQL query syntax. Not all is applicable to + the WorldCat Search API that is discussed here. + + + + +- __Searching WorldCat Indexes__ + + Current page with links containing a lot of information about + wielding WorldCat searches. Not all information is application to + the WorldCat Search API that is discussed here, and most of the + most helpful information is already covered in the links above. + + + + + +## Similar projects / code + +- __A Ruby Gem to communicate with the WorldCat Search API__ + + + + +- __Python scripts using the WorldCat search API__ + + + + +## Papers/Articles + +- __Using the WorldCat API to Develop Data-Driven Decision-Making for Gifts-in-Kind__ + + + + +- __Destroyer and Preserver, Hear, Oh Hear! Not All Uncirculated Books Must Chariotest to a Dark Wintry Bed: How We Used the Books Must Chariotest to a Dark Wintry Bed: How We Used the OCLC WorldCat Search API to Inform Our Weeding Decisions with OCLC WorldCat Search API to Inform Our Weeding Decisions with Holdings Data Holdings Data__ + + diff --git a/libbib.Rcheck/00check.log b/libbib.Rcheck/00check.log new file mode 100644 index 0000000..544f068 --- /dev/null +++ b/libbib.Rcheck/00check.log @@ -0,0 +1,93 @@ +* using log directory ‘/usr/local/google/home/chiricom/git/libbib/libbib.Rcheck’ +* using R Under development (unstable) (2026-08-15 r90413) +* using platform: x86_64-pc-linux-gnu +* R was compiled by + gcc (Debian 15.2.0-8) 15.2.0 + GNU Fortran (Debian 15.2.0-8) 15.2.0 +* running under: Debian GNU/Linux rodete +* using session charset: UTF-8 +* current time: 2026-08-18 23:47:58 UTC +* using option ‘--as-cran’ +* checking for file ‘libbib/DESCRIPTION’ ... OK +* checking extension type ... Package +* this is package ‘libbib’ version ‘1.6.4’ +* package encoding: UTF-8 +* checking CRAN incoming feasibility ... [12s/17s] WARNING +Maintainer: ‘Tony Fischetti ’ + +Insufficient package version (submitted: 1.6.4, existing: 1.6.4) + +Found the following (possibly) invalid URLs: + URL: https://www.worldcat.org/advancedsearch (moved to https://search.worldcat.org/advancedsearch) + From: inst/doc/using-the-worldcat-search-api.html + Status: 301 + Message: Moved Permanently +For content that is 'Moved Permanently', please change http to https, +add trailing slashes, or replace the old by the new URL. +* checking package namespace information ... OK +* checking package dependencies ... OK +* checking if this is a source package ... OK +* checking if there is a namespace ... OK +* checking for executable files ... OK +* checking for hidden files and directories ... OK +* checking for portable file names ... OK +* checking for sufficient/correct file permissions ... OK +* checking whether package ‘libbib’ can be installed ... OK +* checking installed package size ... OK +* checking package directory ... OK +* checking for future file timestamps ... OK +* checking ‘build’ directory ... OK +* checking DESCRIPTION meta-information ... OK +* checking top-level files ... NOTE +Non-standard file/directory found at top level: + ‘Makefile’ +* checking for left-over files ... OK +* checking index information ... OK +* checking package subdirectories ... OK +* checking code files for non-ASCII characters ... OK +* checking R files for syntax errors ... OK +* checking whether the package can be loaded ... OK +* checking whether the package can be loaded with stated dependencies ... OK +* checking whether the package can be unloaded cleanly ... OK +* checking whether the namespace can be loaded with stated dependencies ... OK +* checking whether the namespace can be unloaded cleanly ... OK +* checking loading without being on the library search path ... OK +* checking use of S3 registration ... OK +* checking dependencies in R code ... OK +* checking S3 generic/method consistency ... OK +* checking replacement functions ... OK +* checking foreign function calls ... OK +* checking R code for possible problems ... OK +* checking Rd files ... OK +* checking Rd metadata ... OK +* checking Rd line widths ... OK +* checking Rd cross-references ... OK +* checking for missing documentation entries ... OK +* checking for code/documentation mismatches ... OK +* checking Rd \usage sections ... OK +* checking Rd contents ... OK +* checking for unstated dependencies in examples ... OK +* checking contents of ‘data’ directory ... OK +* checking data for non-ASCII characters ... OK +* checking data for ASCII and uncompressed saves ... OK +* checking line endings in Makefiles ... OK +* checking for GNU extensions in Makefiles ... OK +* checking include directives in Makefiles ... OK +* checking installed files from ‘inst/doc’ ... OK +* checking files in ‘vignettes’ ... OK +* checking examples ... NOTE +Examples with CPU (user + system) or elapsed time > 5s + user system elapsed +check_isbn_10_check_digit 6.927 0.018 0.202 +* checking for unstated dependencies in ‘tests’ ... OK +* checking tests ... OK + Running ‘testthat.R’ +* checking for unstated dependencies in vignettes ... OK +* checking package vignettes ... OK +* checking re-building of vignette outputs ... OK +* checking PDF version of manual ... OK +* checking HTML version of manual ... OK +* checking for non-standard things in the check directory ... OK +* checking for detritus in the temp directory ... OK +* DONE +Status: 1 WARNING, 2 NOTEs diff --git a/libbib.Rcheck/R_check_bin/R b/libbib.Rcheck/R_check_bin/R new file mode 100755 index 0000000..3e289bc --- /dev/null +++ b/libbib.Rcheck/R_check_bin/R @@ -0,0 +1,2 @@ +echo "'R' should not be used without a path -- see par. 1.6 of the manual" +exit 1 diff --git a/libbib.Rcheck/R_check_bin/Rscript b/libbib.Rcheck/R_check_bin/Rscript new file mode 100755 index 0000000..6fead74 --- /dev/null +++ b/libbib.Rcheck/R_check_bin/Rscript @@ -0,0 +1,2 @@ +echo "'Rscript' should not be used without a path -- see par. 1.6 of the manual" +exit 1 diff --git a/libbib.Rcheck/Rdlatex.log b/libbib.Rcheck/Rdlatex.log new file mode 100644 index 0000000..a3155ca --- /dev/null +++ b/libbib.Rcheck/Rdlatex.log @@ -0,0 +1,515 @@ +Hmm ... looks like a package +Converting parsed Rd's to LaTeX ..... +Creating pdf output from LaTeX ... + +This is pdfTeX, Version 3.141592653-2.6-1.40.29 (TeX Live 2026/Debian) (preloaded format=pdflatex) + restricted \write18 enabled. +entering extended mode +LaTeX2e <2025-11-01> +L3 programming layer <2026-01-19> +(./Rd2.tex +(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls +Document Class: book 2025/01/22 v1.4n Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo)) +(/usr/local/google/home/chiricom/svn/r-devel/share/texmf/tex/latex/Rd.sty +(/usr/share/texlive/texmf-dist/tex/latex/base/ifthen.sty) +(/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/bm.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty) +(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/textcomp.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/mathrsfs.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/fontenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/times.sty) +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/zi4.sty +`inconsolata-zi4' v1.12, 2019/05/17 Text macros for Inconsolata (msharpe) +(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex))))) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty +(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg) +(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/mathcolor.ltx)) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvsetkeys/kvsetkeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/kvdefinekeys/kvdefinekeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdfescape/pdfescape.sty +(/usr/share/texlive/texmf-dist/tex/generic/ltxcmds/ltxcmds.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdftexcmds/pdftexcmds.sty +(/usr/share/texlive/texmf-dist/tex/generic/infwarerr/infwarerr.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hycolor/hycolor.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty +(/usr/share/texlive/texmf-dist/tex/latex/refcount/refcount.sty) +(/usr/share/texlive/texmf-dist/tex/generic/gettitlestring/gettitlestring.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvoptions/kvoptions.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/etoolbox/etoolbox.sty) +(/usr/share/texlive/texmf-dist/tex/generic/stringenc/stringenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def) +(/usr/share/texlive/texmf-dist/tex/generic/intcalc/intcalc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/puenc.def) +(/usr/share/texlive/texmf-dist/tex/generic/bitset/bitset.sty +(/usr/share/texlive/texmf-dist/tex/generic/bigintcalc/bigintcalc.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def +(/usr/share/texlive/texmf-dist/tex/latex/rerunfilecheck/rerunfilecheck.sty +(/usr/share/texlive/texmf-dist/tex/generic/uniquecounter/uniquecounter.sty)))) +(/usr/share/texlive/texmf-dist/tex/latex/base/makeidx.sty) +Writing index file Rd2.idx +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/t1ptm.fd) +(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def) +No file Rd2.aux. +(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +) (/usr/share/texlive/texmf-dist/tex/latex/inconsolata/t1zi4.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/ursfs.fd) +No file Rd2.toc. +[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}{/usr/share/texlive/texmf- +dist/fonts/enc/dvips/base/8r.enc}{/usr/share/texlive/texmf-dist/fonts/enc/dvips +/inconsolata/i4-t1-0.enc}] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/ts1zi4.fd) [13{/usr/share/ +texlive/texmf-dist/fonts/enc/dvips/inconsolata/i4-ts1.enc}] [14] [15] [16] +[17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] +[32] [33] [34] [35] [36] +Overfull \hbox (17.27782pt too wide) in paragraph at lines 2136--2136 + []\T1/zi4/m/n/9 # "http://classify.oclc.org/classify2/ClassifyDemo?search-stan +dnum-txt=629725006&startRec=0"[] + +Overfull \hbox (38.27475pt too wide) in paragraph at lines 2139--2139 + []\T1/zi4/m/n/9 # [1] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=039333712X&startRec=0"[] + +Overfull \hbox (33.77475pt too wide) in paragraph at lines 2141--2141 + []\T1/zi4/m/n/9 # [3] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=629725006&startRec=0"[] +[37] [38] [39] [40] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2409--2409 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)})[] +[41] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2415--2415 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] + +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2425--2425 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] +[42] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2507--2511 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[43] [44] +Overfull \hbox (30.85889pt too wide) in paragraph at lines 2655--2663 +\T1/ptm/m/n/10 tu-tion, and, by de-fault, the bib-li-o-graphic in-for-ma-tion p +ro-vided by []\T1/zi4/m/n/10 worldcat_api_bib_read_info_by_...[]\T1/ptm/m/n/10 +. +[45] [46] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2787--2791 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[47] [48] +Overfull \hbox (91.14795pt too wide) in paragraph at lines 2901--2903 +[]\T1/ptm/m/n/10 There is an en-tire vi-gnette ded-i-cated to this func-tion; t +o view it, ex-e-cute []\T1/zi4/m/n/10 vignette("using-the-worldcat-search-api") + + +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2918--2922 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[49] [50] [51] +No file Rd2.ind. +[52] (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.aux) + +Package rerunfilecheck Warning: File `Rd2.out' has changed. +(rerunfilecheck) Rerun to get outlines right +(rerunfilecheck) or use package `bookmark'. + + ) +(see the transcript file for additional information) +pdfTeX warning (dest): name{Rfn.paste} has been referenced but does not exist, +replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.make.unique} has been referenced but does not e +xist, replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.is.na} has been referenced but does not exist, +replaced by a fixed one + + +Output written on Rd2.pdf (52 pages, 173363 bytes). +Transcript written on Rd2.log. +This is makeindex, version 2.18 [TeX Live 2026] (kpathsea + Thai support). +Scanning input file Rd2.idx....done (91 entries accepted, 0 rejected). +Sorting entries....done (620 comparisons). +Generating output file Rd2.ind....done (145 lines written, 0 warnings). +Output written in Rd2.ind. +Transcript written in Rd2.ilg. +This is pdfTeX, Version 3.141592653-2.6-1.40.29 (TeX Live 2026/Debian) (preloaded format=pdflatex) + restricted \write18 enabled. +entering extended mode +LaTeX2e <2025-11-01> +L3 programming layer <2026-01-19> +(./Rd2.tex +(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls +Document Class: book 2025/01/22 v1.4n Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo)) +(/usr/local/google/home/chiricom/svn/r-devel/share/texmf/tex/latex/Rd.sty +(/usr/share/texlive/texmf-dist/tex/latex/base/ifthen.sty) +(/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/bm.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty) +(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/textcomp.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/mathrsfs.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/fontenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/times.sty) +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/zi4.sty +`inconsolata-zi4' v1.12, 2019/05/17 Text macros for Inconsolata (msharpe) +(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex))))) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty +(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg) +(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/mathcolor.ltx)) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvsetkeys/kvsetkeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/kvdefinekeys/kvdefinekeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdfescape/pdfescape.sty +(/usr/share/texlive/texmf-dist/tex/generic/ltxcmds/ltxcmds.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdftexcmds/pdftexcmds.sty +(/usr/share/texlive/texmf-dist/tex/generic/infwarerr/infwarerr.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hycolor/hycolor.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty +(/usr/share/texlive/texmf-dist/tex/latex/refcount/refcount.sty) +(/usr/share/texlive/texmf-dist/tex/generic/gettitlestring/gettitlestring.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvoptions/kvoptions.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/etoolbox/etoolbox.sty) +(/usr/share/texlive/texmf-dist/tex/generic/stringenc/stringenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def) +(/usr/share/texlive/texmf-dist/tex/generic/intcalc/intcalc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/puenc.def) +(/usr/share/texlive/texmf-dist/tex/generic/bitset/bitset.sty +(/usr/share/texlive/texmf-dist/tex/generic/bigintcalc/bigintcalc.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def +(/usr/share/texlive/texmf-dist/tex/latex/rerunfilecheck/rerunfilecheck.sty +(/usr/share/texlive/texmf-dist/tex/generic/uniquecounter/uniquecounter.sty)))) +(/usr/share/texlive/texmf-dist/tex/latex/base/makeidx.sty) +Writing index file Rd2.idx +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/t1ptm.fd) +(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.aux) +(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +) (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.out) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.out) +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/t1zi4.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/ursfs.fd) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.toc [1{/var/lib/texmf/fonts/map/pdftex/ +updmap/pdftex.map}{/usr/share/texlive/texmf-dist/fonts/enc/dvips/base/8r.enc}{/ +usr/share/texlive/texmf-dist/fonts/enc/dvips/inconsolata/i4-t1-0.enc}]) +[2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/ts1zi4.fd) [14{/usr/share/ +texlive/texmf-dist/fonts/enc/dvips/inconsolata/i4-ts1.enc}] [15] [16] [17] +[18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] +[33] [34] [35] [36] [37] +Overfull \hbox (17.27782pt too wide) in paragraph at lines 2136--2136 + []\T1/zi4/m/n/9 # "http://classify.oclc.org/classify2/ClassifyDemo?search-stan +dnum-txt=629725006&startRec=0"[] + +Overfull \hbox (38.27475pt too wide) in paragraph at lines 2139--2139 + []\T1/zi4/m/n/9 # [1] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=039333712X&startRec=0"[] + +Overfull \hbox (33.77475pt too wide) in paragraph at lines 2141--2141 + []\T1/zi4/m/n/9 # [3] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=629725006&startRec=0"[] +[38] [39] [40] [41] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2409--2409 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)})[] +[42] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2415--2415 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] + +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2425--2425 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] +[43] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2507--2511 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[44] [45] +Overfull \hbox (30.85889pt too wide) in paragraph at lines 2655--2663 +\T1/ptm/m/n/10 tu-tion, and, by de-fault, the bib-li-o-graphic in-for-ma-tion p +ro-vided by []\T1/zi4/m/n/10 worldcat_api_bib_read_info_by_...[]\T1/ptm/m/n/10 +. +[46] [47] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2787--2791 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[48] [49] +Overfull \hbox (91.14795pt too wide) in paragraph at lines 2901--2903 +[]\T1/ptm/m/n/10 There is an en-tire vi-gnette ded-i-cated to this func-tion; t +o view it, ex-e-cute []\T1/zi4/m/n/10 vignette("using-the-worldcat-search-api") + + +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2918--2922 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[50] [51] [52] (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.ind [53] + +LaTeX Font Warning: Font shape `T1/zi4/m/it' undefined +(Font) using `T1/zi4/m/n' instead on input line 119. + + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 119--121 +\T1/ptm/m/it/10 (\T1/zi4/m/n/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 )\ +T1/ptm/m/n/10 , + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 121--123 +\T1/ptm/m/it/10 (\T1/zi4/m/it/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 ) +\T1/ptm/m/n/10 , + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 123--125 +\T1/ptm/m/it/10 (\T1/zi4/m/it/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 ) +\T1/ptm/m/n/10 , +[54] [55]) (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.aux) + +LaTeX Font Warning: Some font shapes were not available, defaults substituted. + + +Package rerunfilecheck Warning: File `Rd2.out' has changed. +(rerunfilecheck) Rerun to get outlines right +(rerunfilecheck) or use package `bookmark'. + + ) +(see the transcript file for additional information) +pdfTeX warning (dest): name{Rfn.paste} has been referenced but does not exist, +replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.make.unique} has been referenced but does not e +xist, replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.is.na} has been referenced but does not exist, +replaced by a fixed one + + +Output written on Rd2.pdf (55 pages, 194728 bytes). +Transcript written on Rd2.log. +This is makeindex, version 2.18 [TeX Live 2026] (kpathsea + Thai support). +Scanning input file Rd2.idx....done (91 entries accepted, 0 rejected). +Sorting entries....done (620 comparisons). +Generating output file Rd2.ind....done (145 lines written, 0 warnings). +Output written in Rd2.ind. +Transcript written in Rd2.ilg. +This is pdfTeX, Version 3.141592653-2.6-1.40.29 (TeX Live 2026/Debian) (preloaded format=pdflatex) + restricted \write18 enabled. +entering extended mode +LaTeX2e <2025-11-01> +L3 programming layer <2026-01-19> +(./Rd2.tex +(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls +Document Class: book 2025/01/22 v1.4n Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo)) +(/usr/local/google/home/chiricom/svn/r-devel/share/texmf/tex/latex/Rd.sty +(/usr/share/texlive/texmf-dist/tex/latex/base/ifthen.sty) +(/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/longtable.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/bm.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/alltt.sty) +(/usr/share/texlive/texmf-dist/tex/latex/tools/verbatim.sty) +(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/textcomp.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty +For additional information on amsmath, use the `?' option. +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty)) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amsfonts.sty) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/amssymb.sty) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/mathrsfs.sty) +(/usr/share/texlive/texmf-dist/tex/latex/base/fontenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/times.sty) +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/zi4.sty +`inconsolata-zi4' v1.12, 2019/05/17 Text macros for Inconsolata (msharpe) +(/usr/share/texlive/texmf-dist/tex/latex/xkeyval/xkeyval.sty +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkeyval.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/xkvutils.tex +(/usr/share/texlive/texmf-dist/tex/generic/xkeyval/keyval.tex))))) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty +(/usr/share/texlive/texmf-dist/tex/latex/graphics-cfg/color.cfg) +(/usr/share/texlive/texmf-dist/tex/latex/graphics-def/pdftex.def) +(/usr/share/texlive/texmf-dist/tex/latex/graphics/mathcolor.ltx)) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvsetkeys/kvsetkeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/kvdefinekeys/kvdefinekeys.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdfescape/pdfescape.sty +(/usr/share/texlive/texmf-dist/tex/generic/ltxcmds/ltxcmds.sty) +(/usr/share/texlive/texmf-dist/tex/generic/pdftexcmds/pdftexcmds.sty +(/usr/share/texlive/texmf-dist/tex/generic/infwarerr/infwarerr.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hycolor/hycolor.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty +(/usr/share/texlive/texmf-dist/tex/latex/refcount/refcount.sty) +(/usr/share/texlive/texmf-dist/tex/generic/gettitlestring/gettitlestring.sty +(/usr/share/texlive/texmf-dist/tex/latex/kvoptions/kvoptions.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/etoolbox/etoolbox.sty) +(/usr/share/texlive/texmf-dist/tex/generic/stringenc/stringenc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def) +(/usr/share/texlive/texmf-dist/tex/generic/intcalc/intcalc.sty) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/puenc.def) +(/usr/share/texlive/texmf-dist/tex/generic/bitset/bitset.sty +(/usr/share/texlive/texmf-dist/tex/generic/bigintcalc/bigintcalc.sty))) +(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def +(/usr/share/texlive/texmf-dist/tex/latex/rerunfilecheck/rerunfilecheck.sty +(/usr/share/texlive/texmf-dist/tex/generic/uniquecounter/uniquecounter.sty)))) +(/usr/share/texlive/texmf-dist/tex/latex/base/makeidx.sty) +Writing index file Rd2.idx +(/usr/share/texlive/texmf-dist/tex/latex/psnfss/t1ptm.fd) +(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.aux) +(/usr/share/texlive/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +) (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.out) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.out) +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/t1zi4.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsa.fd) +(/usr/share/texlive/texmf-dist/tex/latex/amsfonts/umsb.fd) +(/usr/share/texlive/texmf-dist/tex/latex/jknapltx/ursfs.fd) +(/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.toc [1{/var/lib/texmf/fonts/map/pdftex/ +updmap/pdftex.map}{/usr/share/texlive/texmf-dist/fonts/enc/dvips/base/8r.enc}{/ +usr/share/texlive/texmf-dist/fonts/enc/dvips/inconsolata/i4-t1-0.enc}]) +[2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] +(/usr/share/texlive/texmf-dist/tex/latex/inconsolata/ts1zi4.fd) [14{/usr/share/ +texlive/texmf-dist/fonts/enc/dvips/inconsolata/i4-ts1.enc}] [15] [16] [17] +[18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] +[33] [34] [35] [36] [37] +Overfull \hbox (17.27782pt too wide) in paragraph at lines 2136--2136 + []\T1/zi4/m/n/9 # "http://classify.oclc.org/classify2/ClassifyDemo?search-stan +dnum-txt=629725006&startRec=0"[] + +Overfull \hbox (38.27475pt too wide) in paragraph at lines 2139--2139 + []\T1/zi4/m/n/9 # [1] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=039333712X&startRec=0"[] + +Overfull \hbox (33.77475pt too wide) in paragraph at lines 2141--2141 + []\T1/zi4/m/n/9 # [3] "http://classify.oclc.org/classify2/ClassifyDemo?search- +standnum-txt=629725006&startRec=0"[] +[38] [39] [40] [41] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2409--2409 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)})[] +[42] +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2415--2415 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] + +Overfull \hbox (42.77475pt too wide) in paragraph at lines 2425--2425 + []\T1/zi4/m/n/9 split_map_filter_reduce(someisbns, mapfun=function(x){normaliz +e_isbn(x, convert.to.isbn.13=TRUE)},[] +[43] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2507--2511 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[44] [45] +Overfull \hbox (30.85889pt too wide) in paragraph at lines 2655--2663 +\T1/ptm/m/n/10 tu-tion, and, by de-fault, the bib-li-o-graphic in-for-ma-tion p +ro-vided by []\T1/zi4/m/n/10 worldcat_api_bib_read_info_by_...[]\T1/ptm/m/n/10 +. +[46] [47] +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2787--2791 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[48] [49] +Overfull \hbox (91.14795pt too wide) in paragraph at lines 2901--2903 +[]\T1/ptm/m/n/10 There is an en-tire vi-gnette ded-i-cated to this func-tion; t +o view it, ex-e-cute []\T1/zi4/m/n/10 vignette("using-the-worldcat-search-api") + + +Overfull \hbox (5.24847pt too wide) in paragraph at lines 2918--2922 +\T1/ptm/m/n/10 way to use these func-tions is to set a global op-tions with you +r key: []\T1/zi4/m/n/10 options("libbib.wskey"="YOUR +[50] [51] [52] (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.ind [53] + +LaTeX Font Warning: Font shape `T1/zi4/m/it' undefined +(Font) using `T1/zi4/m/n' instead on input line 119. + + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 119--121 +\T1/ptm/m/it/10 (\T1/zi4/m/n/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 )\ +T1/ptm/m/n/10 , + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 121--123 +\T1/ptm/m/it/10 (\T1/zi4/m/it/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 ) +\T1/ptm/m/n/10 , + +Overfull \hbox (5.01662pt too wide) in paragraph at lines 123--125 +\T1/ptm/m/it/10 (\T1/zi4/m/it/10 worldcat_api_bib_read_info_by\T1/ptm/m/it/10 ) +\T1/ptm/m/n/10 , +[54] [55]) (/tmp/RtmpxmMqOy/Rd2pdf6b0456238221/Rd2.aux) + +LaTeX Font Warning: Some font shapes were not available, defaults substituted. + + ) +(see the transcript file for additional information) +pdfTeX warning (dest): name{Rfn.paste} has been referenced but does not exist, +replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.make.unique} has been referenced but does not e +xist, replaced by a fixed one + + +pdfTeX warning (dest): name{Rfn.is.na} has been referenced but does not exist, +replaced by a fixed one + + +Output written on Rd2.pdf (55 pages, 195491 bytes). +Transcript written on Rd2.log. +Saving output to ‘libbib-manual.pdf’ ... +Done +You may want to clean up by 'rm -Rf /tmp/RtmpxmMqOy/Rd2pdf6b0456238221' diff --git a/libbib.Rcheck/libbib-Ex.R b/libbib.Rcheck/libbib-Ex.R new file mode 100644 index 0000000..cb21eac --- /dev/null +++ b/libbib.Rcheck/libbib-Ex.R @@ -0,0 +1,1573 @@ +pkgname <- "libbib" +source(file.path(R.home("share"), "R", "examples-header.R")) +options(warn = 1) +base::assign(".ExTimings", "libbib-Ex.timings", pos = 'CheckExEnv') +base::cat("name\tuser\tsystem\telapsed\n", file=base::get(".ExTimings", pos = 'CheckExEnv')) +base::assign(".format_ptime", +function(x) { + if(!is.na(x[4L])) x[1L] <- x[1L] + x[4L] + if(!is.na(x[5L])) x[2L] <- x[2L] + x[5L] + options(OutDec = '.') + format(x[1L:3L], digits = 7L) +}, +pos = 'CheckExEnv') + +### * +library('libbib') + +base::assign(".oldSearch", base::search(), pos = 'CheckExEnv') +base::assign(".old_wd", base::getwd(), pos = 'CheckExEnv') +cleanEx() +nameEx("car") +### * car + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: car +### Title: Return first element of vector +### Aliases: car + +### ** Examples + +library(data.table) +car(c(8, 6, 7, 5, 3, 0, 9)) # 8 +mt <- as.data.table(mtcars) +dt_del_cols(mt, "cyl", "disp", "hp") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("car", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("check_isbn_10_check_digit") +### * check_isbn_10_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: check_isbn_10_check_digit +### Title: Check the check digit of an ISBN 10 +### Aliases: check_isbn_10_check_digit + +### ** Examples + + +check_isbn_10_check_digit("012491540X") # TRUE +check_isbn_10_check_digit("0-124-91540-X") # TRUE + +# vectorized +check_isbn_10_check_digit(c("012491540X", "9004037812")) # TRUE FALSE + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("check_isbn_10_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("check_isbn_13_check_digit") +### * check_isbn_13_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: check_isbn_13_check_digit +### Title: Check the check digit of an ISBN 13 +### Aliases: check_isbn_13_check_digit + +### ** Examples + + +check_isbn_13_check_digit("9780306406157") # TRUE +check_isbn_13_check_digit("978-0-306-40615-7") # TRUE + +# vectorized +check_isbn_13_check_digit(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("check_isbn_13_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("check_issn_check_digit") +### * check_issn_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: check_issn_check_digit +### Title: Check the check digit of an ISSN +### Aliases: check_issn_check_digit + +### ** Examples + + +check_issn_check_digit("2434561X") # TRUE +check_issn_check_digit("2434-561X") # TRUE + +# vectorized +check_issn_check_digit(c("03785955", "2434561X", NA)) # TRUE TRUE NA +check_issn_check_digit(c("0378-5955", "2434-561X", NA)) +# TRUE TRUE NA + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("check_issn_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("convert_to_isbn_13") +### * convert_to_isbn_13 + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: convert_to_isbn_13 +### Title: Convert ISBN 10 to ISBN 13 +### Aliases: convert_to_isbn_13 + +### ** Examples + + +convert_to_isbn_13("012491540X") # 9780124915404 + +# vectorized +convert_to_isbn_13(c("012491540X", "9004037810")) +# "9780124915404" "9789004037816" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("convert_to_isbn_13", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("cp_lb_attributes") +### * cp_lb_attributes + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: cp_lb_attributes +### Title: Copy special libbib attributes from one object to another +### Aliases: cp_lb_attributes + +### ** Examples + + +tmp1 <- "a" +set_lb_date(tmp1, "2021-05-08") +set_lb_attribute(tmp1, "note", "just an example") + +tmp2 <- "b" +cp_lb_attributes(tmp1, tmp2) +attributes(tmp2)$lb.date +# [1] "2021-05-08" +attributes(tmp2)$lb.note +# [1] "just an example" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("cp_lb_attributes", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_add_to_col_names") +### * dt_add_to_col_names + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_add_to_col_names +### Title: Add string to all column names in a data.table +### Aliases: dt_add_to_col_names + +### ** Examples + +library(data.table) +DT <- as.data.table(iris) + +dt_add_to_col_names(DT, "_post") +names(DT) +# [1] "Sepal.Length_post" "Sepal.Width_post" "Petal.Length_post" +# [4] "Petal.Width_post" "Species_post" + + DT <- as.data.table(iris) +dt_add_to_col_names(DT, "pre_", prefix=TRUE) +names(DT) +# [1] "pre_Sepal.Length" "pre_Sepal.Width" "pre_Petal.Length" "pre_Petal.Width" +# [5] "pre_Species" + +DT <- as.data.table(iris) +dt_add_to_col_names(DT, "_post", exclude="Species") +names(DT) +# [1] "Sepal.Length_post" "Sepal.Width_post" "Petal.Length_post" +# [4] "Petal.Width_post" "Species" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_add_to_col_names", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_counts_and_percents") +### * dt_counts_and_percents + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_counts_and_percents +### Title: Group by, count, and percent count in a data.table +### Aliases: dt_counts_and_percents + +### ** Examples + +library(data.table) + +iris_dt <- as.data.table(iris) +dt_counts_and_percents(iris_dt, "Species") +mt <- as.data.table(mtcars) +mt[, cyl:=factor(cyl)] +dt_counts_and_percents(mt, "cyl") +dt_counts_and_percents(mt, "cyl", percent.cutoff=25) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_counts_and_percents", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_del_cols") +### * dt_del_cols + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_del_cols +### Title: Delete columns in a data.table +### Aliases: dt_del_cols + +### ** Examples + +library(data.table) +mt <- as.data.table(mtcars) +dt_del_cols(mt, "cyl", "disp", "hp") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_del_cols", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_keep_cols") +### * dt_keep_cols + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_keep_cols +### Title: Keep columns in a data.table +### Aliases: dt_keep_cols + +### ** Examples + +library(data.table) +mt <- as.data.table(mtcars) +dt_keep_cols(mt, "mpg", "am", "gear", "carb") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_keep_cols", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_na_breakdown") +### * dt_na_breakdown + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_na_breakdown +### Title: Get a breakdown of the NA-status of a column in a data.table +### Aliases: dt_na_breakdown + +### ** Examples + +library(data.table) + +iris_dt <- as.data.table(iris) +iris_dt[sample(1:.N, 10), Species:=NA_character_] +dt_na_breakdown(iris_dt, "Species") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_na_breakdown", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_percent_not_na") +### * dt_percent_not_na + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_percent_not_na +### Title: Return the percentage of non-NA instances in a data.table column +### Aliases: dt_percent_not_na + +### ** Examples + +library(data.table) + +mt <- as.data.table(mtcars) +mt[mpg<16, mpg:=NA] +dt_percent_not_na(mt, "mpg") # 68.75 + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_percent_not_na", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("dt_set_clean_names") +### * dt_set_clean_names + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: dt_set_clean_names +### Title: Takes a data.table and set to cleaned column names +### Aliases: dt_set_clean_names + +### ** Examples + +library(data.table) + +ejemplo <- as.data.table(iris) +setnames(ejemplo, c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\nWidth", "SpĂȘcies")) +dt_set_clean_names(ejemplo) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("dt_set_clean_names", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("fread_plus_date") +### * fread_plus_date + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: fread_plus_date +### Title: Read a file and set a special libbib date attribute +### Aliases: fread_plus_date + +### ** Examples + +## Not run: +##D # there's a file called "iris-2021-05-08.csv" on disk +##D dat <- fread_plus_date("iris.csv") +##D attribute(dat)$lb.date +##D # [1] "2021-05-08 +##D +##D # can also read the full file name +##D dat <- fread_plus_date("iris-2021-05-08.csv") +##D attribute(dat)$lb.date +##D # [1] "2021-05-08 +## End(Not run) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("fread_plus_date", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("fwrite_plus_date") +### * fwrite_plus_date + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: fwrite_plus_date +### Title: Write a file with a date appended to the file name. +### Aliases: fwrite_plus_date + +### ** Examples + +## Not run: +##D +##D set_lb_date(iris, "2021-05-08") +##D fwrite_plus_date(iris, "iris.csv.gz") +##D # "iris-2021-05-08.csv.gz" is now written to disk +##D +## End(Not run) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("fwrite_plus_date", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_all_lc_call_subject_letters") +### * get_all_lc_call_subject_letters + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_all_lc_call_subject_letters +### Title: Get all subject letters of LC Call Number +### Aliases: get_all_lc_call_subject_letters + +### ** Examples + + +get_all_lc_call_subject_letters("Q172.5.E77") +# Q +get_all_lc_call_subject_letters("AF172.5.E77") +# NA + +# vectorized +get_all_lc_call_subject_letters(c("Q 172.5", "AF172", "PR6023.A93")) +# Q NA PR + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_all_lc_call_subject_letters", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_clean_names") +### * get_clean_names + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_clean_names +### Title: Takes a data.frame and returns cleaned column names +### Aliases: get_clean_names + +### ** Examples + +ejemplo <- iris +names(ejemplo) <- c("Sepal Length", "Sepal@Width", "Petal Length", + "Petal\\nWidth", "SpĂȘcies") +# c("sepal_length" "sepal_width" "petallength" "petal_nwidth" "sp_cies") + +# c("Sepal_Length" "Sepal_Width" "PetalLength" "Petal_nWidth" "Sp_cies") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_clean_names", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_country_from_code") +### * get_country_from_code + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_country_from_code +### Title: Conversion from country code to country name +### Aliases: get_country_from_code + +### ** Examples + + +get_country_from_code("ck") +# Colombia + +# tolerant of case and leading/trailing whitespace +get_country_from_code(c(" PE", "not-a-country", "nyu")) +# c("Peru", NA, "New York (State)") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_country_from_code", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_dewey_decimal_subject_class") +### * get_dewey_decimal_subject_class + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_dewey_decimal_subject_class +### Title: Conversion from Dewey Decimal call numbers to first-level +### subject description +### Aliases: get_dewey_decimal_subject_class + +### ** Examples + + +get_dewey_decimal_subject_class("709.05") # Arts + +get_dewey_decimal_subject_class("823.912") +# Literature (Belles-lettres) and rhetoric + +# vectorized +get_dewey_decimal_subject_class(c("709.05", "invalid", NA, "823.912")) +# c("Arts", NA, NA, "Literature (Belles-lettres) and rhetoric") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_dewey_decimal_subject_class", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_dewey_decimal_subject_division") +### * get_dewey_decimal_subject_division + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_dewey_decimal_subject_division +### Title: Conversion from Dewey Decimal call numbers to second-level +### subject description +### Aliases: get_dewey_decimal_subject_division + +### ** Examples + + +get_dewey_decimal_subject_division("709.05") # Arts + +get_dewey_decimal_subject_division("823.912") +# "English and Old English literatures" + +# vectorized +get_dewey_decimal_subject_division(c("709.05", "invalid", NA, "823.912")) +# c("Arts", NA, NA, "English and Old English literatures") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_dewey_decimal_subject_division", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_dewey_decimal_subject_section") +### * get_dewey_decimal_subject_section + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_dewey_decimal_subject_section +### Title: Conversion from Dewey Decimal call numbers to third-level +### subject description +### Aliases: get_dewey_decimal_subject_section + +### ** Examples + + +get_dewey_decimal_subject_section("709.05") +# "History, geographic treatment, biography" + +get_dewey_decimal_subject_section("823.912") +# "English fiction" + +# vectorized +get_dewey_decimal_subject_section(c("709.05", "invalid", NA, "823.912")) +# c("History, geographic treatment, biography", NA, NA, +# "English fiction") + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_dewey_decimal_subject_section", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_isbn_10_check_digit") +### * get_isbn_10_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_isbn_10_check_digit +### Title: Get ISBN 10 check digit +### Aliases: get_isbn_10_check_digit + +### ** Examples + + +get_isbn_10_check_digit("012491540X") +get_isbn_10_check_digit("0-124-91540-X", allow.hyphens=TRUE) + +# nine digit string +get_isbn_10_check_digit("900403781") + +get_isbn_10_check_digit("onetwothre", errors.as.nas=TRUE) # NA + +# vectorized +get_isbn_10_check_digit(c("012491540X", "9004037810", "900403781")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_isbn_10_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_isbn_13_check_digit") +### * get_isbn_13_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_isbn_13_check_digit +### Title: Get ISBN 13 check digit +### Aliases: get_isbn_13_check_digit + +### ** Examples + + +get_isbn_13_check_digit("9780306406157") + +# 12 digit string +get_isbn_13_check_digit("978030640615") + +get_isbn_13_check_digit("onetwothreefo", errors.as.nas=TRUE) # NA + +# vectorized +get_isbn_13_check_digit(c("9780306406157", "9783161484100")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_isbn_13_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_issn_check_digit") +### * get_issn_check_digit + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_issn_check_digit +### Title: Get ISSN check digit +### Aliases: get_issn_check_digit + +### ** Examples + + +get_issn_check_digit("03785955") + +get_issn_check_digit("2434-561X", allow.hyphens=TRUE) + +# nine digit string +get_issn_check_digit("0378595") + +# vectorized +get_issn_check_digit(c("0378595", "2434561X", NA)) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_issn_check_digit", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_language_from_code") +### * get_language_from_code + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_language_from_code +### Title: Conversion from language code to language name +### Aliases: get_language_from_code + +### ** Examples + + +get_language_from_code("yor") +# Yoruba + +# tolerant of case and leading/trailing whitespace +get_language_from_code(c("yor", " SPA ", "not-a-language", "nah", NA)) +# c("Yoruba", "Spanish", NA, "Nahuatl", NA) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_language_from_code", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_lc_call_first_letter") +### * get_lc_call_first_letter + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_lc_call_first_letter +### Title: Get the first letter of LC Call Number +### Aliases: get_lc_call_first_letter + +### ** Examples + + +get_lc_call_first_letter("Q172.5.E77") +# Q +get_lc_call_first_letter("AF172.5.E77") +# NA + +# vectorized +get_lc_call_first_letter(c("Q 172.5", "AF172", "PR6023.A93")) +# Q NA P + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_lc_call_first_letter", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("get_lc_call_subject_classification") +### * get_lc_call_subject_classification + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: get_lc_call_subject_classification +### Title: Conversion from Library of Congress Call number to subject +### classification +### Aliases: get_lc_call_subject_classification + +### ** Examples + + +get_lc_call_subject_classification("ND 237.S18 $b S87 1997") +# Fine Arts + +get_lc_call_subject_classification("ND 237.S18 $b S87 1997", subclassification=TRUE) +# Painting + +get_lc_call_subject_classification("PQ2246.M3") +# Language and Literature + +get_lc_call_subject_classification("PQ2246.M3", + subclassification=TRUE) +# "French, Italian, Spanish, and Portuguese literature" + +get_lc_call_subject_classification("PQ2246.M3", already.parsed=TRUE) +# NA + +get_lc_call_subject_classification("PQ", already.parsed=TRUE, + subclassification=TRUE) +# "French, Italian, Spanish, and Portuguese literature" + +# vectorized +get_lc_call_subject_classification(c("ND 237", "\\\\$a ND 2", "PQ2246.M3"), + subclassification=TRUE) +# c("Painting", NA, "French, Italian, Spanish, and Portuguese literature") + + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("get_lc_call_subject_classification", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("is_valid_isbn_10") +### * is_valid_isbn_10 + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: is_valid_isbn_10 +### Title: Return TRUE if valid ISBN 10 +### Aliases: is_valid_isbn_10 + +### ** Examples + + +is_valid_isbn_10("012491540X") # TRUE +is_valid_isbn_10("0-124-91540-X") # TRUE + +# vectorized +is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +is_valid_isbn_10(c("012491540X", "hubo un tiempo")) # TRUE FALSE + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("is_valid_isbn_10", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("is_valid_isbn_13") +### * is_valid_isbn_13 + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: is_valid_isbn_13 +### Title: Return TRUE if valid ISBN 13 +### Aliases: is_valid_isbn_13 + +### ** Examples + + +is_valid_isbn_13("9780306406157") # TRUE +is_valid_isbn_13("978-0-306-40615-7") # TRUE + +# vectorized +is_valid_isbn_10(c("012491540X", "9004037812")) # TRUE FALSE +is_valid_isbn_13(c("978-0-306-40615-7", "9783161484103")) # TRUE FALSE +is_valid_isbn_13(c("978-0-306-40615-7", "hubo un tiempo")) # TRUE FALSE + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("is_valid_isbn_13", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("is_valid_issn") +### * is_valid_issn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: is_valid_issn +### Title: Return TRUE if valid ISSN +### Aliases: is_valid_issn + +### ** Examples + + +is_valid_issn("2434561X") # TRUE +is_valid_issn("2434-561X") # TRUE + +# vectorized + +is_valid_issn(c("2434-561X", "2434-5611", "0378-5955", NA)) +# TRUE FALSE TRUE NA + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("is_valid_issn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("is_valid_lc_call") +### * is_valid_lc_call + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: is_valid_lc_call +### Title: Check if LC Call Number is valid +### Aliases: is_valid_lc_call + +### ** Examples + + +is_valid_lc_call("Q172.5.E77") +# TRUE +is_valid_lc_call("AF172.5.E77") +# FALSE + +# vectorized +is_valid_lc_call(c("Q 172.5", "AF172", "PR6023.A93")) +# TRUE FALSE TRUE + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("is_valid_lc_call", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("loc_permalink_from_lccn") +### * loc_permalink_from_lccn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: loc_permalink_from_lccn +### Title: Get Library of Congress catalog permalinks from LCCNs +### Aliases: loc_permalink_from_lccn + +### ** Examples + +loc_permalink_from_lccn("n78-890351") # "https://lccn.loc.gov/n78890351" +loc_permalink_from_lccn("85-2 ") # "https://lccn.loc.gov/85000002" +loc_permalink_from_lccn("75-425165//r75") # "https://lccn.loc.gov/75425165" + +# vectorized +loc_permalink_from_lccn(c("###78890351#", NA, "n78-890351")) + +# MARCXML metadata format +loc_permalink_from_lccn("73167510", format="marcxml") +# "https://lccn.loc.gov/73167510/marcxml" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("loc_permalink_from_lccn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("marc_008_get_info") +### * marc_008_get_info + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: marc_008_get_info +### Title: Get info from MARC control field 008 +### Aliases: marc_008_get_info + +### ** Examples + + +# reissue publication date +marc_008_get_info("950622r19701880ru 000 0 rus d") +# pub_date pub_place_code lang_code +# +# 1: 1970 ru rus + +# The Brothers Karamazov (1970 reissue but original publication date) +marc_008_get_info("950622r19701880ru 000 0 rus d", + original.pub.date=TRUE) +# pub_date pub_place_code lang_code +# +# 1: 1880 ru rus + +# vectorized +marc_008_get_info(c("101106s1992 gr 000 1 gre d", NA, + "180528s2017 ag 000 j spa d")) +# pub_date pub_place_code lang_code +# +# 1: 1992 gr gre +# 2: NA +# 3: 2017 ag spa + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("marc_008_get_info", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("marc_leader_get_info") +### * marc_leader_get_info + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: marc_leader_get_info +### Title: Get info from MARC leader +### Aliases: marc_leader_get_info + +### ** Examples + + +marc_leader_get_info("00000cam a22000008i 4500") +# record_type bib_level +# +# 1: Language Material Monograph/Item + +# vectorized +marc_leader_get_info(c("00000cam a2200000Ma 4500", NA, + "00000cem a2200000Ma 4500")) +# record_type bib_level +# +# 1: Language Material Monograph/Item +# 2: +# 3: Cartographic material Monograph/Item + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("marc_leader_get_info", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("normalize_isbn") +### * normalize_isbn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: normalize_isbn +### Title: Attempt to enforce validity and canonical form to an ISBN +### Aliases: normalize_isbn + +### ** Examples + + +normalize_isbn("012491540x") # "012491540X" +normalize_isbn("012491540x", convert.to.isbn.13=TRUE) +"9780124915404" + +# vectorized +normalize_isbn(c("513213012491540x245", + "978966819^*!X7918", + NA, + "97815724115799781572411579")) +# "012491540X", "9789668197918", NA, "9781572411579" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("normalize_isbn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("normalize_isbn_10") +### * normalize_isbn_10 + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: normalize_isbn_10 +### Title: Attempt to enforce validity and canonical form to ISBN 10 +### Aliases: normalize_isbn_10 + +### ** Examples + + +normalize_isbn_10("012491540x") # "012491540X" +normalize_isbn_10("012491540x xe32ea") # "012491540X" +normalize_isbn_10("012491540x", convert.to.isbn.13=TRUE) +# "9780124915404" +normalize_isbn_10("513213012491540x") # "012491540X" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("normalize_isbn_10", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("normalize_isbn_13") +### * normalize_isbn_13 + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: normalize_isbn_13 +### Title: Attempt to enforce validity and canonical form to ISBN 13 +### Aliases: normalize_isbn_13 + +### ** Examples + + +normalize_isbn_13("978966819^*!X7918") # "9789668197918" + +# vectorized +normalize_isbn_13(c("978-9-66-819791-8", "__9__781572411579")) +# "9789668197918" "9781572411579" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("normalize_isbn_13", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("normalize_issn") +### * normalize_issn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: normalize_issn +### Title: Attempt to enforce validity and canonical form to ISSN +### Aliases: normalize_issn + +### ** Examples + + +# adds leading zero +normalize_issn("3785955") # "03785955" + +# adds X to 7 digit ISSN if valid +normalize_issn("2434561") # "2434561X" + +normalize_issn("2434561", pretty=TRUE) # "2434-561X" + +# finds correct sequence +normalize_issn("21335212434561X") # "2434561X" + +# vectorized +normalize_issn(c("__2434__561X", "2434561", "21335212434561X")) +# "2434561X" "2434561X" "2434561X" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("normalize_issn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("normalize_lccn") +### * normalize_lccn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: normalize_lccn +### Title: Attempt to enforce validity of LCCN and convert to normalized +### form +### Aliases: normalize_lccn + +### ** Examples + + +normalize_lccn("n 78890351 ") # "n78890351" + +normalize_lccn("###78890351#") # "78890351" + +normalize_lccn(" 79139101 /AC/r932") # "79139101" + +normalize_lccn("85-2 ") # "85000002" +normalize_lccn("85-2 ", allow.hyphens=FALSE) # NA + +# vectorized +normalize_lccn(c("85-2 ", " 79139101 /AC/r932", "n 78890351 ")) +# c("85000002", "79139101", "n78890351")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("normalize_lccn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("oclc_classify_link_from_standard_num") +### * oclc_classify_link_from_standard_num + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: oclc_classify_link_from_standard_num +### Title: Get OCLC Classify link from a standard number +### Aliases: oclc_classify_link_from_standard_num + +### ** Examples + + +oclc_classify_link_from_standard_num("629725006") +# "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" + +oclc_classify_link_from_standard_num(c("039333712X", NA, "629725006")) +# [1] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=039333712X&startRec=0" +# [2] NA +# [3] "http://classify.oclc.org/classify2/ClassifyDemo?search-standnum-txt=629725006&startRec=0" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("oclc_classify_link_from_standard_num", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("recombine_with_sep_closure") +### * recombine_with_sep_closure + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: recombine_with_sep_closure +### Title: Return a function that will combine/contatenate a vector +### Aliases: recombine_with_sep_closure + +### ** Examples + + +lambda <- recombine_with_sep_closure() +lambda(c(8, 6, 7)) # "8;6;7" + +# directly +recombine_with_sep_closure()(c(8,6,7)) # "8;6;7" +lambda <- recombine_with_sep_closure(" ") +lambda(c("this", "that", NA,"the-other")) # "this that NA the-other" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("recombine_with_sep_closure", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("remove_duplicates_and_nas") +### * remove_duplicates_and_nas + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: remove_duplicates_and_nas +### Title: Remove duplicate elements and NAs from a vector +### Aliases: remove_duplicates_and_nas + +### ** Examples + + +remove_duplicates_and_nas(c(8, 6, 7, 5, 3, 0, 9, 6, NA, 3)) +# 8 6 7 5 3 0 9 + +remove_duplicates_and_nas(c(NA, NA)) +# NA + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("remove_duplicates_and_nas", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("set_lb_attribute") +### * set_lb_attribute + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: set_lb_attribute +### Title: Set special libbib attribute on object +### Aliases: set_lb_attribute + +### ** Examples + +set_lb_attribute(mtcars, "source", "R built-in dataset") + +versicolor <- iris[iris$Species=="versicolor", ] +set_lb_attribute(versicolor, "note", "modified built-in dataset") +attributes(versicolor)$lb.note +# [1] "modified built-in dataset" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("set_lb_attribute", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("set_lb_date") +### * set_lb_date + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: set_lb_date +### Title: Set special libbib date attribute on object +### Aliases: set_lb_date + +### ** Examples + +set_lb_date(mtcars, "2021-05-08") +attributes(mtcars)$lb.date +# [1] "2021-05-08 + +set_lb_date(mtcars, Sys.Date()) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("set_lb_date", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("split_map_filter_reduce") +### * split_map_filter_reduce + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: split_map_filter_reduce +### Title: Split, Map, Filter, and Reduce a string vector +### Aliases: split_map_filter_reduce + +### ** Examples + + +someisbns <- c("9782711875177;garbage-isbn;2711875172;2844268900", + "1861897952; 978-1-86189-795-4") + +# will return only the first ISBN for each record +split_map_filter_reduce(someisbns) +# "9782711875177" "1861897952" + +# will return only the first ISBN for each record, after normalizing +# each ISBN +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}) +# "9782711875177" "9781861897954" + +# will return all ISBNs, for each record, separated by a semicolon +# after applying normalize_isbn to each ISBN +# note the duplicates introduced after normalization occurs +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + reduxfun=recombine_with_sep_closure()) +# "9782711875177;NA;9782711875177;9782844268907" "9781861897954;9781861897954" + +# After splitting each items ISBN list by semicolon, this runs +# normalize_isbn in each of them. Duplicates are produced when +# an ISBN 10 converts to an ISBN 13 that is already in the ISBN +# list for the item. NAs are produced when an ISBN fails to normalize. +# Then, all duplicates and NAs are removed. Finally, the remaining +# ISBNs, for each record, are pasted together using a space as a separator +split_map_filter_reduce(someisbns, mapfun=function(x){normalize_isbn(x, convert.to.isbn.13=TRUE)}, + filterfun=remove_duplicates_and_nas, + reduxfun=recombine_with_sep_closure(" ")) +# "9782711875177 9782844268907" "9781861897954" + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("split_map_filter_reduce", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_api_bib_read_info_by") +### * worldcat_api_bib_read_info_by + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_api_bib_read_info_by +### Title: Get bibliographic info from a standard number +### Aliases: worldcat_api_bib_read_info_by +### worldcat_api_bib_read_info_by_oclc worldcat_api_bib_read_info_by_isbn +### worldcat_api_bib_read_info_by_issn + +### ** Examples + + +## Not run: +##D worldcat_api_bib_read_info_by_isbn("9780984201006") +##D # oclc isbn issn title +##D # +##D # 1: 462894360 9780984201006 The Great Debate about Art / +##D # author leader +##D # +##D # 1: Harris, Roy, 00000cam a2200000 a 4500 +##D # oh08 +##D # +##D # 1: 091031s2010 ilua b 000 0 eng c +##D +##D worldcat_api_bib_read_info_by_issn("13602365") +##D # oclc isbn issn title author +##D # +##D # 1: 37787277 14664410 The journal of architecture. +##D # leader oh08 +##D # +##D # 1: 00000cas a2200000 a 4500 971015c19969999enkbx pso 0 a0eng c +##D +## End(Not run) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_api_bib_read_info_by", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_api_classify_by") +### * worldcat_api_classify_by + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_api_classify_by +### Title: Search WorldCat classify API by ISBN, ISSN, or OCLC number +### Aliases: worldcat_api_classify_by worldcat_api_classify_by_oclc +### worldcat_api_classify_by_isbn worldcat_api_classify_by_issn + +### ** Examples + + +## Not run: +##D worldcat_api_classify_by_oclc("93976650") +##D # oclc title author total_holdings total_eholdings call_type +##D # +##D # 1: 939766505 Lobster King, Richard J. 244 534 DDC +##D # 2: 939766505 Lobster King, Richard J. 244 534 LCC +##D # recommendation holdings http_status_code classify_response_code +##D # +##D # 1: 641.395 767 200 0 +##D # 2: QL444.M33 318 200 0 +##D +## End(Not run) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_api_classify_by", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_api_locations_by") +### * worldcat_api_locations_by + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_api_locations_by +### Title: Get holding libraries by standard number +### Aliases: worldcat_api_locations_by worldcat_api_locations_by_oclc +### worldcat_api_locations_by_isbn worldcat_api_locations_by_issn + +### ** Examples + + +## Not run: +##D # worldcat_api_locations_by_oclc("877749545", max_libraries=10, +##D # include.bib.info=FALSE) +##D # oclc institution_identifier +##D # +##D # 1: 877749545 NLE +##D # 2: 877749545 NLW +##D # 3: 877749545 EUM +##D # 4: 877749545 LTU +##D # 5: 877749545 ELU +##D # 6: 877749545 UKUAL +##D # institution_name copies +##D # +##D # 1: National Library of Scotland 1 +##D # 2: National Library of Wales 1 +##D # 3: University of Manchester Library 1 +##D # 4: University of Leicester, David Wilson Library 1 +##D # 5: University of London Senate House Library 1 +##D # 6: University of the Arts London 1 +##D +## End(Not run) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_api_locations_by", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_api_search") +### * worldcat_api_search + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_api_search +### Title: Use the WorldCat Search API +### Aliases: worldcat_api_search + +### ** Examples + + +## Not run: +##D +##D # A title search for "The Brothers Karamazov" +##D worldcat_api_search('$title = "Brothers Karamazov"') +##D +##D # An exact title search for "The Brothers Karamazov" +##D worldcat_api_search('$title exact "Brothers Karamazov"') +##D +##D # Search for title "Madame Bovary" by author "Gustave Flaubert" +##D # in language Greek (all results) +##D # (queries may span multiple lines) +##D sru <- '$author = "Gustave Flaubert" and $title="Madame Bovary" +##D and $language=greek' +##D worldcat_api_search(sru, max_records=Inf) +##D +##D # Hip Hop (subject) materials on Cassette, CD, or wax from years 1987 to 1990 +##D sru <- '(($material_type=cas or $material_type=cda or $material_type=lps) +##D and $subject="Rap") and $year="1987-1990"' +##D worldcat_api_search(sru) +##D +##D # all materials with keyword "Common Lisp" at The New York Public Library +##D sru <- '$keyword="common lisp" and $holding_library=NYP' +##D worldcat_api_search(sru, max_records=Inf) +##D +##D # 19th century materials on ethics (Dewey code 170s / LC Call prefix BJ) +##D sru <- '($dewey="17*" or $lc_call="bj*") and $year="18*"' +##D worldcat_api_search(sru, max_records=Inf) +##D +##D # Music (Dewey 780s) materials that are only held by The New York Public +##D # Library (a "cg" code of 11 means there is only one holding) +##D # [searching with debugging] +##D sru <- '$dewey="78*" and $holding_library=NYP +##D and $library_holdings_group=11' +##D worldcat_api_search(sru, debug=TRUE) +##D +##D Keyword search for "danger music" from year 2010 to present +##D worldcat_api_search('$keyword="danger music" and $year="2010-"') +##D +## End(Not run) + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_api_search", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_permalink_from_isbn") +### * worldcat_permalink_from_isbn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_permalink_from_isbn +### Title: Get WorldCat catalog permalinks from ISBNs +### Aliases: worldcat_permalink_from_isbn + +### ** Examples + + +worldcat_permalink_from_isbn("1788393724") +# http://www.worldcat.org/isbn/1788393724 + +worldcat_permalink_from_isbn("0-124-91540-X") +# http://www.worldcat.org/isbn/012491540X + +worldcat_permalink_from_isbn("0-124-91540-X", normalize=FALSE) +# http://www.worldcat.org/isbn/0-124-91540-X + +# vectorized +worldcat_permalink_from_isbn(c("1788393724", NA, "0-124-91540-X")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_permalink_from_isbn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_permalink_from_issn") +### * worldcat_permalink_from_issn + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_permalink_from_issn +### Title: Get WorldCat catalog permalinks from ISSNs +### Aliases: worldcat_permalink_from_issn + +### ** Examples + +worldcat_permalink_from_issn("0968-1221") # http://www.worldcat.org/issn/0968-1221 + +worldcat_permalink_from_issn("2434-561X") # http://www.worldcat.org/issn/2434561X + +# vectorized +worldcat_permalink_from_issn(c("0968-1221", NA, "2434-561X")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_permalink_from_issn", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +cleanEx() +nameEx("worldcat_permalink_from_oclc_number") +### * worldcat_permalink_from_oclc_number + +flush(stderr()); flush(stdout()) + +base::assign(".ptime", proc.time(), pos = "CheckExEnv") +### Name: worldcat_permalink_from_oclc_number +### Title: Get WorldCat catalog permalinks from OCLC numbers +### Aliases: worldcat_permalink_from_oclc_number + +### ** Examples + + +worldcat_permalink_from_oclc_number("1005106045") +# http://www.worldcat.org/oclc/1005106045 + +# vectorized +worldcat_permalink_from_oclc_number(c("1049727704", NA, + "1005106045")) + + + + +base::assign(".dptime", (proc.time() - get(".ptime", pos = "CheckExEnv")), pos = "CheckExEnv") +base::cat("worldcat_permalink_from_oclc_number", base::get(".format_ptime", pos = 'CheckExEnv')(get(".dptime", pos = "CheckExEnv")), "\n", file=base::get(".ExTimings", pos = 'CheckExEnv'), append=TRUE, sep="\t") +### *