Skip to content

Commit

Permalink
Add ISBN provider
Browse files Browse the repository at this point in the history
  • Loading branch information
RMHogervorst committed Nov 27, 2023
1 parent 5ed2ed5 commit 5c0bc7c
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 12 deletions.
91 changes: 91 additions & 0 deletions R/isbn-provider.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#' @title ISBNProvider
#' @description International Standard Book Number - Provider.
#' ISBN starts with group code, all English language ISBN-10 codes
#' start with a 0 or 1, and all German language books start with a 3.
#' see <https://en.wikipedia.org/wiki/List_of_ISBN_registration_groups>.
#'
#' Charlatan does not provide further helpers for you, but you can supply the
#' prefix yourself, if for instance you want to create Mexican ISBNs you can
#' by supplying the ISBN10 prefix 970, or for Andorra supply the ISBN 13 prefix
#' 97899920 (that is 978 for ISBN13, and 99920 for Andorra).
#'
#' @param n (integer) number of ISBN10s to make, default=1
#' @param prefix (integer/character) prefix for ISBN
#' @export
#' @examples
#' z <- ISBNProvider$new()
#' z$isbn10()
#' z$isbn13()
#' z$isbn10(10)
#' z$isbn13(100)
#' # or even z$isbn10(500)
ISBNProvider <- R6::R6Class(
"ISBNProvider",
inherit = BareProvider,
public = list(
#' @description Make a ISBN10
#' This is a completely random (apart from the prefix), but valid ISBN10 number.
isbn10 = function(n = 1, prefix = NULL) {
replicate(n, private$generate_isbn10(prefix = prefix))
},
#' @description Make a ISBN13.
#' This is a completely random (apart from the prefix), but valid ISBN13 number.
isbn13 = function(n = 1, prefix = NULL) {
replicate(n, private$generate_isbn13(prefix = prefix))
}
),
private = list(
provider_ = "ISBNProvider",
generate_isbn10 = function(prefix = NULL) {
first9isbn <- sample(0:9, size = 9, replace = TRUE)
if (!is.null(prefix)) {
first9isbn <- private$subst_vector(prefix, first9isbn)
}
final_number <- private$generate_isbn10_checkdigit(first9isbn)
isbn <- paste0(c(first9isbn, final_number), collapse = "")
isbn
},
generate_isbn10_checkdigit = function(first9isbn) {
first_9 <- as.integer(first9isbn)
if (length(first_9) != 9) {
stop("needs exactly 9 tokens")
}
final_number <- 11 - (checksum_util(first_9, 10:2) %% 11)
if (final_number == 10) {
final_number <- "X"
}
final_number
},
generate_isbn13 = function(prefix = NULL) {
first12isbn <- sample(0:9, 12, replace = TRUE)
if (!is.null(prefix)) {
first12isbn <- private$subst_vector(prefix, first12isbn)
}
final_number <- private$generate_isbn13_checkdigit(first12isbn)
isbn <- paste0(c(first12isbn, final_number), collapse = "")
isbn
},
generate_isbn13_checkdigit = function(first12isbn) {
# first12isbn should be a vector of 12 long.
first_12 <- as.integer(first12isbn)
if (length(first_12) != 12) {
stop("needs exactly 12 tokens")
}
final_number <- 10 - (checksum_util(first_12, rep(c(1, 3), 6)) %% 10)
if (final_number == 10) {
final_number <- 0
}
final_number
},
subst_vector = function(prefix, vector) {
step <- nchar(prefix)
max_n <- length(vector)
if (step > max_n) {
step <- max_n
}
values <- strsplit(as.character(prefix), "")[[1]]
vector[1:step] <- values[1:step]
as.integer(vector)
}
)
)
1 change: 0 additions & 1 deletion R/sequence-provider.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#' @title SequenceProvider
#' @description genetic sequence generator
#' @export
#' @keywords internal
#' @examples
#' z <- SequenceProvider$new()
#' z$render()
Expand Down
12 changes: 1 addition & 11 deletions R/ssn-provider-all.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,7 @@ SSNProvider_nl_NL <- R6Class(
if (length(first_8) == 7) {
first_8[8] <- 1
}
final_number <- (
9 * first_8[1] +
+8 * first_8[2] +
+7 * first_8[3] +
+6 * first_8[4] +
+5 * first_8[5] +
+4 * first_8[6] +
+3 * first_8[7] +
+2 * first_8[8]
) %% 11

final_number <- checksum_util(first_8,9:2) %% 11
bsn <- paste0(c(first_8, final_number), collapse = "")
bsn
}
Expand Down
10 changes: 10 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,13 @@ locale_mismatch <- function(parent_provider, child_provider) {
child <- cr_loc_spec_provider(child_provider, "en_US")$allowed_locales()
parent[!parent %in% child]
}

#' generalized util function for sequence multiplication
#'
#' Util function for ISBN, ean, SSN providers.
#' for cases such as sum(x[4]*5 + x[3]*4 + x[2]*3 + x[1] *2)
#' @keywords internal
checksum_util = function(vector,multiplicationvector){
stopifnot(length(vector)==length(multiplicationvector))
sum(vector * multiplicationvector)
}
32 changes: 32 additions & 0 deletions tests/testthat/test-isbn.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
test_that("ISBN 13 creates valid ISBN", {
ISBNP <- ISBNProvider$new()
# ISBN version 13
# 978-0-306-40615-? 7
# LOW LEVEL CHECKDIGIT
expect_equal(ISBNP$.__enclos_env__$private$generate_isbn13_checkdigit(c(9,7,8,0,3,0,6,4,0,6,1,5)), 7)
# UNDERLYING GENERATOR
expect_equal(nchar(ISBNP$.__enclos_env__$private$generate_isbn13()), 13)
# USER FACING FUNCTION
expect_equal(nchar(ISBNP$isbn13()), 13)
})
test_that("ISBN 10 creates valid ISBN", {
ISBNP <- ISBNProvider$new()
# isbn version 10
# 0-306-40615-? 2
# LOW LEVEL CHECKDIGIT
expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0,3,0,6,4,0,6,1,5)), 2)
# UNDERLYING GENERATOR
expect_equal(nchar(ISBNP$.__enclos_env__$private$generate_isbn10()), 10)
# USER FACING FUNCTION
expect_equal(nchar(ISBNP$isbn10()), 10)
})

test_that("prefix logic works", {
ISBNP <- ISBNProvider$new()

expect_equal(ISBNP$.__enclos_env__$private$subst_vector("978", c(1, 1, 1, 1, 1)), c(9, 7, 8, 1, 1))
# 978 or 979
expect_equal(substr(ISBNP$isbn13(n = 1, prefix = 978), 1, 3), "978")
# 1 or 0 for isbn10
expect_equal(substr(ISBNP$isbn10(n = 1, prefix = 1), 1, 1), "1")
})
11 changes: 11 additions & 0 deletions tests/testthat/test-zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,14 @@ test_that("All non-localized providers inherit from BareProvider", {
}
}
})


test_that("checksum_util works for our usecases",{
# ISBN 10
expect_equal(checksum_util(c(0,3,0,6,4,0,6,1,5),10:2), 130)
# ISBN 13
expect_equal(checksum_util(c(9,7,8,0,3,0,6,4,0,6,1,5),rep(c(1,3),6)), 93)
#SSN dutch
#111222333 en 123456782
expect_equal(checksum_util(c(1,1,1,2,2,2,3,3),9:2), 69)
})

0 comments on commit 5c0bc7c

Please sign in to comment.