Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ISBN provider #142

Merged
merged 4 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Collate:
'internet-provider-fr_FR.R'
'internet-provider-hr_HR.R'
'internet-provider.R'
'isbn-provider.R'
'job.R'
'jobs-provider-da_DK.R'
'jobs-provider-en_US.R'
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ doc:
install: doc build
R CMD INSTALL . && rm *.tar.gz

build:
update_collate:
${RSCRIPT} -e "roxygen2::update_collate('.')"

build: update_collate
R CMD build .

eg:
Expand All @@ -29,7 +32,7 @@ locales_update:
${RSCRIPT} -e "devtools::load_all(); z=data.table::setDF(data.table::rbindlist(lapply(available_locales, stringi::stri_locale_info))); save(z, version=2, file='data/available_locales_df.rda')"

# No real targets!
.PHONY: all test doc install
.PHONY: all test doc install

vignettes:
${RSCRIPT} -e "devtools::build_vignettes()"
Expand Down
1 change: 0 additions & 1 deletion R/address-provider-en_NZ.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ AddressProvider_en_NZ <- R6::R6Class(
pattern <- super$random_element(private$city_formats)
dat <- list(
# , , te_reo_first, te_reo_ending, te_reo_part

first_name = private$pp$first_name(),
last_name = private$pp$last_name(),
city_suffix = super$random_element(private$street_suffixes),
Expand Down
1 change: 0 additions & 1 deletion R/address-provider.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,3 @@ AddressProvider <- R6::R6Class(
provider_ = "AddressProvider"
)
)

92 changes: 92 additions & 0 deletions R/isbn-provider.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#' @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")

Check warning on line 51 in R/isbn-provider.R

View check run for this annotation

Codecov / codecov/patch

R/isbn-provider.R#L51

Added line #L51 was not covered by tests
}
final_number <- 11 - (checksum_util(first_9, 10:2) %% 11)
final_number <- final_number %% 11
if (final_number == 10) {
final_number <- "X"
}
as.character(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")

Check warning on line 73 in R/isbn-provider.R

View check run for this annotation

Codecov / codecov/patch

R/isbn-provider.R#L73

Added line #L73 was not covered by tests
}
final_number <- 10 - (checksum_util(first_12, rep(c(1, 3), 6)) %% 10)
if (final_number == 10) {
final_number <- 0

Check warning on line 77 in R/isbn-provider.R

View check run for this annotation

Codecov / codecov/patch

R/isbn-provider.R#L77

Added line #L77 was not covered by tests
}
final_number
},
subst_vector = function(prefix, vector) {
step <- nchar(prefix)
max_n <- length(vector)
if (step > max_n) {
step <- max_n

Check warning on line 85 in R/isbn-provider.R

View check run for this annotation

Codecov / codecov/patch

R/isbn-provider.R#L85

Added line #L85 was not covered by tests
}
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
16 changes: 2 additions & 14 deletions R/ssn-provider-all.R
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,9 @@ SSNProvider_nl_NL <- R6Class(
#' @description Make a SSN
#' Dutch SSN (BSN) is 9 digits that follow a certain proof (elfproef).
render = function() {
first_8 <- as.integer(strsplit(as.character(as.integer(runif(1) * 1e8)), "")[[1]])
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
first_8 <- sample(0:9, 8, replace = TRUE)

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: 16 additions & 16 deletions tests/testthat/test-addresses.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ test_that("every_locale has the same basic functions", {
expect_false(bb$address() == "")
expect_is(bb$city, "function")
expect_type(bb$city(), "character")
expect_false(bb$city() == "",label = sprintf("city - %s", locale))
expect_false(bb$city() == "", label = sprintf("city - %s", locale))
expect_is(bb$street_address, "function")
expect_type(bb$street_address(), "character")
expect_false(bb$street_address() == "",label = sprintf("city - %s", locale))
expect_false(bb$street_address() == "", label = sprintf("city - %s", locale))
expect_is(bb$street_name, "function")
expect_type(bb$street_name(), "character")
expect_false(bb$street_name() == "",label = sprintf("city - %s", locale))
expect_false(bb$street_name() == "", label = sprintf("city - %s", locale))
expect_is(bb$postcode, "function")
expect_type(bb$postcode(), "character")
expect_false(bb$postcode() == "", label = sprintf("postcode - %s", locale))
Expand Down Expand Up @@ -75,18 +75,18 @@ test_that("custom functions from AddressProvider_nl_NL work", {
expect_true(aa$province() %in% aa$.__enclos_env__$private$provinces)
})

test_that("all locales consistently give results -- stresstest",{
skip_on_cran()
skip_on_ci()

aa <- cr_loc_spec_provider("AddressProvider", "en_US")
for (locale in aa$allowed_locales()) {
bb <- cr_loc_spec_provider("AddressProvider", locale)
for (i in 1:50){
expect_false(bb$city() == "",label = sprintf("city - %s", locale))
expect_false(bb$street_address() == "",label = sprintf("city - %s", locale))
expect_false(bb$street_name() == "",label = sprintf("city - %s", locale))
expect_false(bb$postcode() == "", label = sprintf("postcode - %s", locale))
}
test_that("all locales consistently give results -- stresstest", {
skip_on_cran()
skip_on_ci()

aa <- cr_loc_spec_provider("AddressProvider", "en_US")
for (locale in aa$allowed_locales()) {
bb <- cr_loc_spec_provider("AddressProvider", locale)
for (i in 1:50) {
expect_false(bb$city() == "", label = sprintf("city - %s", locale))
expect_false(bb$street_address() == "", label = sprintf("city - %s", locale))
expect_false(bb$street_name() == "", label = sprintf("city - %s", locale))
expect_false(bb$postcode() == "", label = sprintf("postcode - %s", locale))
}
}
})
2 changes: 1 addition & 1 deletion tests/testthat/test-company.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ test_that("all locales have `company()` function", {
for (loc in CompanyProvider_en_US$new()$allowed_locales()) {
aa <- cr_loc_spec_provider("CompanyProvider", locale = loc)
expect_gt(nchar(aa$company()), 0)
expect_false(aa$company() == "",label = sprintf("company - %s", loc))
expect_false(aa$company() == "", label = sprintf("company - %s", loc))
expect_type(aa$company, "closure")
}
})
Expand Down
50 changes: 50 additions & 0 deletions tests/testthat/test-isbn.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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
# 0575055030 men at arms
expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0, 5, 7, 5, 0, 5, 5, 0, 3)), "0")
# 038553826X raising steam
expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0, 3, 8, 5, 5, 3, 8, 2, 6)), "X")
# 0062429981 The Shepherd's Crown
expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0, 0, 6, 2, 4, 2, 9, 9, 8)), "1")

## optional extra checks
# # 0192854259 good omens
# expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0,1,9,2,8,5,4,2,5)), "9")
# # 0552152676 thud
# expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0,5,5,2,1,5,2,6,7)), "6")
# # 0552142352 interesting times
# expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0,5,5,2,1,4,2,3,5)), "2")
# # 0552134635 moving pictures
# expect_equal(ISBNP$.__enclos_env__$private$generate_isbn10_checkdigit(c(0,5,5,2,1,3,4,6,3)), "5")

# 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)
})
Loading